Relax v4l2_sink lock constraints

To fix a data race, commit 5caeab5f6d
called video_buffer_push() and video_buffer_consume() under the
v4l2_sink lock.

Instead, use the previous_skipped indication (initialized with video
buffer locked) to lock only for protecting the has_frame flag.

This enables the possibility for the video_buffer to notify new frames
via callbacks without lock inversion issues.
This commit is contained in:
Romain Vimont 2021-07-04 12:30:49 +02:00
parent 32e692d5d2
commit 28bce48d47

View file

@ -121,11 +121,11 @@ run_v4l2_sink(void *data) {
break; break;
} }
video_buffer_consume(&vs->vb, vs->frame);
vs->has_frame = false; 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) {
@ -303,17 +303,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 previous_skipped;
bool ok = video_buffer_push(&vs->vb, frame, &previous_skipped);
bool ok = video_buffer_push(&vs->vb, frame, NULL);
if (!ok) { if (!ok) {
return false; return false;
} }
if (!previous_skipped) {
sc_mutex_lock(&vs->mutex);
vs->has_frame = true; vs->has_frame = true;
sc_cond_signal(&vs->cond); sc_cond_signal(&vs->cond);
sc_mutex_unlock(&vs->mutex); sc_mutex_unlock(&vs->mutex);
}
return true; return true;
} }