ducatividenc: properly timestamp frames to cater for B frames
authorVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Thu, 25 Oct 2012 18:03:08 +0000 (18:03 +0000)
committerVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Thu, 25 Oct 2012 18:03:08 +0000 (18:03 +0000)
This relies on an assumption about the codec which is explained
in a comment in the source.

src/gstducatividenc.c

index 5191cf07c5d5072de4e4ab7a2a48d08dddc29d12..cea4ddc7e1a4781042117f334e644ba327b0017f 100644 (file)
@@ -573,6 +573,7 @@ gst_ducati_videnc_handle_frame (GstBaseVideoEncoder * base_video_encoder,
   XDAS_Int32 err;
   const GstVideoState *state;
   int i;
+  GstClockTime ts;
 
   state = gst_base_video_encoder_get_state (base_video_encoder);
 
@@ -586,6 +587,7 @@ gst_ducati_videnc_handle_frame (GstBaseVideoEncoder * base_video_encoder,
   }
 
   inbuf = gst_buffer_ref (frame->sink_buffer);
+  ts = GST_BUFFER_TIMESTAMP (inbuf);
 have_inbuf:
   priv_in = get_buffer_priv (self, inbuf, state->width, state->height);
   if (priv_in == NULL) {
@@ -594,6 +596,7 @@ have_inbuf:
     inbuf = GST_BUFFER (gst_drm_buffer_pool_get (self->input_pool, FALSE));
     memcpy (GST_BUFFER_DATA (inbuf), GST_BUFFER_DATA (frame->sink_buffer),
         GST_BUFFER_SIZE (frame->sink_buffer));
+    GST_BUFFER_TIMESTAMP (inbuf) = ts;
     goto have_inbuf;
   }
 
@@ -648,13 +651,38 @@ have_inbuf:
     return GST_FLOW_ERROR;
   }
 
-  frame->is_sync_point = GST_DUCATIVIDENC_GET_CLASS (self)->is_sync_point (self,
-      self->outArgs->encodedFrameType);
-  frame->src_buffer = gst_buffer_new_and_alloc (self->outArgs->bytesGenerated);
-  memcpy (GST_BUFFER_DATA (frame->src_buffer),
-      GST_BUFFER_DATA (outbuf), self->outArgs->bytesGenerated);
-  GST_DEBUG_OBJECT (self, "Encoded frame in %u bytes",
-      self->outArgs->bytesGenerated);
+  if (self->outArgs->bytesGenerated > 0) {
+    frame->is_sync_point =
+        GST_DUCATIVIDENC_GET_CLASS (self)->is_sync_point (self,
+        self->outArgs->encodedFrameType);
+    frame->src_buffer =
+        gst_buffer_new_and_alloc (self->outArgs->bytesGenerated);
+    memcpy (GST_BUFFER_DATA (frame->src_buffer), GST_BUFFER_DATA (outbuf),
+        self->outArgs->bytesGenerated);
+    GST_DEBUG_OBJECT (self, "Encoded frame in %u bytes",
+        self->outArgs->bytesGenerated);
+
+    /* As we can get frames in a different order we sent them (if the codec
+       supports B frames and we set it up for generating those), we need to
+       work out what input frame corresponds to the frame we just got, to
+       keep presentation times correct.
+       It seems that the codec will free buffers in the right order for this,
+       but I can not find anything saying this in the docs, so:
+       - it might be subject to change
+       - it might not be true in all setups
+       - it might not be true for all codecs
+       However, that's the only way I can see to do it. So there's a nice
+       assert below that will blow up if the codec does not free exactly one
+       input frame when it outputs a frame. That doesn't catch all cases,
+       such as when it frees them in the wrong order, but that seems less
+       likely to happen.
+       The timestamp and duration are given to the base class, which will
+       in turn set them onto the encoded buffer. */
+    g_assert (self->outArgs->freeBufID[0] && !self->outArgs->freeBufID[1]);
+    inbuf = GST_BUFFER (self->outArgs->freeBufID[0]);
+    frame->presentation_timestamp = GST_BUFFER_TIMESTAMP (inbuf);
+    frame->presentation_duration = GST_BUFFER_DURATION (inbuf);
+  }
 
   gst_buffer_unref (outbuf);