mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 06:46:38 +00:00
mfc: Implement tracking of frames using the v4l2_buffer timestamp
This commit is contained in:
parent
35400051fa
commit
fe5b268a1c
3 changed files with 39 additions and 50 deletions
|
@ -221,7 +221,7 @@ gst_mfc_dec_reset (GstVideoDecoder * decoder, gboolean hard)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
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;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
gint mfc_ret;
|
gint mfc_ret;
|
||||||
|
@ -229,6 +229,7 @@ gst_mfc_dec_queue_input (GstMFCDec * self, GstBuffer * inbuf)
|
||||||
guint8 *mfc_inbuf_data;
|
guint8 *mfc_inbuf_data;
|
||||||
gint mfc_inbuf_size;
|
gint mfc_inbuf_size;
|
||||||
GstMapInfo map;
|
GstMapInfo map;
|
||||||
|
struct timeval timestamp;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Dequeueing input");
|
GST_DEBUG_OBJECT (self, "Dequeueing input");
|
||||||
|
|
||||||
|
@ -244,8 +245,8 @@ gst_mfc_dec_queue_input (GstMFCDec * self, GstBuffer * inbuf)
|
||||||
|
|
||||||
g_assert (mfc_inbuf != NULL);
|
g_assert (mfc_inbuf != NULL);
|
||||||
|
|
||||||
if (inbuf) {
|
if (frame) {
|
||||||
gst_buffer_map (inbuf, &map, GST_MAP_READ);
|
gst_buffer_map (frame->input_buffer, &map, GST_MAP_READ);
|
||||||
|
|
||||||
mfc_inbuf_data = (guint8 *) mfc_buffer_get_input_data (mfc_inbuf);
|
mfc_inbuf_data = (guint8 *) mfc_buffer_get_input_data (mfc_inbuf);
|
||||||
g_assert (mfc_inbuf_data != NULL);
|
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);
|
memcpy (mfc_inbuf_data, map.data, map.size);
|
||||||
mfc_buffer_set_input_size (mfc_inbuf, 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 {
|
} else {
|
||||||
GST_DEBUG_OBJECT (self, "Passing EOS input buffer");
|
GST_DEBUG_OBJECT (self, "Passing EOS input buffer");
|
||||||
|
|
||||||
mfc_buffer_set_input_size (mfc_inbuf, 0);
|
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;
|
goto enqueue_error;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -287,7 +294,7 @@ too_small_inbuf:
|
||||||
GST_ELEMENT_ERROR (self, STREAM, FORMAT, ("Too large input frames"),
|
GST_ELEMENT_ERROR (self, STREAM, FORMAT, ("Too large input frames"),
|
||||||
("Maximum size %d, got %d", mfc_inbuf_size, map.size));
|
("Maximum size %d, got %d", mfc_inbuf_size, map.size));
|
||||||
ret = GST_FLOW_ERROR;
|
ret = GST_FLOW_ERROR;
|
||||||
gst_buffer_unmap (inbuf, &map);
|
gst_buffer_unmap (frame->input_buffer, &map);
|
||||||
goto done;
|
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
|
static gboolean
|
||||||
gst_mfc_dec_negotiate (GstVideoDecoder * decoder)
|
gst_mfc_dec_negotiate (GstVideoDecoder * decoder)
|
||||||
{
|
{
|
||||||
|
@ -416,6 +397,7 @@ gst_mfc_dec_dequeue_output (GstMFCDec * self)
|
||||||
gint64 deadline;
|
gint64 deadline;
|
||||||
Fimc *fimc = NULL;
|
Fimc *fimc = NULL;
|
||||||
GstVideoFrame vframe;
|
GstVideoFrame vframe;
|
||||||
|
struct timeval timestamp;
|
||||||
|
|
||||||
if (!self->initialized) {
|
if (!self->initialized) {
|
||||||
GST_DEBUG_OBJECT (self, "Initializing decoder");
|
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));
|
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) {
|
if (mfc_ret == -2) {
|
||||||
GST_DEBUG_OBJECT (self, "Timeout dequeueing output, trying again");
|
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)
|
if (mfc_ret < 0)
|
||||||
|
@ -475,8 +460,11 @@ gst_mfc_dec_dequeue_output (GstMFCDec * self)
|
||||||
|
|
||||||
g_assert (mfc_outbuf != NULL);
|
g_assert (mfc_outbuf != NULL);
|
||||||
|
|
||||||
/* FIXME: Replace this by gst_video_decoder_get_frame() with an ID */
|
frame = NULL;
|
||||||
frame = gst_mfc_dec_get_earliest_frame (self);
|
if (timestamp.tv_sec != -1)
|
||||||
|
frame =
|
||||||
|
gst_video_decoder_get_frame (GST_VIDEO_DECODER (self),
|
||||||
|
timestamp.tv_sec);
|
||||||
|
|
||||||
if (frame) {
|
if (frame) {
|
||||||
deadline =
|
deadline =
|
||||||
|
@ -677,15 +665,7 @@ gst_mfc_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Handling frame");
|
GST_DEBUG_OBJECT (self, "Handling frame");
|
||||||
|
|
||||||
/* FIXME: Would be good to assign an ID to input frames */
|
if ((ret = gst_mfc_dec_queue_input (self, frame)) != GST_FLOW_OK) {
|
||||||
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) {
|
|
||||||
gst_video_codec_frame_unref (frame);
|
gst_video_codec_frame_unref (frame);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -450,7 +450,7 @@ void mfc_dec_destroy(struct mfc_dec_context *ctx)
|
||||||
free(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] = {
|
struct v4l2_plane planes[NUM_INPUT_PLANES] = {
|
||||||
[0] = {
|
[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) {
|
if (ioctl(ctx->fd, VIDIOC_QBUF, &qbuf) < 0) {
|
||||||
GST_ERROR ("Enqueuing of input buffer %d failed; prev state: %d",
|
GST_ERROR ("Enqueuing of input buffer %d failed; prev state: %d",
|
||||||
buffer->index, buffer->state);
|
buffer->index, buffer->state);
|
||||||
|
@ -589,7 +592,7 @@ int mfc_dec_enqueue_output(struct mfc_dec_context *ctx, struct mfc_buffer *buffe
|
||||||
return 0;
|
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;
|
int i;
|
||||||
struct v4l2_plane planes[NUM_OUTPUT_PLANES];
|
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;
|
ctx->output_buffer[qbuf.index].plane[i].bytesused = qbuf.m.planes[i].bytesused;
|
||||||
|
|
||||||
*buffer = &(ctx->output_buffer[qbuf.index]);
|
*buffer = &(ctx->output_buffer[qbuf.index]);
|
||||||
|
|
||||||
|
if (timestamp)
|
||||||
|
*timestamp = qbuf.timestamp;
|
||||||
|
|
||||||
ctx->output_frames_available--;
|
ctx->output_frames_available--;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -637,7 +644,7 @@ int mfc_dec_flush(struct mfc_dec_context *ctx)
|
||||||
struct mfc_buffer *buffer;
|
struct mfc_buffer *buffer;
|
||||||
/* Make sure there is room for the decode to finish */
|
/* Make sure there is room for the decode to finish */
|
||||||
if (mfc_dec_output_available(ctx) || force_dequeue_output) {
|
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;
|
return -1;
|
||||||
if (mfc_dec_enqueue_output(ctx, buffer) < 0)
|
if (mfc_dec_enqueue_output(ctx, buffer) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -48,6 +48,8 @@
|
||||||
#ifndef VIDEO_EXYNOS4_MFC_V4L2_INCLUDE_MFC_DECODER_H
|
#ifndef VIDEO_EXYNOS4_MFC_V4L2_INCLUDE_MFC_DECODER_H
|
||||||
#define 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_buffer;
|
||||||
struct mfc_dec_context;
|
struct mfc_dec_context;
|
||||||
|
|
||||||
|
@ -157,7 +159,7 @@ int mfc_dec_output_available(struct mfc_dec_context*);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Enqueue frame containing compressed data */
|
/* 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.
|
* 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
|
* when mfc_dec_output_available() is not true, subsequent video
|
||||||
* frames may not decode correctly.
|
* 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);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue