diff options
author | Wim Taymans <wtaymans@redhat.com> | 2014-01-10 17:18:53 +0100 |
---|---|---|
committer | Wim Taymans <wtaymans@redhat.com> | 2014-01-10 17:28:22 +0100 |
commit | 81cef109e20cbce285bacaf673597aef57fc30f3 (patch) | |
tree | 1e741a751fa2292c8f016840343e581d979ef1d5 | |
parent | 1e65aac1a44c4e4abc513221dcbb79b5d8d17962 (diff) |
avviddec: release buffers when not direct rendering
New libav will not call the release_buffer callback anymore when
avcodec_default_get_buffer() is called from get_buffer. Releasing of the
memory in a picture should now be done by registering a callback to the
avbuffer objects in the picture. There is some compatibility code to
wrap the memory we provide in get_buffer in avbuffer with a callback to
release_buffer but that is not done when avcodec_default_get_buffer()
is called.
Work around this by adding a dummy avbuffer object to the picture that
will release the frame.
Fixes https://bugzilla.gnome.org/show_bug.cgi?id=721077
-rw-r--r-- | ext/libav/gstavviddec.c | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/ext/libav/gstavviddec.c b/ext/libav/gstavviddec.c index 63c742e..9f9fca5 100644 --- a/ext/libav/gstavviddec.c +++ b/ext/libav/gstavviddec.c @@ -524,6 +524,7 @@ open_failed: typedef struct { + GstFFMpegVidDec *ffmpegdec; GstVideoCodecFrame *frame; gboolean mapped; GstVideoFrame vframe; @@ -531,13 +532,17 @@ typedef struct } GstFFMpegVidDecVideoFrame; static GstFFMpegVidDecVideoFrame * -gst_ffmpegviddec_video_frame_new (GstVideoCodecFrame * frame) +gst_ffmpegviddec_video_frame_new (GstFFMpegVidDec * ffmpegdec, + GstVideoCodecFrame * frame) { GstFFMpegVidDecVideoFrame *dframe; dframe = g_slice_new0 (GstFFMpegVidDecVideoFrame); + dframe->ffmpegdec = ffmpegdec; dframe->frame = frame; + GST_DEBUG_OBJECT (ffmpegdec, "new video frame %p", dframe); + return dframe; } @@ -545,6 +550,8 @@ static void gst_ffmpegviddec_video_frame_free (GstFFMpegVidDec * ffmpegdec, GstFFMpegVidDecVideoFrame * frame) { + GST_DEBUG_OBJECT (ffmpegdec, "free video frame %p", frame); + if (frame->mapped) gst_video_frame_unmap (&frame->vframe); gst_video_decoder_release_frame (GST_VIDEO_DECODER (ffmpegdec), frame->frame); @@ -552,6 +559,14 @@ gst_ffmpegviddec_video_frame_free (GstFFMpegVidDec * ffmpegdec, g_slice_free (GstFFMpegVidDecVideoFrame, frame); } +static void +dummy_free_buffer (void *opaque, uint8_t * data) +{ + GstFFMpegVidDecVideoFrame *frame = opaque; + + gst_ffmpegviddec_video_frame_free (frame->ffmpegdec, frame); +} + /* 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 @@ -590,7 +605,8 @@ gst_ffmpegviddec_get_buffer (AVCodecContext * context, AVFrame * picture) goto duplicate_frame; /* GstFFMpegVidDecVideoFrame receives the frame ref */ - picture->opaque = dframe = gst_ffmpegviddec_video_frame_new (frame); + picture->opaque = dframe = + gst_ffmpegviddec_video_frame_new (ffmpegdec, frame); GST_DEBUG_OBJECT (ffmpegdec, "storing opaque %p", dframe); @@ -694,11 +710,19 @@ invalid_frame: fallback: { int c; + gboolean first = TRUE; int ret = avcodec_default_get_buffer (context, picture); - for (c = 0; c < AV_NUM_DATA_POINTERS; c++) + for (c = 0; c < AV_NUM_DATA_POINTERS; c++) { ffmpegdec->stride[c] = picture->linesize[c]; + if (picture->buf[c] == NULL && first) { + picture->buf[c] = + av_buffer_create (NULL, 0, dummy_free_buffer, dframe, 0); + first = FALSE; + } + } + return ret; } duplicate_frame: @@ -1669,8 +1693,8 @@ gst_ffmpegviddec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query) avcodec_align_dimensions2 (ffmpegdec->context, &width, &height, linesize_align); edge = - ffmpegdec->context-> - flags & CODEC_FLAG_EMU_EDGE ? 0 : avcodec_get_edge_width (); + ffmpegdec-> + context->flags & CODEC_FLAG_EMU_EDGE ? 0 : avcodec_get_edge_width (); /* increase the size for the padding */ width += edge << 1; height += edge << 1; |