mfc: Implement tracking of frames using the v4l2_buffer timestamp
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 24 Dec 2012 14:34:49 +0000 (15:34 +0100)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 31 Dec 2012 14:59:06 +0000 (15:59 +0100)
sys/mfc/gstmfcdec.c
sys/mfc/mfc_decoder/mfc_decoder.c
sys/mfc/mfc_decoder/mfc_decoder.h

index 73218b6..6c92efa 100644 (file)
@@ -221,7 +221,7 @@ gst_mfc_dec_reset (GstVideoDecoder * decoder, gboolean hard)
 }
 
 static GstFlowReturn
-gst_mfc_dec_queue_input (GstMFCDec * self, GstBuffer * inbuf)
+gst_mfc_dec_queue_input (GstMFCDec * self, GstVideoCodecFrame * frame)
 {
   GstFlowReturn ret = GST_FLOW_OK;
   gint mfc_ret;
@@ -229,6 +229,7 @@ gst_mfc_dec_queue_input (GstMFCDec * self, GstBuffer * inbuf)
   guint8 *mfc_inbuf_data;
   gint mfc_inbuf_size;
   GstMapInfo map;
+  struct timeval timestamp;
 
   GST_DEBUG_OBJECT (self, "Dequeueing input");
 
@@ -244,8 +245,8 @@ gst_mfc_dec_queue_input (GstMFCDec * self, GstBuffer * inbuf)
 
   g_assert (mfc_inbuf != NULL);
 
-  if (inbuf) {
-    gst_buffer_map (inbuf, &map, GST_MAP_READ);
+  if (frame) {
+    gst_buffer_map (frame->input_buffer, &map, GST_MAP_READ);
 
     mfc_inbuf_data = (guint8 *) mfc_buffer_get_input_data (mfc_inbuf);
     g_assert (mfc_inbuf_data != NULL);
@@ -260,14 +261,20 @@ gst_mfc_dec_queue_input (GstMFCDec * self, GstBuffer * inbuf)
     memcpy (mfc_inbuf_data, map.data, map.size);
     mfc_buffer_set_input_size (mfc_inbuf, map.size);
 
-    gst_buffer_unmap (inbuf, &map);
+    gst_buffer_unmap (frame->input_buffer, &map);
+
+    timestamp.tv_usec = 0;
+    timestamp.tv_sec = frame->system_frame_number;
   } else {
     GST_DEBUG_OBJECT (self, "Passing EOS input buffer");
 
     mfc_buffer_set_input_size (mfc_inbuf, 0);
+    timestamp.tv_usec = 0;
+    timestamp.tv_sec = -1;
   }
 
-  if ((mfc_ret = mfc_dec_enqueue_input (self->context, mfc_inbuf)) < 0)
+  if ((mfc_ret =
+          mfc_dec_enqueue_input (self->context, mfc_inbuf, &timestamp)) < 0)
     goto enqueue_error;
 
 done:
@@ -287,7 +294,7 @@ too_small_inbuf:
     GST_ELEMENT_ERROR (self, STREAM, FORMAT, ("Too large input frames"),
         ("Maximum size %d, got %d", mfc_inbuf_size, map.size));
     ret = GST_FLOW_ERROR;
-    gst_buffer_unmap (inbuf, &map);
+    gst_buffer_unmap (frame->input_buffer, &map);
     goto done;
   }
 
@@ -301,32 +308,6 @@ enqueue_error:
   }
 }
 
-static GstVideoCodecFrame *
-gst_mfc_dec_get_earliest_frame (GstMFCDec * self)
-{
-  GstVideoCodecFrame *frame = NULL;
-  GList *frames, *l;
-
-  frames = gst_video_decoder_get_frames (GST_VIDEO_DECODER (self));
-
-  for (l = frames; l; l = l->next) {
-    GstVideoCodecFrame *tmp = (GstVideoCodecFrame *) l->data;
-
-    if (!frame) {
-      frame = tmp;
-    } else if (frame->pts > tmp->pts) {
-      gst_video_codec_frame_unref (frame);
-      frame = tmp;
-    } else {
-      gst_video_codec_frame_unref (tmp);
-    }
-  }
-
-  g_list_free (frames);
-
-  return frame;
-}
-
 static gboolean
 gst_mfc_dec_negotiate (GstVideoDecoder * decoder)
 {
@@ -416,6 +397,7 @@ gst_mfc_dec_dequeue_output (GstMFCDec * self)
   gint64 deadline;
   Fimc *fimc = NULL;
   GstVideoFrame vframe;
+  struct timeval timestamp;
 
   if (!self->initialized) {
     GST_DEBUG_OBJECT (self, "Initializing decoder");
@@ -463,10 +445,13 @@ gst_mfc_dec_dequeue_output (GstMFCDec * self)
       state = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self));
     }
 
