From 2f36ffb7d02d844a814a938053d856a96d415fba Mon Sep 17 00:00:00 2001 From: Andoni Morales Alastruey Date: Fri, 26 Apr 2013 17:47:26 +0200 Subject: applemedia: fix H264 streams with b-frames The decoder output frames in DTS order, even with the flag kVTDecodeFrame_EnableTemporalProcessing. We store a internal queue of the decoded frames and push them PTS order. --- sys/applemedia/vtdec.c | 59 +++++++++++++++++++++++++++++++++++--------------- sys/applemedia/vtdec.h | 3 ++- 2 files changed, 43 insertions(+), 19 deletions(-) (limited to 'sys') diff --git a/sys/applemedia/vtdec.c b/sys/applemedia/vtdec.c index 97b5fa579..a46ab9b64 100644 --- a/sys/applemedia/vtdec.c +++ b/sys/applemedia/vtdec.c @@ -162,7 +162,7 @@ gst_vtdec_change_state (GstElement * element, GstStateChange transition) if (error != NULL) goto api_error; - self->cur_outbufs = g_ptr_array_new (); + self->cur_outbufs = g_queue_new (); } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); @@ -175,8 +175,7 @@ gst_vtdec_change_state (GstElement * element, GstStateChange transition) gst_video_info_init (&self->vinfo); - g_ptr_array_free (self->cur_outbufs, TRUE); - self->cur_outbufs = NULL; + g_queue_free_full (self->cur_outbufs, (GDestroyNotify) gst_buffer_unref); g_object_unref (self->ctx); self->ctx = NULL; @@ -455,6 +454,12 @@ gst_vtdec_destroy_session (GstVTDec * self, VTDecompressionSessionRef * session) } } +static gint +_sort_buffers (GstBuffer *buf1, GstBuffer *buf2, void *data) +{ + return GST_BUFFER_PTS(buf1) - GST_BUFFER_PTS(buf2); +} + static GstFlowReturn gst_vtdec_decode_buffer (GstVTDec * self, GstBuffer * buf) { @@ -463,10 +468,10 @@ gst_vtdec_decode_buffer (GstVTDec * self, GstBuffer * buf) VTStatus status; VTDecodeFrameFlags frame_flags = 0; GstFlowReturn ret = GST_FLOW_OK; - guint i; sbuf = gst_vtdec_sample_buffer_from (self, buf); + self->flush = FALSE; status = vt->VTDecompressionSessionDecodeFrame (self->session, sbuf, frame_flags, buf, NULL); if (status != 0) { @@ -483,23 +488,33 @@ gst_vtdec_decode_buffer (GstVTDec * self, GstBuffer * buf) CFRelease (sbuf); gst_buffer_unref (buf); - if (self->cur_outbufs->len > 0) { - if (!gst_vtdec_negotiate_downstream (self)) + if (self->flush) { + if (!gst_vtdec_negotiate_downstream (self)) { ret = GST_FLOW_NOT_NEGOTIATED; - } - - for (i = 0; i != self->cur_outbufs->len; i++) { - GstBuffer *buf = g_ptr_array_index (self->cur_outbufs, i); + goto error; + } - if (ret == GST_FLOW_OK) { + g_queue_sort (self->cur_outbufs, (GCompareDataFunc) _sort_buffers, NULL); + while (!g_queue_is_empty (self->cur_outbufs)) { + buf = g_queue_pop_head (self->cur_outbufs); + GST_LOG_OBJECT (self, "Pushing buffer with PTS:%" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_PTS (buf))); ret = gst_pad_push (self->srcpad, buf); - } else { - gst_buffer_unref (buf); + if (ret != GST_FLOW_OK) { + goto error; + } } - } - g_ptr_array_set_size (self->cur_outbufs, 0); + }; +exit: return ret; + +error: + { + g_queue_free_full (self->cur_outbufs, (GDestroyNotify) gst_buffer_unref); + self->cur_outbufs = g_queue_new (); + goto exit; + } } static void @@ -521,9 +536,17 @@ gst_vtdec_enqueue_frame (void *data1, void *data2, VTStatus result, } buf = gst_core_video_buffer_new (cvbuf, &self->vinfo); - gst_buffer_copy_into (buf, self->cur_inbuf, GST_BUFFER_COPY_METADATA, 0, -1); - - g_ptr_array_add (self->cur_outbufs, buf); + gst_buffer_copy_into (buf, src_buf, GST_BUFFER_COPY_METADATA, 0, -1); + GST_BUFFER_PTS (buf) = pts.value; + GST_BUFFER_DURATION (buf) = duration.value; + + g_queue_push_head (self->cur_outbufs, buf); + if (GST_BUFFER_PTS (src_buf) <= GST_BUFFER_DTS (src_buf)) { + GST_LOG_OBJECT (self, "Flushing interal queue of buffers"); + self->flush = TRUE; + } else { + GST_LOG_OBJECT (self, "Queuing buffer"); + } beach: return; diff --git a/sys/applemedia/vtdec.h b/sys/applemedia/vtdec.h index c74f4ca24..ed680fc7b 100644 --- a/sys/applemedia/vtdec.h +++ b/sys/applemedia/vtdec.h @@ -67,7 +67,8 @@ struct _GstVTDec CMFormatDescriptionRef fmt_desc; VTDecompressionSessionRef session; - GPtrArray * cur_outbufs; + GQueue * cur_outbufs; + gboolean flush; }; void gst_vtdec_register_elements (GstPlugin * plugin); -- cgit v1.2.1