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:
parent
33fbdc86c7
commit
5caeab5f6d
2 changed files with 11 additions and 3 deletions
|
@ -112,7 +112,7 @@ run_v4l2_sink(void *data) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
sc_mutex_lock(&vs->mutex);
|
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);
|
sc_cond_wait(&vs->cond, &vs->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,9 +121,11 @@ run_v4l2_sink(void *data) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
video_buffer_consume(&vs->vb, vs->frame);
|
||||||
|
vs->has_frame = false;
|
||||||
|
|
||||||
sc_mutex_unlock(&vs->mutex);
|
sc_mutex_unlock(&vs->mutex);
|
||||||
|
|
||||||
video_buffer_consume(&vs->vb, vs->frame);
|
|
||||||
bool ok = encode_and_write_frame(vs, vs->frame);
|
bool ok = encode_and_write_frame(vs, vs->frame);
|
||||||
av_frame_unref(vs->frame);
|
av_frame_unref(vs->frame);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
|
@ -241,6 +243,7 @@ sc_v4l2_sink_open(struct sc_v4l2_sink *vs) {
|
||||||
goto error_av_frame_free;
|
goto error_av_frame_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vs->has_frame = false;
|
||||||
vs->header_written = false;
|
vs->header_written = false;
|
||||||
vs->stopped = false;
|
vs->stopped = false;
|
||||||
|
|
||||||
|
@ -299,14 +302,18 @@ sc_v4l2_sink_close(struct sc_v4l2_sink *vs) {
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
sc_v4l2_sink_push(struct sc_v4l2_sink *vs, const AVFrame *frame) {
|
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);
|
bool ok = video_buffer_push(&vs->vb, frame, NULL);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// signal possible change of vs->vb.pending_frame_consumed
|
vs->has_frame = true;
|
||||||
sc_cond_signal(&vs->cond);
|
sc_cond_signal(&vs->cond);
|
||||||
|
|
||||||
|
sc_mutex_unlock(&vs->mutex);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ struct sc_v4l2_sink {
|
||||||
sc_thread thread;
|
sc_thread thread;
|
||||||
sc_mutex mutex;
|
sc_mutex mutex;
|
||||||
sc_cond cond;
|
sc_cond cond;
|
||||||
|
bool has_frame;
|
||||||
bool stopped;
|
bool stopped;
|
||||||
bool header_written;
|
bool header_written;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue