avcodec/mpegpicture: Split ff_alloc_picture() into check and alloc part

ff_alloc_picture() currently does two things: It checks the
consistency of the linesize (which should not be necessary, but is)
and it allocates certain buffers. (It does not actually allocate
the picture buffers, so its name is misleading.)
This commit splits it into two separate functions. The rationale
for this is that for the encoders, every picture needs its linesizes
checked, but not every picture needs these extra buffers.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
release/7.1
Andreas Rheinhardt 1 year ago
parent 042117da75
commit 89ca63cc9c
  1. 70
      libavcodec/mpegpicture.c
  2. 15
      libavcodec/mpegpicture.h
  3. 8
      libavcodec/mpegvideo_dec.c
  4. 57
      libavcodec/mpegvideo_enc.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;
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);
ptrdiff_t linesize = *linesizep, uvlinesize = *uvlinesizep;
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;
}
/**

@ -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);

@ -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;

@ -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;
}

Loading…
Cancel
Save