diff --git a/libavcodec/mpegpicture.c b/libavcodec/mpegpicture.c index f605338845..840aa23c38 100644 --- a/libavcodec/mpegpicture.c +++ b/libavcodec/mpegpicture.c @@ -91,40 +91,27 @@ int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me, return 0; } -/** - * Check the pic's linesize and allocate linesize dependent scratch buffers - */ -static int handle_pic_linesizes(AVCodecContext *avctx, Picture *pic, - MotionEstContext *me, ScratchpadContext *sc, - int linesize, int uvlinesize) +int ff_mpv_pic_check_linesize(void *logctx, const AVFrame *f, + ptrdiff_t *linesizep, ptrdiff_t *uvlinesizep) { - int ret; + ptrdiff_t linesize = *linesizep, uvlinesize = *uvlinesizep; - if ((linesize && linesize != pic->f->linesize[0]) || - (uvlinesize && uvlinesize != pic->f->linesize[1])) { - av_log(avctx, AV_LOG_ERROR, "Stride change unsupported: " - "linesize=%d/%d uvlinesize=%d/%d)\n", - linesize, pic->f->linesize[0], - uvlinesize, pic->f->linesize[1]); - ff_mpeg_unref_picture(pic); + if ((linesize && linesize != f->linesize[0]) || + (uvlinesize && uvlinesize != f->linesize[1])) { + av_log(logctx, AV_LOG_ERROR, "Stride change unsupported: " + "linesize=%"PTRDIFF_SPECIFIER"/%d uvlinesize=%"PTRDIFF_SPECIFIER"/%d)\n", + linesize, f->linesize[0], + uvlinesize, f->linesize[1]); return AVERROR_PATCHWELCOME; } - if (av_pix_fmt_count_planes(pic->f->format) > 2 && - pic->f->linesize[1] != pic->f->linesize[2]) { - av_log(avctx, AV_LOG_ERROR, "uv stride mismatch unsupported\n"); - ff_mpeg_unref_picture(pic); + if (av_pix_fmt_count_planes(f->format) > 2 && + f->linesize[1] != f->linesize[2]) { + av_log(logctx, AV_LOG_ERROR, "uv stride mismatch unsupported\n"); return AVERROR_PATCHWELCOME; } - - ret = ff_mpeg_framesize_alloc(avctx, me, sc, - pic->f->linesize[0]); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, - "get_buffer() failed to allocate context scratch buffers.\n"); - ff_mpeg_unref_picture(pic); - return ret; - } + *linesizep = f->linesize[0]; + *uvlinesizep = f->linesize[1]; return 0; } @@ -156,28 +143,22 @@ static int alloc_picture_tables(BufferPoolContext *pools, Picture *pic, return 0; } -/** - * Allocate a Picture. - * The pixels are allocated/set by calling get_buffer() if shared = 0 - */ -int ff_alloc_picture(AVCodecContext *avctx, Picture *pic, MotionEstContext *me, - ScratchpadContext *sc, BufferPoolContext *pools, - int mb_height, ptrdiff_t *linesize, ptrdiff_t *uvlinesize) +int ff_mpv_alloc_pic_accessories(AVCodecContext *avctx, Picture *pic, + MotionEstContext *me, ScratchpadContext *sc, + BufferPoolContext *pools, int mb_height) { int ret; - if (handle_pic_linesizes(avctx, pic, me, sc, - *linesize, *uvlinesize) < 0) - return -1; - - *linesize = pic->f->linesize[0]; - *uvlinesize = pic->f->linesize[1]; - for (int i = 0; i < MPV_MAX_PLANES; i++) { pic->data[i] = pic->f->data[i]; pic->linesize[i] = pic->f->linesize[i]; } + ret = ff_mpeg_framesize_alloc(avctx, me, sc, + pic->f->linesize[0]); + if (ret < 0) + goto fail; + ret = alloc_picture_tables(pools, pic, mb_height); if (ret < 0) goto fail; @@ -192,9 +173,8 @@ int ff_alloc_picture(AVCodecContext *avctx, Picture *pic, MotionEstContext *me, return 0; fail: - av_log(avctx, AV_LOG_ERROR, "Error allocating a picture.\n"); - ff_mpeg_unref_picture(pic); - return AVERROR(ENOMEM); + av_log(avctx, AV_LOG_ERROR, "Error allocating picture accessories.\n"); + return ret; } /** diff --git a/libavcodec/mpegpicture.h b/libavcodec/mpegpicture.h index 814f71213e..6589b38262 100644 --- a/libavcodec/mpegpicture.h +++ b/libavcodec/mpegpicture.h @@ -96,9 +96,18 @@ typedef struct Picture { /** * Allocate a Picture's accessories, but not the AVFrame's buffer itself. */ -int ff_alloc_picture(AVCodecContext *avctx, Picture *pic, MotionEstContext *me, - ScratchpadContext *sc, BufferPoolContext *pools, - int mb_height, ptrdiff_t *linesize, ptrdiff_t *uvlinesize); +int ff_mpv_alloc_pic_accessories(AVCodecContext *avctx, Picture *pic, + MotionEstContext *me, ScratchpadContext *sc, + BufferPoolContext *pools, int mb_height); + +/** + * Check that the linesizes of an AVFrame are consistent with the requirements + * of mpegvideo. + * FIXME: There should be no need for this function. mpegvideo should be made + * to work with changing linesizes. + */ +int ff_mpv_pic_check_linesize(void *logctx, const struct AVFrame *f, + ptrdiff_t *linesizep, ptrdiff_t *uvlinesizep); int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me, ScratchpadContext *sc, int linesize); diff --git a/libavcodec/mpegvideo_dec.c b/libavcodec/mpegvideo_dec.c index 570a422b6f..663d97e60f 100644 --- a/libavcodec/mpegvideo_dec.c +++ b/libavcodec/mpegvideo_dec.c @@ -259,6 +259,10 @@ static int alloc_picture(MpegEncContext *s, Picture **picp, int reference) if (ret < 0) goto fail; + ret = ff_mpv_pic_check_linesize(avctx, pic->f, &s->linesize, &s->uvlinesize); + if (ret < 0) + goto fail; + ret = ff_hwaccel_frame_priv_alloc(avctx, &pic->hwaccel_picture_private); if (ret < 0) goto fail; @@ -267,8 +271,8 @@ static int alloc_picture(MpegEncContext *s, Picture **picp, int reference) av_assert1(s->mb_height == s->buffer_pools.alloc_mb_height || FFALIGN(s->mb_height, 2) == s->buffer_pools.alloc_mb_height); av_assert1(s->mb_stride == s->buffer_pools.alloc_mb_stride); - ret = ff_alloc_picture(s->avctx, pic, &s->me, &s->sc, &s->buffer_pools, - s->mb_height, &s->linesize, &s->uvlinesize); + ret = ff_mpv_alloc_pic_accessories(s->avctx, pic, &s->me, &s->sc, + &s->buffer_pools, s->mb_height); if (ret < 0) goto fail; *picp = pic; diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index d9e30df904..0b3eef646c 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -1103,6 +1103,10 @@ static int alloc_picture(MpegEncContext *s, Picture *pic) if (ret < 0) return ret; + ret = ff_mpv_pic_check_linesize(avctx, pic->f, &s->linesize, &s->uvlinesize); + if (ret < 0) + return ret; + for (int i = 0; pic->f->data[i]; i++) { int offset = (EDGE_WIDTH >> (i ? s->chroma_y_shift : 0)) * pic->f->linesize[i] + @@ -1112,11 +1116,7 @@ static int alloc_picture(MpegEncContext *s, Picture *pic) pic->f->width = avctx->width; pic->f->height = avctx->height; - av_assert1(s->mb_width == s->buffer_pools.alloc_mb_width); - av_assert1(s->mb_height == s->buffer_pools.alloc_mb_height); - av_assert1(s->mb_stride == s->buffer_pools.alloc_mb_stride); - return ff_alloc_picture(s->avctx, pic, &s->me, &s->sc, &s->buffer_pools, - s->mb_height, &s->linesize, &s->uvlinesize); + return 0; } static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) @@ -1188,7 +1188,7 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) } else { ret = alloc_picture(s, pic); if (ret < 0) - return ret; + goto fail; ret = av_frame_copy_props(pic->f, pic_arg); if (ret < 0) { ff_mpeg_unref_picture(pic); @@ -1258,6 +1258,9 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) s->input_picture[encoding_delay] = pic; return 0; +fail: + ff_mpeg_unref_picture(pic); + return ret; } static int skip_check(MpegEncContext *s, const Picture *p, const Picture *ref) @@ -1600,45 +1603,37 @@ no_output_pic: s->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_B ? 3 : 0; - if ((ret = av_frame_ref(s->new_pic, - s->reordered_input_picture[0]->f))) - goto fail; - if (s->reordered_input_picture[0]->shared || s->avctx->rc_buffer_size) { // input is a shared pix, so we can't modify it -> allocate a new // one & ensure that the shared one is reuseable - - Picture *pic; - int i = ff_find_unused_picture(s->avctx, s->picture, 0); - if (i < 0) - return i; - pic = &s->picture[i]; - - pic->reference = s->reordered_input_picture[0]->reference; - ret = alloc_picture(s, pic); + av_frame_move_ref(s->new_pic, s->reordered_input_picture[0]->f); + ret = alloc_picture(s, s->reordered_input_picture[0]); if (ret < 0) goto fail; - ret = av_frame_copy_props(pic->f, s->reordered_input_picture[0]->f); - if (ret < 0) { - ff_mpeg_unref_picture(pic); + ret = av_frame_copy_props(s->reordered_input_picture[0]->f, s->new_pic); + if (ret < 0) goto fail; - } - pic->coded_picture_number = s->reordered_input_picture[0]->coded_picture_number; - pic->display_picture_number = s->reordered_input_picture[0]->display_picture_number; - - /* mark us unused / free shared pic */ - ff_mpeg_unref_picture(s->reordered_input_picture[0]); - - s->cur_pic_ptr = pic; } else { // input is not a shared pix -> reuse buffer for current_pix - s->cur_pic_ptr = s->reordered_input_picture[0]; + ret = av_frame_ref(s->new_pic, s->reordered_input_picture[0]->f); + if (ret < 0) + goto fail; for (int i = 0; i < MPV_MAX_PLANES; i++) { if (s->new_pic->data[i]) s->new_pic->data[i] += INPLACE_OFFSET; } } + s->cur_pic_ptr = s->reordered_input_picture[0]; + av_assert1(s->mb_width == s->buffer_pools.alloc_mb_width); + av_assert1(s->mb_height == s->buffer_pools.alloc_mb_height); + av_assert1(s->mb_stride == s->buffer_pools.alloc_mb_stride); + ret = ff_mpv_alloc_pic_accessories(s->avctx, s->cur_pic_ptr, &s->me, + &s->sc, &s->buffer_pools, s->mb_height); + if (ret < 0) { + ff_mpeg_unref_picture(s->cur_pic_ptr); + return ret; + } s->picture_number = s->cur_pic_ptr->display_picture_number; }