From fe5b268a1c19ce85870fb1c3a04276bf19b4eb40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 24 Dec 2012 15:34:49 +0100 Subject: [PATCH] mfc: Implement tracking of frames using the v4l2_buffer timestamp --- sys/mfc/gstmfcdec.c | 70 +++++++++++-------------------- sys/mfc/mfc_decoder/mfc_decoder.c | 13 ++++-- sys/mfc/mfc_decoder/mfc_decoder.h | 6 ++- 3 files changed, 39 insertions(+), 50 deletions(-) diff --git a/sys/mfc/gstmfcdec.c b/sys/mfc/gstmfcdec.c index 73218b64f3..6c92efab06 100644 --- a/sys/mfc/gstmfcdec.c +++ b/sys/mfc/gstmfcdec.c @@ -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, ×tamp)) < 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, + ×tamp)) < 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, ×tamp); } 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; } diff --git a/sys/mfc/mfc_decoder/mfc_decoder.c b/sys/mfc/mfc_decoder/mfc_decoder.c index ac0e7cec36..4ce6bee1dd 100644 --- a/sys/mfc/mfc_decoder/mfc_decoder.c +++ b/sys/mfc/mfc_decoder/mfc_decoder.c @@ -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; diff --git a/sys/mfc/mfc_decoder/mfc_decoder.h b/sys/mfc/mfc_decoder/mfc_decoder.h index 88169cc484..087d17fd47 100644 --- a/sys/mfc/mfc_decoder/mfc_decoder.h +++ b/sys/mfc/mfc_decoder/mfc_decoder.h @@ -48,6 +48,8 @@ #ifndef VIDEO_EXYNOS4_MFC_V4L2_INCLUDE_MFC_DECODER_H #define VIDEO_EXYNOS4_MFC_V4L2_INCLUDE_MFC_DECODER_H +#include + 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); /*