videodecoder: don't take STREAM_LOCK on upstream events

Don't try to take STREAM_LOCK on upstream events such as QOS.
Protect qos-related variables with object lock instead. Fixes
possible deadlock when shutting down in certain situations.

https://bugzilla.gnome.org/show_bug.cgi?id=684658
This commit is contained in:
Tim-Philipp Müller 2012-09-24 10:16:09 +01:00
parent 386206e627
commit 62c111f1e4

View file

@ -382,8 +382,9 @@ struct _GstVideoDecoderPrivate
gboolean output_state_changed; gboolean output_state_changed;
/* QoS properties */ /* QoS properties */
gdouble proportion; gdouble proportion; /* OBJECT_LOCK */
GstClockTime earliest_time; GstClockTime earliest_time; /* OBJECT_LOCK */
GstClockTime qos_frame_duration; /* OBJECT_LOCK */
gboolean discont; gboolean discont;
/* qos messages: frames dropped/processed */ /* qos messages: frames dropped/processed */
guint dropped; guint dropped;
@ -1261,7 +1262,6 @@ gst_video_decoder_src_event_default (GstVideoDecoder * decoder,
gdouble proportion; gdouble proportion;
GstClockTimeDiff diff; GstClockTimeDiff diff;
GstClockTime timestamp; GstClockTime timestamp;
GstClockTime duration;
gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp); gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);
@ -1269,15 +1269,7 @@ gst_video_decoder_src_event_default (GstVideoDecoder * decoder,
priv->proportion = proportion; priv->proportion = proportion;
if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (timestamp))) { if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (timestamp))) {
if (G_UNLIKELY (diff > 0)) { if (G_UNLIKELY (diff > 0)) {
GST_VIDEO_DECODER_STREAM_LOCK (decoder); priv->earliest_time = timestamp + 2 * diff + priv->qos_frame_duration;
if (priv->output_state != NULL && priv->output_state->info.fps_n > 0)
duration =
gst_util_uint64_scale (GST_SECOND,
priv->output_state->info.fps_d, priv->output_state->info.fps_n);
else
duration = 0;
GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
priv->earliest_time = timestamp + 2 * diff + duration;
} else { } else {
priv->earliest_time = timestamp + diff; priv->earliest_time = timestamp + diff;
} }
@ -1614,6 +1606,11 @@ gst_video_decoder_reset (GstVideoDecoder * decoder, gboolean full)
if (priv->output_state) if (priv->output_state)
gst_video_codec_state_unref (priv->output_state); gst_video_codec_state_unref (priv->output_state);
priv->output_state = NULL; priv->output_state = NULL;
GST_OBJECT_LOCK (decoder);
priv->qos_frame_duration = 0;
GST_OBJECT_UNLOCK (decoder);
priv->min_latency = 0; priv->min_latency = 0;
priv->max_latency = 0; priv->max_latency = 0;
@ -1652,8 +1649,10 @@ gst_video_decoder_reset (GstVideoDecoder * decoder, gboolean full)
priv->bytes_out = 0; priv->bytes_out = 0;
priv->time = 0; priv->time = 0;
GST_OBJECT_LOCK (decoder);
priv->earliest_time = GST_CLOCK_TIME_NONE; priv->earliest_time = GST_CLOCK_TIME_NONE;
priv->proportion = 0.5; priv->proportion = 0.5;
GST_OBJECT_UNLOCK (decoder);
GST_VIDEO_DECODER_STREAM_UNLOCK (decoder); GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
} }
@ -2226,13 +2225,16 @@ gst_video_decoder_drop_frame (GstVideoDecoder * dec, GstVideoCodecFrame * frame)
dec->priv->dropped++; dec->priv->dropped++;
/* post QoS message */ /* post QoS message */
timestamp = frame->pts; GST_OBJECT_LOCK (dec);
proportion = dec->priv->proportion; proportion = dec->priv->proportion;
earliest_time = dec->priv->earliest_time;
GST_OBJECT_UNLOCK (dec);
timestamp = frame->pts;
segment = &dec->output_segment; segment = &dec->output_segment;
stream_time = stream_time =
gst_segment_to_stream_time (segment, GST_FORMAT_TIME, timestamp); gst_segment_to_stream_time (segment, GST_FORMAT_TIME, timestamp);
qostime = gst_segment_to_running_time (segment, GST_FORMAT_TIME, timestamp); qostime = gst_segment_to_running_time (segment, GST_FORMAT_TIME, timestamp);
earliest_time = dec->priv->earliest_time;
jitter = GST_CLOCK_DIFF (qostime, earliest_time); jitter = GST_CLOCK_DIFF (qostime, earliest_time);
qos_msg = qos_msg =
gst_message_new_qos (GST_OBJECT_CAST (dec), FALSE, qostime, stream_time, gst_message_new_qos (GST_OBJECT_CAST (dec), FALSE, qostime, stream_time,
@ -2629,6 +2631,7 @@ gst_video_decoder_set_output_state (GstVideoDecoder * decoder,
{ {
GstVideoDecoderPrivate *priv = decoder->priv; GstVideoDecoderPrivate *priv = decoder->priv;
GstVideoCodecState *state; GstVideoCodecState *state;
GstClockTime qos_frame_duration;
GST_DEBUG_OBJECT (decoder, "fmt:%d, width:%d, height:%d, reference:%p", GST_DEBUG_OBJECT (decoder, "fmt:%d, width:%d, height:%d, reference:%p",
fmt, width, height, reference); fmt, width, height, reference);
@ -2642,9 +2645,20 @@ gst_video_decoder_set_output_state (GstVideoDecoder * decoder,
gst_video_codec_state_unref (priv->output_state); gst_video_codec_state_unref (priv->output_state);
priv->output_state = gst_video_codec_state_ref (state); priv->output_state = gst_video_codec_state_ref (state);
if (priv->output_state != NULL && priv->output_state->info.fps_n > 0) {
qos_frame_duration =
gst_util_uint64_scale (GST_SECOND, priv->output_state->info.fps_d,
priv->output_state->info.fps_n);
} else {
qos_frame_duration = 0;
}
priv->output_state_changed = TRUE; priv->output_state_changed = TRUE;
GST_VIDEO_DECODER_STREAM_UNLOCK (decoder); GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
GST_OBJECT_LOCK (decoder);
priv->qos_frame_duration = qos_frame_duration;
GST_OBJECT_UNLOCK (decoder);
return state; return state;
} }