ffdec: refactor picture fill code

Make a method to hold the code to convert a GstVideoFrame to an AVFrame so that
we can reuse it in the non-direct rendering case.
This commit is contained in:
Wim Taymans 2011-07-29 13:40:30 +02:00
parent 3a8445fc80
commit 1dc718b195

View file

@ -889,45 +889,12 @@ open_failed:
}
}
/* called when ffmpeg wants us to allocate a buffer to write the decoded frame
* into. We try to give it memory from our pool */
static int
gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
static void
gst_ffmpegdec_fill_picture (GstFFMpegDec * ffmpegdec, GstVideoFrame * frame,
AVFrame * picture)
{
GstBuffer *buf = NULL;
GstFFMpegDec *ffmpegdec;
GstFlowReturn ret;
GstVideoFrame *frame;
guint i;
ffmpegdec = (GstFFMpegDec *) context->opaque;
GST_DEBUG_OBJECT (ffmpegdec, "getting buffer");
/* apply the last info we have seen to this picture, when we get the
* picture back from ffmpeg we can use this to correctly timestamp the output
* buffer */
picture->reordered_opaque = context->reordered_opaque;
/* make sure we don't free the buffer when it's not ours */
picture->opaque = NULL;
/* see if we need renegotiation */
if (G_UNLIKELY (!gst_ffmpegdec_video_negotiate (ffmpegdec, FALSE)))
goto negotiate_failed;
if (!ffmpegdec->current_dr)
goto no_dr;
/* alloc with aligned dimensions for ffmpeg */
GST_LOG_OBJECT (ffmpegdec, "doing alloc from pool");
ret = gst_buffer_pool_acquire_buffer (ffmpegdec->pool, &buf, NULL);
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto alloc_failed;
frame = g_slice_new (GstVideoFrame);
if (!gst_video_frame_map (frame, &ffmpegdec->pool_info, buf,
GST_MAP_READWRITE))
goto invalid_frame;
AVCodecContext *context = ffmpegdec->context;
/* setup data pointers and strides */
for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (frame); i++) {
@ -958,14 +925,56 @@ gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
picture->data[plane] += (vedge * picture->linesize[plane]) + hedge;
}
}
}
/* called when ffmpeg wants us to allocate a buffer to write the decoded frame
* into. We try to give it memory from our pool */
static int
gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
{
GstBuffer *buf = NULL;
GstFFMpegDec *ffmpegdec;
GstFlowReturn ret;
GstVideoFrame frame;
ffmpegdec = (GstFFMpegDec *) context->opaque;
GST_DEBUG_OBJECT (ffmpegdec, "getting buffer");
/* apply the last info we have seen to this picture, when we get the
* picture back from ffmpeg we can use this to correctly timestamp the output
* buffer */
picture->reordered_opaque = context->reordered_opaque;
/* make sure we don't free the buffer when it's not ours */
picture->opaque = NULL;
/* see if we need renegotiation */
if (G_UNLIKELY (!gst_ffmpegdec_video_negotiate (ffmpegdec, FALSE)))
goto negotiate_failed;
if (!ffmpegdec->current_dr)
goto no_dr;
/* alloc with aligned dimensions for ffmpeg */
GST_LOG_OBJECT (ffmpegdec, "doing alloc from pool");
ret = gst_buffer_pool_acquire_buffer (ffmpegdec->pool, &buf, NULL);
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto alloc_failed;
if (!gst_video_frame_map (&frame, &ffmpegdec->pool_info, buf,
GST_MAP_READWRITE))
goto invalid_frame;
gst_ffmpegdec_fill_picture (ffmpegdec, &frame, picture);
/* tell ffmpeg we own this buffer, tranfer the ref we have on the buffer to
* the opaque data. */
picture->type = FF_BUFFER_TYPE_USER;
picture->age = 256 * 256 * 256 * 64;
picture->opaque = frame;
picture->opaque = g_slice_dup (GstVideoFrame, &frame);
GST_LOG_OBJECT (ffmpegdec, "returned buffer %p in frame %p", buf, frame);
GST_LOG_OBJECT (ffmpegdec, "returned buffer %p in frame %p", buf,
picture->opaque);
return 0;
@ -991,7 +1000,6 @@ invalid_frame:
/* alloc default buffer when we can't get one from downstream */
GST_LOG_OBJECT (ffmpegdec, "failed to map frame, fallback alloc");
gst_buffer_unref (buf);
g_slice_free (GstVideoFrame, frame);
goto fallback;
}
fallback:
@ -1626,63 +1634,72 @@ static GstFlowReturn
get_output_buffer (GstFFMpegDec * ffmpegdec, GstBuffer ** outbuf)
{
GstFlowReturn ret;
GstVideoFrame *frame;
ret = GST_FLOW_OK;
*outbuf = NULL;
if (ffmpegdec->picture->opaque != NULL) {
GstVideoFrame *frame;
/* we allocated a picture already for ffmpeg to decode into, let's pick it
* up and use it now. */
frame = ffmpegdec->picture->opaque;
*outbuf = frame->buffer;
GST_LOG_OBJECT (ffmpegdec, "using opaque buffer %p", *outbuf);
GST_LOG_OBJECT (ffmpegdec, "using opaque buffer %p on frame %p", *outbuf,
frame);
gst_buffer_ref (*outbuf);
} else {
AVPicture pic, *outpic;
GstVideoFrame frame;
AVPicture *src, *dest;
AVFrame pic;
gint width, height;
guint8 *data;
gsize size;
GstBuffer *buf;
GST_LOG_OBJECT (ffmpegdec, "get output buffer");
if (G_UNLIKELY (!gst_ffmpegdec_video_negotiate (ffmpegdec, FALSE)))
goto negotiate_failed;
ret = gst_buffer_pool_acquire_buffer (ffmpegdec->pool, &buf, NULL);
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto alloc_failed;
if (!gst_video_frame_map (&frame, &ffmpegdec->pool_info, buf,
GST_MAP_READWRITE))
goto invalid_frame;
gst_ffmpegdec_fill_picture (ffmpegdec, &frame, &pic);
width = ffmpegdec->out_info.width;
height = ffmpegdec->out_info.height;
GST_LOG_OBJECT (ffmpegdec, "width %d/height %d", width, height);
src = (AVPicture *) ffmpegdec->picture;
dest = (AVPicture *) & pic;
ret = gst_buffer_pool_acquire_buffer (ffmpegdec->pool, outbuf, NULL);
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto alloc_failed;
GST_LOG_OBJECT (ffmpegdec, "copy width %d/height %d", width, height);
av_picture_copy (dest, src, ffmpegdec->context->pix_fmt, width, height);
/* original ffmpeg code does not handle odd sizes correctly.
* This patched up version does */
data = gst_buffer_map (*outbuf, &size, NULL, GST_MAP_WRITE);
gst_video_frame_unmap (&frame);
gst_ffmpeg_avpicture_fill (&pic, data,
ffmpegdec->context->pix_fmt, width, height);
outpic = (AVPicture *) ffmpegdec->picture;
GST_LOG_OBJECT (ffmpegdec, "linsize %d %d %d", outpic->linesize[0],
outpic->linesize[1], outpic->linesize[2]);
GST_LOG_OBJECT (ffmpegdec, "data %u %u %u", 0,
(guint) (outpic->data[1] - outpic->data[0]),
(guint) (outpic->data[2] - outpic->data[0]));
av_picture_copy (&pic, outpic, ffmpegdec->context->pix_fmt, width, height);
gst_buffer_unmap (*outbuf, data, size);
*outbuf = buf;
}
ffmpegdec->picture->reordered_opaque = -1;
return ret;
return GST_FLOW_OK;
/* special cases */
negotiate_failed:
{
GST_DEBUG_OBJECT (ffmpegdec, "negotiation failed");
return GST_FLOW_NOT_NEGOTIATED;
}
alloc_failed:
{
GST_DEBUG_OBJECT (ffmpegdec, "buffer alloc failed");
return ret;
}
invalid_frame:
{
GST_DEBUG_OBJECT (ffmpegdec, "could not map frame");
return GST_FLOW_ERROR;
}
}
static void