androidmedia: Fix draining logic to let the base class handle EOS events

https://bugzilla.gnome.org//show_bug.cgi?id=734775
This commit is contained in:
Sebastian Dröge 2014-08-14 15:24:21 +03:00
parent 17181bfe16
commit ca62186797
6 changed files with 39 additions and 101 deletions

View file

@ -717,7 +717,7 @@ gst_amc_audio_dec_start (GstAudioDecoder * decoder)
self = GST_AMC_AUDIO_DEC (decoder); self = GST_AMC_AUDIO_DEC (decoder);
self->last_upstream_ts = 0; self->last_upstream_ts = 0;
self->eos = FALSE; self->drained = TRUE;
self->downstream_flow_ret = GST_FLOW_OK; self->downstream_flow_ret = GST_FLOW_OK;
self->started = FALSE; self->started = FALSE;
self->flushing = TRUE; self->flushing = TRUE;
@ -758,7 +758,7 @@ gst_amc_audio_dec_stop (GstAudioDecoder * decoder)
self->codec_datas = NULL; self->codec_datas = NULL;
self->downstream_flow_ret = GST_FLOW_FLUSHING; self->downstream_flow_ret = GST_FLOW_FLUSHING;
self->eos = FALSE; self->drained = TRUE;
g_mutex_lock (&self->drain_lock); g_mutex_lock (&self->drain_lock);
self->draining = FALSE; self->draining = FALSE;
g_cond_broadcast (&self->drain_cond); g_cond_broadcast (&self->drain_cond);
@ -990,7 +990,7 @@ gst_amc_audio_dec_flush (GstAudioDecoder * decoder, gboolean hard)
/* Start the srcpad loop again */ /* Start the srcpad loop again */
self->last_upstream_ts = 0; self->last_upstream_ts = 0;
self->eos = FALSE; self->drained = TRUE;
self->downstream_flow_ret = GST_FLOW_OK; self->downstream_flow_ret = GST_FLOW_OK;
gst_pad_start_task (GST_AUDIO_DECODER_SRC_PAD (self), gst_pad_start_task (GST_AUDIO_DECODER_SRC_PAD (self),
(GstTaskFunction) gst_amc_audio_dec_loop, decoder, NULL); (GstTaskFunction) gst_amc_audio_dec_loop, decoder, NULL);
@ -1029,13 +1029,6 @@ gst_amc_audio_dec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf)
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
} }
if (self->eos) {
GST_WARNING_OBJECT (self, "Got frame after EOS");
if (inbuf)
gst_buffer_unref (inbuf);
return GST_FLOW_EOS;
}
if (self->flushing) if (self->flushing)
goto flushing; goto flushing;
@ -1144,6 +1137,7 @@ gst_amc_audio_dec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf)
} }
goto queue_error; goto queue_error;
} }
self->drained = FALSE;
} }
gst_buffer_unmap (inbuf, &minfo); gst_buffer_unmap (inbuf, &minfo);
gst_buffer_unref (inbuf); gst_buffer_unref (inbuf);
@ -1212,9 +1206,9 @@ gst_amc_audio_dec_drain (GstAmcAudioDec * self)
return GST_FLOW_OK; return GST_FLOW_OK;
} }
/* Don't send EOS buffer twice, this doesn't work */ /* Don't send drain buffer twice, this doesn't work */
if (self->eos) { if (self->drained) {
GST_DEBUG_OBJECT (self, "Codec is EOS already"); GST_DEBUG_OBJECT (self, "Codec is drained already");
return GST_FLOW_OK; return GST_FLOW_OK;
} }
@ -1258,6 +1252,8 @@ gst_amc_audio_dec_drain (GstAmcAudioDec * self)
} }
} }
self->drained = TRUE;
self->draining = FALSE;
g_mutex_unlock (&self->drain_lock); g_mutex_unlock (&self->drain_lock);
GST_AUDIO_DECODER_STREAM_LOCK (self); GST_AUDIO_DECODER_STREAM_LOCK (self);
} else if (idx >= self->n_input_buffers) { } else if (idx >= self->n_input_buffers) {

View file

@ -78,9 +78,8 @@ struct _GstAmcAudioDec
GCond drain_cond; GCond drain_cond;
/* TRUE if EOS buffers shouldn't be forwarded */ /* TRUE if EOS buffers shouldn't be forwarded */
gboolean draining; gboolean draining;
/* TRUE if the component is drained currently */
/* TRUE if upstream is EOS */ gboolean drained;
gboolean eos;
GstFlowReturn downstream_flow_ret; GstFlowReturn downstream_flow_ret;

View file

@ -88,8 +88,7 @@ static GstFlowReturn gst_amc_video_dec_finish (GstVideoDecoder * decoder);
static gboolean gst_amc_video_dec_decide_allocation (GstVideoDecoder * bdec, static gboolean gst_amc_video_dec_decide_allocation (GstVideoDecoder * bdec,
GstQuery * query); GstQuery * query);
static GstFlowReturn gst_amc_video_dec_drain (GstAmcVideoDec * self, static GstFlowReturn gst_amc_video_dec_drain (GstAmcVideoDec * self);
gboolean at_eos);
enum enum
{ {
@ -874,7 +873,7 @@ gst_amc_video_dec_start (GstVideoDecoder * decoder)
self = GST_AMC_VIDEO_DEC (decoder); self = GST_AMC_VIDEO_DEC (decoder);
self->last_upstream_ts = 0; self->last_upstream_ts = 0;
self->eos = FALSE; self->drained = TRUE;
self->downstream_flow_ret = GST_FLOW_OK; self->downstream_flow_ret = GST_FLOW_OK;
self->started = FALSE; self->started = FALSE;
self->flushing = TRUE; self->flushing = TRUE;
@ -909,7 +908,7 @@ gst_amc_video_dec_stop (GstVideoDecoder * decoder)
gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder)); gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder));
self->downstream_flow_ret = GST_FLOW_FLUSHING; self->downstream_flow_ret = GST_FLOW_FLUSHING;
self->eos = FALSE; self->drained = TRUE;
g_mutex_lock (&self->drain_lock); g_mutex_lock (&self->drain_lock);
self->draining = FALSE; self->draining = FALSE;
g_cond_broadcast (&self->drain_cond); g_cond_broadcast (&self->drain_cond);
@ -983,7 +982,7 @@ gst_amc_video_dec_set_format (GstVideoDecoder * decoder,
} }
if (needs_disable && is_format_change) { if (needs_disable && is_format_change) {
gst_amc_video_dec_drain (self, FALSE); gst_amc_video_dec_drain (self);
GST_VIDEO_DECODER_STREAM_UNLOCK (self); GST_VIDEO_DECODER_STREAM_UNLOCK (self);
gst_amc_video_dec_stop (GST_VIDEO_DECODER (self)); gst_amc_video_dec_stop (GST_VIDEO_DECODER (self));
GST_VIDEO_DECODER_STREAM_LOCK (self); GST_VIDEO_DECODER_STREAM_LOCK (self);
@ -1104,7 +1103,7 @@ gst_amc_video_dec_flush (GstVideoDecoder * decoder)
/* Start the srcpad loop again */ /* Start the srcpad loop again */
self->last_upstream_ts = 0; self->last_upstream_ts = 0;
self->eos = FALSE; self->drained = TRUE;
self->downstream_flow_ret = GST_FLOW_OK; self->downstream_flow_ret = GST_FLOW_OK;
gst_pad_start_task (GST_VIDEO_DECODER_SRC_PAD (self), gst_pad_start_task (GST_VIDEO_DECODER_SRC_PAD (self),
(GstTaskFunction) gst_amc_video_dec_loop, decoder, NULL); (GstTaskFunction) gst_amc_video_dec_loop, decoder, NULL);
@ -1139,12 +1138,6 @@ gst_amc_video_dec_handle_frame (GstVideoDecoder * decoder,
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
} }
if (self->eos) {
GST_WARNING_OBJECT (self, "Got frame after EOS");
gst_video_codec_frame_unref (frame);
return GST_FLOW_EOS;
}
if (self->flushing) if (self->flushing)
goto flushing; goto flushing;
@ -1254,6 +1247,7 @@ gst_amc_video_dec_handle_frame (GstVideoDecoder * decoder,
} }
goto queue_error; goto queue_error;
} }
self->drained = FALSE;
} }
gst_buffer_unmap (frame->input_buffer, &minfo); gst_buffer_unmap (frame->input_buffer, &minfo);
@ -1312,11 +1306,11 @@ gst_amc_video_dec_finish (GstVideoDecoder * decoder)
self = GST_AMC_VIDEO_DEC (decoder); self = GST_AMC_VIDEO_DEC (decoder);
return gst_amc_video_dec_drain (self, TRUE); return gst_amc_video_dec_drain (self);
} }
static GstFlowReturn static GstFlowReturn
gst_amc_video_dec_drain (GstAmcVideoDec * self, gboolean at_eos) gst_amc_video_dec_drain (GstAmcVideoDec * self)
{ {
GstFlowReturn ret; GstFlowReturn ret;
gint idx; gint idx;
@ -1328,13 +1322,11 @@ gst_amc_video_dec_drain (GstAmcVideoDec * self, gboolean at_eos)
return GST_FLOW_OK; return GST_FLOW_OK;
} }
/* Don't send EOS buffer twice, this doesn't work */ /* Don't send drain buffer twice, this doesn't work */
if (self->eos) { if (self->drained) {
GST_DEBUG_OBJECT (self, "Codec is EOS already"); GST_DEBUG_OBJECT (self, "Codec is drained already");
return GST_FLOW_OK; return GST_FLOW_OK;
} }
if (at_eos)
self->eos = TRUE;
/* Make sure to release the base class stream lock, otherwise /* Make sure to release the base class stream lock, otherwise
* _loop() can't call _finish_frame() and we might block forever * _loop() can't call _finish_frame() and we might block forever
@ -1376,6 +1368,8 @@ gst_amc_video_dec_drain (GstAmcVideoDec * self, gboolean at_eos)
} }
} }
self->drained = TRUE;
self->draining = FALSE;
g_mutex_unlock (&self->drain_lock); g_mutex_unlock (&self->drain_lock);
GST_VIDEO_DECODER_STREAM_LOCK (self); GST_VIDEO_DECODER_STREAM_LOCK (self);
} else if (idx >= self->n_input_buffers) { } else if (idx >= self->n_input_buffers) {

View file

@ -75,9 +75,8 @@ struct _GstAmcVideoDec
GCond drain_cond; GCond drain_cond;
/* TRUE if EOS buffers shouldn't be forwarded */ /* TRUE if EOS buffers shouldn't be forwarded */
gboolean draining; gboolean draining;
/* TRUE if the component is drained currently */
/* TRUE if upstream is EOS */ gboolean drained;
gboolean eos;
GstFlowReturn downstream_flow_ret; GstFlowReturn downstream_flow_ret;
}; };

