summaryrefslogtreecommitdiff
path: root/libavcodec/mpegpicture.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/mpegpicture.c')
-rw-r--r--libavcodec/mpegpicture.c97
1 files changed, 74 insertions, 23 deletions
diff --git a/libavcodec/mpegpicture.c b/libavcodec/mpegpicture.c
index 1d9544b482..c0e06900fe 100644
--- a/libavcodec/mpegpicture.c
+++ b/libavcodec/mpegpicture.c
@@ -1,20 +1,20 @@
/*
* Mpeg video formats-related picture management functions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,6 +22,7 @@
#include "libavutil/avassert.h"
#include "libavutil/common.h"
+#include "libavutil/pixdesc.h"
#include "avcodec.h"
#include "motion_est.h"
@@ -56,17 +57,26 @@ do {\
int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me,
ScratchpadContext *sc, int linesize)
{
- int alloc_size = FFALIGN(FFABS(linesize) + 32, 32);
+ int alloc_size = FFALIGN(FFABS(linesize) + 64, 32);
+
+ if (avctx->hwaccel)
+ return 0;
+
+ if (linesize < 24) {
+ av_log(avctx, AV_LOG_ERROR, "Image too small, temporary buffers cannot function\n");
+ return AVERROR_PATCHWELCOME;
+ }
// edge emu needs blocksize + filter length - 1
// (= 17x17 for halfpel / 21x21 for H.264)
// VC-1 computes luma and chroma simultaneously and needs 19X19 + 9x9
// at uvlinesize. It supports only YUV420 so 24x24 is enough
// linesize * interlaced * MBsize
- FF_ALLOCZ_OR_GOTO(avctx, sc->edge_emu_buffer, alloc_size * 2 * 24,
+ // we also use this buffer for encoding in encode_mb_internal() needig an additional 32 lines
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, sc->edge_emu_buffer, alloc_size, 4 * 70,
fail);
- FF_ALLOCZ_OR_GOTO(avctx, me->scratchpad, alloc_size * 2 * 16 * 3,
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, me->scratchpad, alloc_size, 4 * 16 * 2,
fail)
me->temp = me->scratchpad;
sc->rd_scratchpad = me->scratchpad;
@@ -138,15 +148,18 @@ static int alloc_frame_buffer(AVCodecContext *avctx, Picture *pic,
}
}
- if (linesize && (linesize != pic->f->linesize[0] ||
- uvlinesize != pic->f->linesize[1])) {
+ if ((linesize && linesize != pic->f->linesize[0]) ||
+ (uvlinesize && uvlinesize != pic->f->linesize[1])) {
av_log(avctx, AV_LOG_ERROR,
- "get_buffer() failed (stride changed)\n");
+ "get_buffer() failed (stride changed: linesize=%d/%d uvlinesize=%d/%d)\n",
+ linesize, pic->f->linesize[0],
+ uvlinesize, pic->f->linesize[1]);
ff_mpeg_unref_picture(avctx, pic);
return -1;
}
- if (pic->f->linesize[1] != pic->f->linesize[2]) {
+ if (av_pix_fmt_count_planes(pic->f->format) > 2 &&
+ pic->f->linesize[1] != pic->f->linesize[2]) {
av_log(avctx, AV_LOG_ERROR,
"get_buffer() failed (uv stride mismatch)\n");
ff_mpeg_unref_picture(avctx, pic);
@@ -165,8 +178,8 @@ static int alloc_frame_buffer(AVCodecContext *avctx, Picture *pic,
return 0;
}
-static int alloc_picture_tables(Picture *pic, int encoding, int out_format,
- int mb_stride, int mb_height, int b8_stride)
+static int alloc_picture_tables(AVCodecContext *avctx, Picture *pic, int encoding, int out_format,
+ int mb_stride, int mb_width, int mb_height, int b8_stride)
{
const int big_mb_num = mb_stride * (mb_height + 1) + 1;
const int mb_array_size = mb_stride * mb_height;
@@ -189,7 +202,11 @@ static int alloc_picture_tables(Picture *pic, int encoding, int out_format,
return AVERROR(ENOMEM);
}
- if (out_format == FMT_H263 || encoding) {
+ if (out_format == FMT_H263 || encoding ||
+#if FF_API_DEBUG_MV
+ avctx->debug_mv ||
+#endif
+ (avctx->flags2 & AV_CODEC_FLAG2_EXPORT_MVS)) {
int mv_size = 2 * (b8_array_size + 4) * sizeof(int16_t);
int ref_index_size = 4 * mb_array_size;
@@ -201,6 +218,9 @@ static int alloc_picture_tables(Picture *pic, int encoding, int out_format,
}
}
+ pic->alloc_mb_width = mb_width;
+ pic->alloc_mb_height = mb_height;
+
return 0;
}
@@ -211,16 +231,21 @@ static int alloc_picture_tables(Picture *pic, int encoding, int out_format,
int ff_alloc_picture(AVCodecContext *avctx, Picture *pic, MotionEstContext *me,
ScratchpadContext *sc, int shared, int encoding,
int chroma_x_shift, int chroma_y_shift, int out_format,
- int mb_stride, int mb_height, int b8_stride,
+ int mb_stride, int mb_width, int mb_height, int b8_stride,
ptrdiff_t *linesize, ptrdiff_t *uvlinesize)
{
int i, ret;
+ if (pic->qscale_table_buf)
+ if ( pic->alloc_mb_width != mb_width
+ || pic->alloc_mb_height != mb_height)
+ ff_free_picture_tables(pic);
+
if (shared) {
- assert(pic->f->data[0]);
+ av_assert0(pic->f->data[0]);
pic->shared = 1;
} else {
- assert(!pic->f->buf[0]);
+ av_assert0(!pic->f->buf[0]);
if (alloc_frame_buffer(avctx, pic, me, sc,
chroma_x_shift, chroma_y_shift,
*linesize, *uvlinesize) < 0)
@@ -231,8 +256,8 @@ int ff_alloc_picture(AVCodecContext *avctx, Picture *pic, MotionEstContext *me,
}
if (!pic->qscale_table_buf)
- ret = alloc_picture_tables(pic, encoding, out_format,
- mb_stride, mb_height, b8_stride);
+ ret = alloc_picture_tables(avctx, pic, encoding, out_format,
+ mb_stride, mb_width, mb_height, b8_stride);
else
ret = make_tables_writable(pic);
if (ret < 0)
@@ -268,6 +293,8 @@ fail:
*/
void ff_mpeg_unref_picture(AVCodecContext *avctx, Picture *pic)
{
+ int off = offsetof(Picture, mb_mean) + sizeof(pic->mb_mean);
+
pic->tf.f = pic->f;
/* WM Image / Screen codecs allocate internal buffers with different
* dimensions / colorspaces; ignore user-defined callbacks for these. */
@@ -282,6 +309,8 @@ void ff_mpeg_unref_picture(AVCodecContext *avctx, Picture *pic)
if (pic->needs_realloc)
ff_free_picture_tables(pic);
+
+ memset((uint8_t*)pic + off, 0, sizeof(*pic) - off);
}
int ff_update_picture_tables(Picture *dst, Picture *src)
@@ -323,6 +352,9 @@ do { \
dst->ref_index[i] = src->ref_index[i];
}
+ dst->alloc_mb_width = src->alloc_mb_width;
+ dst->alloc_mb_height = src->alloc_mb_height;
+
return 0;
}
@@ -345,8 +377,10 @@ int ff_mpeg_ref_picture(AVCodecContext *avctx, Picture *dst, Picture *src)
if (src->hwaccel_picture_private) {
dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf);
- if (!dst->hwaccel_priv_buf)
+ if (!dst->hwaccel_priv_buf) {
+ ret = AVERROR(ENOMEM);
goto fail;
+ }
dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data;
}
@@ -376,7 +410,7 @@ static inline int pic_is_unused(Picture *pic)
return 0;
}
-static int find_unused_picture(Picture *picture, int shared)
+static int find_unused_picture(AVCodecContext *avctx, Picture *picture, int shared)
{
int i;
@@ -392,12 +426,26 @@ static int find_unused_picture(Picture *picture, int shared)
}
}
- return AVERROR_INVALIDDATA;
+ av_log(avctx, AV_LOG_FATAL,
+ "Internal error, picture buffer overflow\n");
+ /* We could return -1, but the codec would crash trying to draw into a
+ * non-existing frame anyway. This is safer than waiting for a random crash.
+ * Also the return of this is never useful, an encoder must only allocate
+ * as much as allowed in the specification. This has no relationship to how
+ * much libavcodec could allocate (and MAX_PICTURE_COUNT is always large
+ * enough for such valid streams).
+ * Plus, a decoder has to check stream validity and remove frames if too
+ * many reference frames are around. Waiting for "OOM" is not correct at
+ * all. Similarly, missing reference frames have to be replaced by
+ * interpolated/MC frames, anything else is a bug in the codec ...
+ */
+ abort();
+ return -1;
}
int ff_find_unused_picture(AVCodecContext *avctx, Picture *picture, int shared)
{
- int ret = find_unused_picture(picture, shared);
+ int ret = find_unused_picture(avctx, picture, shared);
if (ret >= 0 && ret < MAX_PICTURE_COUNT) {
if (picture[ret].needs_realloc) {
@@ -413,6 +461,9 @@ void ff_free_picture_tables(Picture *pic)
{
int i;
+ pic->alloc_mb_width =
+ pic->alloc_mb_height = 0;
+
av_buffer_unref(&pic->mb_var_buf);
av_buffer_unref(&pic->mc_mb_var_buf);
av_buffer_unref(&pic->mb_mean_buf);