Fix v4l2 data race

The v4l2_sink implementation directly read the internal video_buffer
field "pending_frame_consumed", which is protected by the internal
video_buffer mutex. But this mutex was not locked, so reads were racy.

Lock using the v4l2_sink mutex in addition, and use a separate field to
avoid depending on the video_buffer internal data.
This commit is contained in:
Romain Vimont 2021-06-26 15:53:05 +02:00
parent 33fbdc86c7
commit 5caeab5f6d
2 changed files with 11 additions and 3 deletions

View file

@ -112,7 +112,7 @@ run_v4l2_sink(void *data) {
for (;;) {
sc_mutex_lock(&vs->mutex);
while (!vs->stopped && vs->vb.pending_frame_consumed) {
while (!vs->stopped && !vs->has_frame) {
sc_cond_wait(&vs->cond, &vs->mutex);
}
@ -121,9 +121,11 @@ run_v4l2_sink(void *data) {
break;
}
video_buffer_consume(&vs->vb, vs->frame);
vs->has_frame = false;
sc_mutex_unlock(&vs->mutex);
video_buffer_consume(&vs->vb, vs->frame);
bool ok = encode_and_write_frame(vs, vs->frame);
av_frame_unref(vs->frame);
if (!ok) {
@ -241,6 +243,7 @@ sc_v4l2_sink_open(struct sc_v4l2_sink *vs) {
goto error_av_frame_free;
}
vs->has_frame = false;
vs->header_written = false;
vs->stopped = false;
@ -299,14 +302,18 @@ sc_v4l2_sink_close(struct sc_v4l2_sink *vs) {
static bool
sc_v4l2_sink_push(struct sc_v4l2_sink *vs, const AVFrame *frame) {
sc_mutex_lock(&vs->mutex);
bool ok = video_buffer_push(&vs->vb, frame, NULL);
if (!ok) {
return false;
}
// signal possible change of vs->vb.pending_frame_consumed
vs->has_frame = true;
sc_cond_signal(&vs->cond);
sc_mutex_unlock(&vs->mutex);
return true;
}

View file

@ -22,6 +22,7 @@ struct sc_v4l2_sink {
sc_thread thread;
sc_mutex mutex;
sc_cond cond;
bool has_frame;
bool stopped;
bool header_written;