View file

@ -1172,7 +1172,7 @@ gst_amc_video_enc_start (GstVideoEncoder * encoder)
self = GST_AMC_VIDEO_ENC (encoder); self = GST_AMC_VIDEO_ENC (encoder);
self->last_upstream_ts = 0; self->last_upstream_ts = 0;
self->eos = FALSE; self->drained = TRUE;
self->downstream_flow_ret = GST_FLOW_OK; self->downstream_flow_ret = GST_FLOW_OK;
self->started = FALSE; self->started = FALSE;
self->flushing = TRUE; self->flushing = TRUE;
@ -1207,7 +1207,7 @@ gst_amc_video_enc_stop (GstVideoEncoder * encoder)
gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder)); gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder));
self->downstream_flow_ret = GST_FLOW_FLUSHING; self->downstream_flow_ret = GST_FLOW_FLUSHING;
self->eos = FALSE; self->drained = TRUE;
g_mutex_lock (&self->drain_lock); g_mutex_lock (&self->drain_lock);
self->draining = FALSE; self->draining = FALSE;
g_cond_broadcast (&self->drain_cond); g_cond_broadcast (&self->drain_cond);
@ -1384,7 +1384,7 @@ gst_amc_video_enc_flush (GstVideoEncoder * encoder)
/* Start the srcpad loop again */ /* Start the srcpad loop again */
self->last_upstream_ts = 0; self->last_upstream_ts = 0;
self->eos = FALSE; self->drained = TRUE;
self->downstream_flow_ret = GST_FLOW_OK; self->downstream_flow_ret = GST_FLOW_OK;
gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self), gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self),
(GstTaskFunction) gst_amc_video_enc_loop, encoder, NULL); (GstTaskFunction) gst_amc_video_enc_loop, encoder, NULL);
@ -1416,12 +1416,6 @@ gst_amc_video_enc_handle_frame (GstVideoEncoder * encoder,
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
} }
if (self->eos) {
GST_WARNING_OBJECT (self, "Got frame after EOS");
gst_video_codec_frame_unref (frame);
return GST_FLOW_EOS;
}
if (self->flushing) if (self->flushing)
goto flushing; goto flushing;
@ -1527,6 +1521,8 @@ again:
goto queue_error; goto queue_error;
} }
self->drained = FALSE;
gst_video_codec_frame_unref (frame); gst_video_codec_frame_unref (frame);
return self->downstream_flow_ret; return self->downstream_flow_ret;
@ -1578,57 +1574,10 @@ static GstFlowReturn
gst_amc_video_enc_finish (GstVideoEncoder * encoder) gst_amc_video_enc_finish (GstVideoEncoder * encoder)
{ {
GstAmcVideoEnc *self; GstAmcVideoEnc *self;
gint idx;
GError *err = NULL;
self = GST_AMC_VIDEO_ENC (encoder); self = GST_AMC_VIDEO_ENC (encoder);
GST_DEBUG_OBJECT (self, "Sending EOS to the component");
/* Don't send EOS buffer twice, this doesn't work */ return gst_amc_video_enc_drain (self);
if (self->eos) {
GST_DEBUG_OBJECT (self, "Component is already EOS");
return GST_VIDEO_ENCODER_FLOW_DROPPED;
}
self->eos = TRUE;
/* Make sure to release the base class stream lock, otherwise
* _loop() can't call _finish_frame() and we might block forever
* because no input buffers are released */
GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
/* Send an EOS buffer to the component and let the base
* class drop the EOS event. We will send it later when
* the EOS buffer arrives on the output port.
* Wait at most 0.5s here. */
idx = gst_amc_codec_dequeue_input_buffer (self->codec, 500000, &err);
GST_VIDEO_ENCODER_STREAM_LOCK (self);
if (idx >= 0 && idx < self->n_input_buffers) {
GstAmcBufferInfo buffer_info;
memset (&buffer_info, 0, sizeof (buffer_info));
buffer_info.size = 0;
buffer_info.presentation_time_us =
gst_util_uint64_scale (self->last_upstream_ts, 1, GST_USECOND);
buffer_info.flags |= BUFFER_FLAG_END_OF_STREAM;
if (gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, &err)) {
GST_DEBUG_OBJECT (self, "Sent EOS to the codec");
} else {
GST_ERROR_OBJECT (self, "Failed to send EOS to the codec");
if (!self->flushing)
GST_ELEMENT_WARNING_FROM_ERROR (self, err);
g_clear_error (&err);
}
} else if (idx >= self->n_input_buffers) {
GST_ERROR_OBJECT (self, "Invalid input buffer index %d of %d",
idx, self->n_input_buffers);
} else {
GST_ERROR_OBJECT (self, "Failed to dequeue input buffer for EOS: %d", idx);
if (err)
GST_ELEMENT_WARNING_FROM_ERROR (self, err);
}
return GST_VIDEO_ENCODER_FLOW_DROPPED;
} }
static GstFlowReturn static GstFlowReturn
@ -1644,9 +1593,9 @@ gst_amc_video_enc_drain (GstAmcVideoEnc * self)
return GST_FLOW_OK; return GST_FLOW_OK;
} }
/* Don't send EOS buffer twice, this doesn't work */ /* Don't send drain buffer twice, this doesn't work */
if (self->eos) { if (self->drained) {
GST_DEBUG_OBJECT (self, "Codec is EOS already"); GST_DEBUG_OBJECT (self, "Codec is drained already");
return GST_FLOW_OK; return GST_FLOW_OK;
} }
@ -1690,6 +1639,8 @@ gst_amc_video_enc_drain (GstAmcVideoEnc * self)
} }
} }
self->drained = TRUE;
self->draining = FALSE;
g_mutex_unlock (&self->drain_lock); g_mutex_unlock (&self->drain_lock);
GST_VIDEO_ENCODER_STREAM_LOCK (self); GST_VIDEO_ENCODER_STREAM_LOCK (self);
} else if (idx >= self->n_input_buffers) { } else if (idx >= self->n_input_buffers) {

View file

@ -78,9 +78,8 @@ struct _GstAmcVideoEnc
GCond drain_cond; GCond drain_cond;
/* TRUE if EOS buffers shouldn't be forwarded */ /* TRUE if EOS buffers shouldn't be forwarded */
gboolean draining; gboolean draining;
/* TRUE if the component is drained */
/* TRUE if upstream is EOS */ gboolean drained;
gboolean eos;
GstFlowReturn downstream_flow_ret; GstFlowReturn downstream_flow_ret;
}; };