-    if ((mfc_ret = mfc_dec_dequeue_output (self->context, &mfc_outbuf)) < 0) {
+    if ((mfc_ret =
+            mfc_dec_dequeue_output (self->context, &mfc_outbuf,
+                &timestamp)) < 0) {
       if (mfc_ret == -2) {
         GST_DEBUG_OBJECT (self, "Timeout dequeueing output, trying again");
-        mfc_ret = mfc_dec_dequeue_output (self->context, &mfc_outbuf);
+        mfc_ret =
+            mfc_dec_dequeue_output (self->context, &mfc_outbuf, &timestamp);
       }
 
       if (mfc_ret < 0)
@@ -475,8 +460,11 @@ gst_mfc_dec_dequeue_output (GstMFCDec * self)
 
     g_assert (mfc_outbuf != NULL);
 
-    /* FIXME: Replace this by gst_video_decoder_get_frame() with an ID */
-    frame = gst_mfc_dec_get_earliest_frame (self);
+    frame = NULL;
+    if (timestamp.tv_sec != -1)
+      frame =
+          gst_video_decoder_get_frame (GST_VIDEO_DECODER (self),
+          timestamp.tv_sec);
 
     if (frame) {
       deadline =
@@ -677,15 +665,7 @@ gst_mfc_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
 
   GST_DEBUG_OBJECT (self, "Handling frame");
 
-  /* FIXME: Would be good to assign an ID to input frames */
-  if (frame->pts == GST_CLOCK_TIME_NONE) {
-    GST_ERROR_OBJECT (self, "Only PTS timestamped streams supported so far");
-    gst_video_codec_frame_unref (frame);
-    return GST_FLOW_ERROR;
-  }
-
-  if ((ret =
-          gst_mfc_dec_queue_input (self, frame->input_buffer)) != GST_FLOW_OK) {
+  if ((ret = gst_mfc_dec_queue_input (self, frame)) != GST_FLOW_OK) {
     gst_video_codec_frame_unref (frame);
     return ret;
   }
index ac0e7ce..4ce6bee 100644 (file)
@@ -450,7 +450,7 @@ void mfc_dec_destroy(struct mfc_dec_context *ctx)
     free(ctx);
 }
 
-int mfc_dec_enqueue_input(struct mfc_dec_context *ctx, struct mfc_buffer *buffer)
+int mfc_dec_enqueue_input(struct mfc_dec_context *ctx, struct mfc_buffer *buffer, struct timeval *timestamp)
 {
     struct v4l2_plane planes[NUM_INPUT_PLANES] = {
         [0] = {
@@ -467,6 +467,9 @@ int mfc_dec_enqueue_input(struct mfc_dec_context *ctx, struct mfc_buffer *buffer
         },
     };
 
+    if (timestamp)
+      qbuf.timestamp = *timestamp;
+
     if (ioctl(ctx->fd, VIDIOC_QBUF, &qbuf) < 0) {
         GST_ERROR ("Enqueuing of input buffer %d failed; prev state: %d",
              buffer->index, buffer->state);
@@ -589,7 +592,7 @@ int mfc_dec_enqueue_output(struct mfc_dec_context *ctx, struct mfc_buffer *buffe
     return 0;
 }
 
-int mfc_dec_dequeue_output(struct mfc_dec_context *ctx, struct mfc_buffer **buffer)
+int mfc_dec_dequeue_output(struct mfc_dec_context *ctx, struct mfc_buffer **buffer, struct timeval *timestamp)
 {
     int i;
     struct v4l2_plane planes[NUM_OUTPUT_PLANES];
@@ -611,6 +614,10 @@ int mfc_dec_dequeue_output(struct mfc_dec_context *ctx, struct mfc_buffer **buff
         ctx->output_buffer[qbuf.index].plane[i].bytesused = qbuf.m.planes[i].bytesused;
 
     *buffer = &(ctx->output_buffer[qbuf.index]);
+
+    if (timestamp)
+      *timestamp = qbuf.timestamp;
+
     ctx->output_frames_available--;
     return 0;
 }
@@ -637,7 +644,7 @@ int mfc_dec_flush(struct mfc_dec_context *ctx)
         struct mfc_buffer *buffer;
         /* Make sure there is room for the decode to finish */
         if (mfc_dec_output_available(ctx) || force_dequeue_output) {
-            if (mfc_dec_dequeue_output(ctx, &buffer) < 0)
+            if (mfc_dec_dequeue_output(ctx, &buffer, NULL) < 0)
                 return -1;
             if (mfc_dec_enqueue_output(ctx, buffer) < 0)
                 return -1;
index 88169cc..087d17f 100644 (file)
@@ -48,6 +48,8 @@
 #ifndef VIDEO_EXYNOS4_MFC_V4L2_INCLUDE_MFC_DECODER_H
 #define VIDEO_EXYNOS4_MFC_V4L2_INCLUDE_MFC_DECODER_H
 
+#include <sys/time.h>
+
 struct mfc_buffer;
 struct mfc_dec_context;
 
@@ -157,7 +159,7 @@ int mfc_dec_output_available(struct mfc_dec_context*);
  */
 
 /* Enqueue frame containing compressed data */
-int mfc_dec_enqueue_input(struct mfc_dec_context*, struct mfc_buffer *buffer);
+int mfc_dec_enqueue_input(struct mfc_dec_context*, struct mfc_buffer *buffer, struct timeval *timestamp);
 /*
  * Dequeue a processed input frame.  Will block until one is available.
  *
@@ -173,7 +175,7 @@ int mfc_dec_enqueue_output(struct mfc_dec_context*, struct mfc_buffer *buffer);
  * when mfc_dec_output_available() is not true, subsequent video
  * frames may not decode correctly.
  */
-int mfc_dec_dequeue_output(struct mfc_dec_context*, struct mfc_buffer **buffer);
+int mfc_dec_dequeue_output(struct mfc_dec_context*, struct mfc_buffer **buffer, struct timeval *timestamp);
 
 
 /*