applemedia: fix H264 streams with b-frames
authorAndoni Morales Alastruey <ylatuya@gmail.com>
Fri, 26 Apr 2013 15:47:26 +0000 (17:47 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 20 May 2013 11:31:02 +0000 (13:31 +0200)
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
sys/applemedia/vtdec.h

index 97b5fa5..a46ab9b 100644 (file)
@@ -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;
index c74f4ca..ed680fc 100644 (file)
@@ -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);