mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2025-12-12 01:40:04 +01:00
avcodec/mpegpicture: Store linesize in ScratchpadContext
The mpegvideo-based codecs currently require the linesize to be constant (except when the frame dimensions change); one reason for this is that certain scratch buffers whose size depend on linesize are only allocated once and are presumed to be correctly sized if the pointers are != NULL. This commit changes this by storing the actual linesize these buffers belong to and reallocating the buffers if it does not suffice. This is not enough to actually support changing linesizes, but it is a start. And it is a prerequisite for the next patch. Also don't emit an error message in case the source ctx's edge_emu_buffer is unset in ff_mpeg_update_thread_context(). It need not be an error at all; e.g. it is a perfectly normal state in case a hardware acceleration is used as the scratch buffers are not allocated in this case (it is easy to run into this issue with MPEG-4) or if the src context was not initialized at all (e.g. because the first packet contained garbage). Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
This commit is contained in:
@@ -89,12 +89,16 @@ int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me,
|
|||||||
ScratchpadContext *sc, int linesize)
|
ScratchpadContext *sc, int linesize)
|
||||||
{
|
{
|
||||||
# define EMU_EDGE_HEIGHT (4 * 70)
|
# define EMU_EDGE_HEIGHT (4 * 70)
|
||||||
int alloc_size = FFALIGN(FFABS(linesize) + 64, 32);
|
int linesizeabs = FFABS(linesize);
|
||||||
|
int alloc_size = FFALIGN(linesizeabs + 64, 32);
|
||||||
|
|
||||||
|
if (linesizeabs <= sc->linesize)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (avctx->hwaccel)
|
if (avctx->hwaccel)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (linesize < 24) {
|
if (linesizeabs < 24) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "Image too small, temporary buffers cannot function\n");
|
av_log(avctx, AV_LOG_ERROR, "Image too small, temporary buffers cannot function\n");
|
||||||
return AVERROR_PATCHWELCOME;
|
return AVERROR_PATCHWELCOME;
|
||||||
}
|
}
|
||||||
@@ -102,6 +106,9 @@ int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me,
|
|||||||
if (av_image_check_size2(alloc_size, EMU_EDGE_HEIGHT, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx) < 0)
|
if (av_image_check_size2(alloc_size, EMU_EDGE_HEIGHT, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx) < 0)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
av_freep(&sc->edge_emu_buffer);
|
||||||
|
av_freep(&me->scratchpad);
|
||||||
|
|
||||||
// edge emu needs blocksize + filter length - 1
|
// edge emu needs blocksize + filter length - 1
|
||||||
// (= 17x17 for halfpel / 21x21 for H.264)
|
// (= 17x17 for halfpel / 21x21 for H.264)
|
||||||
// VC-1 computes luma and chroma simultaneously and needs 19X19 + 9x9
|
// VC-1 computes luma and chroma simultaneously and needs 19X19 + 9x9
|
||||||
@@ -110,9 +117,11 @@ int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me,
|
|||||||
// we also use this buffer for encoding in encode_mb_internal() needig an additional 32 lines
|
// we also use this buffer for encoding in encode_mb_internal() needig an additional 32 lines
|
||||||
if (!FF_ALLOCZ_TYPED_ARRAY(sc->edge_emu_buffer, alloc_size * EMU_EDGE_HEIGHT) ||
|
if (!FF_ALLOCZ_TYPED_ARRAY(sc->edge_emu_buffer, alloc_size * EMU_EDGE_HEIGHT) ||
|
||||||
!FF_ALLOCZ_TYPED_ARRAY(me->scratchpad, alloc_size * 4 * 16 * 2)) {
|
!FF_ALLOCZ_TYPED_ARRAY(me->scratchpad, alloc_size * 4 * 16 * 2)) {
|
||||||
|
sc->linesize = 0;
|
||||||
av_freep(&sc->edge_emu_buffer);
|
av_freep(&sc->edge_emu_buffer);
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
}
|
}
|
||||||
|
sc->linesize = linesizeabs;
|
||||||
|
|
||||||
me->temp = me->scratchpad;
|
me->temp = me->scratchpad;
|
||||||
sc->rd_scratchpad = me->scratchpad;
|
sc->rd_scratchpad = me->scratchpad;
|
||||||
@@ -149,9 +158,9 @@ static int handle_pic_linesizes(AVCodecContext *avctx, Picture *pic,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sc->edge_emu_buffer &&
|
ret = ff_mpeg_framesize_alloc(avctx, me, sc,
|
||||||
(ret = ff_mpeg_framesize_alloc(avctx, me, sc,
|
pic->f->linesize[0]);
|
||||||
pic->f->linesize[0])) < 0) {
|
if (ret < 0) {
|
||||||
av_log(avctx, AV_LOG_ERROR,
|
av_log(avctx, AV_LOG_ERROR,
|
||||||
"get_buffer() failed to allocate context scratch buffers.\n");
|
"get_buffer() failed to allocate context scratch buffers.\n");
|
||||||
ff_mpeg_unref_picture(pic);
|
ff_mpeg_unref_picture(pic);
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ typedef struct ScratchpadContext {
|
|||||||
uint8_t *rd_scratchpad; ///< scratchpad for rate distortion mb decision
|
uint8_t *rd_scratchpad; ///< scratchpad for rate distortion mb decision
|
||||||
uint8_t *obmc_scratchpad;
|
uint8_t *obmc_scratchpad;
|
||||||
uint8_t *b_scratchpad; ///< scratchpad used for writing into write only buffers
|
uint8_t *b_scratchpad; ///< scratchpad used for writing into write only buffers
|
||||||
|
int linesize; ///< linesize that the buffers in this context have been allocated for
|
||||||
} ScratchpadContext;
|
} ScratchpadContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -443,6 +443,7 @@ static void free_duplicate_context(MpegEncContext *s)
|
|||||||
s->sc.rd_scratchpad =
|
s->sc.rd_scratchpad =
|
||||||
s->sc.b_scratchpad =
|
s->sc.b_scratchpad =
|
||||||
s->sc.obmc_scratchpad = NULL;
|
s->sc.obmc_scratchpad = NULL;
|
||||||
|
s->sc.linesize = 0;
|
||||||
|
|
||||||
av_freep(&s->dct_error_sum);
|
av_freep(&s->dct_error_sum);
|
||||||
av_freep(&s->me.map);
|
av_freep(&s->me.map);
|
||||||
@@ -464,12 +465,9 @@ static void free_duplicate_contexts(MpegEncContext *s)
|
|||||||
static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src)
|
static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src)
|
||||||
{
|
{
|
||||||
#define COPY(a) bak->a = src->a
|
#define COPY(a) bak->a = src->a
|
||||||
COPY(sc.edge_emu_buffer);
|
COPY(sc);
|
||||||
COPY(me.scratchpad);
|
COPY(me.scratchpad);
|
||||||
COPY(me.temp);
|
COPY(me.temp);
|
||||||
COPY(sc.rd_scratchpad);
|
|
||||||
COPY(sc.b_scratchpad);
|
|
||||||
COPY(sc.obmc_scratchpad);
|
|
||||||
COPY(me.map);
|
COPY(me.map);
|
||||||
COPY(me.score_map);
|
COPY(me.score_map);
|
||||||
COPY(blocks);
|
COPY(blocks);
|
||||||
@@ -503,9 +501,9 @@ int ff_update_duplicate_context(MpegEncContext *dst, const MpegEncContext *src)
|
|||||||
// exchange uv
|
// exchange uv
|
||||||
FFSWAP(void *, dst->pblocks[4], dst->pblocks[5]);
|
FFSWAP(void *, dst->pblocks[4], dst->pblocks[5]);
|
||||||
}
|
}
|
||||||
if (!dst->sc.edge_emu_buffer &&
|
ret = ff_mpeg_framesize_alloc(dst->avctx, &dst->me,
|
||||||
(ret = ff_mpeg_framesize_alloc(dst->avctx, &dst->me,
|
&dst->sc, dst->linesize);
|
||||||
&dst->sc, dst->linesize)) < 0) {
|
if (ret < 0) {
|
||||||
av_log(dst->avctx, AV_LOG_ERROR, "failed to allocate context "
|
av_log(dst->avctx, AV_LOG_ERROR, "failed to allocate context "
|
||||||
"scratch buffers.\n");
|
"scratch buffers.\n");
|
||||||
return ret;
|
return ret;
|
||||||
@@ -646,12 +644,9 @@ static void clear_context(MpegEncContext *s)
|
|||||||
s->ac_val[0] =
|
s->ac_val[0] =
|
||||||
s->ac_val[1] =
|
s->ac_val[1] =
|
||||||
s->ac_val[2] =NULL;
|
s->ac_val[2] =NULL;
|
||||||
s->sc.edge_emu_buffer = NULL;
|
|
||||||
s->me.scratchpad = NULL;
|
s->me.scratchpad = NULL;
|
||||||
s->me.temp =
|
s->me.temp = NULL;
|
||||||
s->sc.rd_scratchpad =
|
memset(&s->sc, 0, sizeof(s->sc));
|
||||||
s->sc.b_scratchpad =
|
|
||||||
s->sc.obmc_scratchpad = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
s->bitstream_buffer = NULL;
|
s->bitstream_buffer = NULL;
|
||||||
|
|||||||
@@ -167,17 +167,12 @@ do {\
|
|||||||
}
|
}
|
||||||
|
|
||||||
// linesize-dependent scratch buffer allocation
|
// linesize-dependent scratch buffer allocation
|
||||||
if (!s->sc.edge_emu_buffer)
|
ret = ff_mpeg_framesize_alloc(s->avctx, &s->me,
|
||||||
if (s1->linesize) {
|
&s->sc, s1->linesize);
|
||||||
if (ff_mpeg_framesize_alloc(s->avctx, &s->me,
|
if (ret < 0) {
|
||||||
&s->sc, s1->linesize) < 0) {
|
|
||||||
av_log(s->avctx, AV_LOG_ERROR, "Failed to allocate context "
|
av_log(s->avctx, AV_LOG_ERROR, "Failed to allocate context "
|
||||||
"scratch buffers.\n");
|
"scratch buffers.\n");
|
||||||
return AVERROR(ENOMEM);
|
return ret;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
av_log(s->avctx, AV_LOG_ERROR, "Context scratch buffers could not "
|
|
||||||
"be allocated due to unknown size.\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MPEG-2/interlacing info
|
// MPEG-2/interlacing info
|
||||||
|
|||||||
Reference in New Issue
Block a user