diff options
author | Janne Grunau <janne-libav@jannau.net> | 2012-11-25 22:42:07 +0100 |
---|---|---|
committer | Janne Grunau <janne-libav@jannau.net> | 2012-12-18 19:48:30 +0100 |
commit | f1d8763a02b5fce9a7d9789e049d74a45b15e1e8 (patch) | |
tree | c319ee271c465de1c768fb61d6f51bea0c33d465 /libavcodec/mpegvideo.c | |
parent | ed2d7d5868a4a5d914f1e5488d63ea696a3b2937 (diff) | |
download | ffmpeg-f1d8763a02b5fce9a7d9789e049d74a45b15e1e8.tar.gz |
mpegvideo: allocate scratch buffers after linesize is known
Since we can't know which stride a custom get_buffer() implementation is
going to use we have to allocate this scratch buffers after the linesize
is known. It was pretty safe for 8 bit per pixel pixel formats since we
always allocated memory for up to 16 bits per pixel. It broke hoever
with cmdutis.c's alloc_buffer() and high pixel bit depth since it
allocated larger edges than mpegvideo expected.
Fixes fuzzed sample nasa-8s2.ts_s244342.
Diffstat (limited to 'libavcodec/mpegvideo.c')
-rw-r--r-- | libavcodec/mpegvideo.c | 76 |
1 files changed, 61 insertions, 15 deletions
diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 773c9e258b..8cd8df8d1f 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -235,12 +235,35 @@ static void free_frame_buffer(MpegEncContext *s, Picture *pic) av_freep(&pic->f.hwaccel_picture_private); } +int ff_mpv_frame_size_alloc(MpegEncContext *s, int linesize) +{ + int alloc_size = FFALIGN(FFABS(linesize) + 32, 32); + + // edge emu needs blocksize + filter length - 1 + // (= 17x17 for halfpel / 21x21 for h264) + // linesize * interlaced * MBsize + FF_ALLOCZ_OR_GOTO(s->avctx, s->edge_emu_buffer, alloc_size * 2 * 21, + fail); + + FF_ALLOCZ_OR_GOTO(s->avctx, s->me.scratchpad, alloc_size * 2 * 16 * 2, + fail) + s->me.temp = s->me.scratchpad; + s->rd_scratchpad = s->me.scratchpad; + s->b_scratchpad = s->me.scratchpad; + s->obmc_scratchpad = s->me.scratchpad + 16; + + return 0; +fail: + av_freep(&s->edge_emu_buffer); + return AVERROR(ENOMEM); +} + /** * Allocate a frame buffer */ static int alloc_frame_buffer(MpegEncContext *s, Picture *pic) { - int r; + int r, ret; if (s->avctx->hwaccel) { assert(!pic->f.hwaccel_picture_private); @@ -282,6 +305,14 @@ static int alloc_frame_buffer(MpegEncContext *s, Picture *pic) return -1; } + if (!s->edge_emu_buffer && + (ret = ff_mpv_frame_size_alloc(s, pic->f.linesize[0])) < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "get_buffer() failed to allocate context scratch buffers.\n"); + free_frame_buffer(s, pic); + return ret; + } + return 0; } @@ -419,19 +450,13 @@ static int init_duplicate_context(MpegEncContext *s, MpegEncContext *base) int yc_size = y_size + 2 * c_size; int i; - // edge emu needs blocksize + filter length - 1 - // (= 17x17 for halfpel / 21x21 for h264) - FF_ALLOCZ_OR_GOTO(s->avctx, s->edge_emu_buffer, - (s->width + 64) * 2 * 21 * 2, fail); // (width + edge + align)*interlaced*MBsize*tolerance + s->edge_emu_buffer = + s->me.scratchpad = + s->me.temp = + s->rd_scratchpad = + s->b_scratchpad = + s->obmc_scratchpad = NULL; - // FIXME should be linesize instead of s->width * 2 - // but that is not known before get_buffer() - FF_ALLOCZ_OR_GOTO(s->avctx, s->me.scratchpad, - (s->width + 64) * 4 * 16 * 2 * sizeof(uint8_t), fail) - s->me.temp = s->me.scratchpad; - s->rd_scratchpad = s->me.scratchpad; - s->b_scratchpad = s->me.scratchpad; - s->obmc_scratchpad = s->me.scratchpad + 16; if (s->encoding) { FF_ALLOCZ_OR_GOTO(s->avctx, s->me.map, ME_MAP_SIZE * sizeof(uint32_t), fail) @@ -510,10 +535,10 @@ static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src) #undef COPY } -void ff_update_duplicate_context(MpegEncContext *dst, MpegEncContext *src) +int ff_update_duplicate_context(MpegEncContext *dst, MpegEncContext *src) { MpegEncContext bak; - int i; + int i, ret; // FIXME copy only needed parts // START_TIMER backup_duplicate_context(&bak, dst); @@ -522,8 +547,15 @@ void ff_update_duplicate_context(MpegEncContext *dst, MpegEncContext *src) for (i = 0; i < 12; i++) { dst->pblocks[i] = &dst->block[i]; } + if (!dst->edge_emu_buffer && + (ret = ff_mpv_frame_size_alloc(dst, dst->linesize)) < 0) { + av_log(dst->avctx, AV_LOG_ERROR, "failed to allocate context " + "scratch buffers.\n"); + return ret; + } // STOP_TIMER("update_duplicate_context") // about 10k cycles / 0.01 sec for 1000frames on 1ghz with 2 threads + return 0; } int ff_mpeg_update_thread_context(AVCodecContext *dst, @@ -608,6 +640,20 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst, FF_INPUT_BUFFER_PADDING_SIZE); } + // linesize dependend scratch buffer allocation + if (!s->edge_emu_buffer) + if (s1->linesize) { + if (ff_mpv_frame_size_alloc(s, s1->linesize) < 0) { + av_log(s->avctx, AV_LOG_ERROR, "Failed to allocate context " + "scratch buffers.\n"); + return AVERROR(ENOMEM); + } + } else { + av_log(s->avctx, AV_LOG_ERROR, "Context scratch buffers could not " + "be allocated due to unknown size.\n"); + return AVERROR_BUG; + } + // MPEG2/interlacing info memcpy(&s->progressive_sequence, &s1->progressive_sequence, (char *) &s1->rtp_mode - (char *) &s1->progressive_sequence); |