mirror of https://github.com/FFmpeg/FFmpeg.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
258 lines
7.8 KiB
258 lines
7.8 KiB
/* |
|
* Mpeg video formats-related picture management functions |
|
* |
|
* This file is part of FFmpeg. |
|
* |
|
* 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. |
|
* |
|
* 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 FFmpeg; if not, write to the Free Software |
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
*/ |
|
|
|
#include "libavutil/avassert.h" |
|
#include "libavutil/common.h" |
|
#include "libavutil/mem.h" |
|
#include "libavutil/pixdesc.h" |
|
#include "libavutil/imgutils.h" |
|
|
|
#include "avcodec.h" |
|
#include "mpegpicture.h" |
|
#include "refstruct.h" |
|
|
|
static void mpv_pic_reset(FFRefStructOpaque unused, void *obj) |
|
{ |
|
MPVPicture *pic = obj; |
|
|
|
av_frame_unref(pic->f); |
|
ff_thread_progress_reset(&pic->progress); |
|
|
|
ff_refstruct_unref(&pic->hwaccel_picture_private); |
|
|
|
ff_refstruct_unref(&pic->mbskip_table); |
|
ff_refstruct_unref(&pic->qscale_table_base); |
|
ff_refstruct_unref(&pic->mb_type_base); |
|
|
|
for (int i = 0; i < 2; i++) { |
|
ff_refstruct_unref(&pic->motion_val_base[i]); |
|
ff_refstruct_unref(&pic->ref_index[i]); |
|
|
|
pic->motion_val[i] = NULL; |
|
} |
|
|
|
pic->mb_type = NULL; |
|
pic->qscale_table = NULL; |
|
|
|
pic->mb_stride = |
|
pic->mb_width = |
|
pic->mb_height = 0; |
|
|
|
pic->dummy = 0; |
|
pic->field_picture = 0; |
|
pic->b_frame_score = 0; |
|
pic->reference = 0; |
|
pic->shared = 0; |
|
pic->display_picture_number = 0; |
|
pic->coded_picture_number = 0; |
|
} |
|
|
|
static int av_cold mpv_pic_init(FFRefStructOpaque opaque, void *obj) |
|
{ |
|
MPVPicture *pic = obj; |
|
int ret, init_progress = (uintptr_t)opaque.nc; |
|
|
|
ret = ff_thread_progress_init(&pic->progress, init_progress); |
|
if (ret < 0) |
|
return ret; |
|
|
|
pic->f = av_frame_alloc(); |
|
if (!pic->f) |
|
return AVERROR(ENOMEM); |
|
return 0; |
|
} |
|
|
|
static void av_cold mpv_pic_free(FFRefStructOpaque unused, void *obj) |
|
{ |
|
MPVPicture *pic = obj; |
|
|
|
ff_thread_progress_destroy(&pic->progress); |
|
av_frame_free(&pic->f); |
|
} |
|
|
|
av_cold FFRefStructPool *ff_mpv_alloc_pic_pool(int init_progress) |
|
{ |
|
return ff_refstruct_pool_alloc_ext(sizeof(MPVPicture), |
|
FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR, |
|
(void*)(uintptr_t)init_progress, |
|
mpv_pic_init, mpv_pic_reset, mpv_pic_free, NULL); |
|
} |
|
|
|
void ff_mpv_unref_picture(MPVWorkPicture *pic) |
|
{ |
|
ff_refstruct_unref(&pic->ptr); |
|
memset(pic, 0, sizeof(*pic)); |
|
} |
|
|
|
static void set_workpic_from_pic(MPVWorkPicture *wpic, const MPVPicture *pic) |
|
{ |
|
for (int i = 0; i < MPV_MAX_PLANES; i++) { |
|
wpic->data[i] = pic->f->data[i]; |
|
wpic->linesize[i] = pic->f->linesize[i]; |
|
} |
|
wpic->qscale_table = pic->qscale_table; |
|
wpic->mb_type = pic->mb_type; |
|
wpic->mbskip_table = pic->mbskip_table; |
|
|
|
for (int i = 0; i < 2; i++) { |
|
wpic->motion_val[i] = pic->motion_val[i]; |
|
wpic->ref_index[i] = pic->ref_index[i]; |
|
} |
|
wpic->reference = pic->reference; |
|
} |
|
|
|
void ff_mpv_replace_picture(MPVWorkPicture *dst, const MPVWorkPicture *src) |
|
{ |
|
av_assert1(dst != src); |
|
ff_refstruct_replace(&dst->ptr, src->ptr); |
|
memcpy(dst, src, sizeof(*dst)); |
|
} |
|
|
|
void ff_mpv_workpic_from_pic(MPVWorkPicture *wpic, MPVPicture *pic) |
|
{ |
|
ff_refstruct_replace(&wpic->ptr, pic); |
|
if (!pic) { |
|
memset(wpic, 0, sizeof(*wpic)); |
|
return; |
|
} |
|
set_workpic_from_pic(wpic, pic); |
|
} |
|
|
|
int ff_mpv_framesize_alloc(AVCodecContext *avctx, |
|
ScratchpadContext *sc, int linesize) |
|
{ |
|
# define EMU_EDGE_HEIGHT (4 * 70) |
|
int linesizeabs = FFABS(linesize); |
|
int alloc_size = FFALIGN(linesizeabs + 64, 32); |
|
|
|
if (linesizeabs <= sc->linesize) |
|
return 0; |
|
|
|
if (avctx->hwaccel) |
|
return 0; |
|
|
|
if (linesizeabs < 24) { |
|
av_log(avctx, AV_LOG_ERROR, "Image too small, temporary buffers cannot function\n"); |
|
return AVERROR_PATCHWELCOME; |
|
} |
|
|
|
if (av_image_check_size2(alloc_size, EMU_EDGE_HEIGHT, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx) < 0) |
|
return AVERROR(ENOMEM); |
|
|
|
av_freep(&sc->edge_emu_buffer); |
|
av_freep(&sc->scratchpad_buf); |
|
|
|
// 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 |
|
// 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) || |
|
!FF_ALLOCZ_TYPED_ARRAY(sc->scratchpad_buf, alloc_size * 4 * 16 * 2)) { |
|
sc->linesize = 0; |
|
av_freep(&sc->edge_emu_buffer); |
|
return AVERROR(ENOMEM); |
|
} |
|
sc->linesize = linesizeabs; |
|
|
|
sc->obmc_scratchpad = sc->scratchpad_buf + 16; |
|
|
|
return 0; |
|
} |
|
|
|
int ff_mpv_pic_check_linesize(void *logctx, const AVFrame *f, |
|
ptrdiff_t *linesizep, ptrdiff_t *uvlinesizep) |
|
{ |
|
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(f->format) > 2 && |
|
f->linesize[1] != f->linesize[2]) { |
|
av_log(logctx, AV_LOG_ERROR, "uv stride mismatch unsupported\n"); |
|
return AVERROR_PATCHWELCOME; |
|
} |
|
*linesizep = f->linesize[0]; |
|
*uvlinesizep = f->linesize[1]; |
|
|
|
return 0; |
|
} |
|
|
|
static int alloc_picture_tables(BufferPoolContext *pools, MPVPicture *pic, |
|
int mb_height) |
|
{ |
|
#define GET_BUFFER(name, buf_suffix, idx_suffix) do { \ |
|
pic->name ## buf_suffix idx_suffix = ff_refstruct_pool_get(pools->name ## _pool); \ |
|
if (!pic->name ## buf_suffix idx_suffix) \ |
|
return AVERROR(ENOMEM); \ |
|
} while (0) |
|
GET_BUFFER(qscale_table, _base,); |
|
GET_BUFFER(mb_type, _base,); |
|
if (pools->motion_val_pool) { |
|
if (pools->mbskip_table_pool) |
|
GET_BUFFER(mbskip_table,,); |
|
for (int i = 0; i < 2; i++) { |
|
GET_BUFFER(ref_index,, [i]); |
|
GET_BUFFER(motion_val, _base, [i]); |
|
pic->motion_val[i] = pic->motion_val_base[i] + 4; |
|
} |
|
} |
|
#undef GET_BUFFER |
|
|
|
pic->mb_width = pools->alloc_mb_width; |
|
pic->mb_height = mb_height; |
|
pic->mb_stride = pools->alloc_mb_stride; |
|
|
|
pic->qscale_table = pic->qscale_table_base + 2 * pic->mb_stride + 1; |
|
pic->mb_type = pic->mb_type_base + 2 * pic->mb_stride + 1; |
|
|
|
return 0; |
|
} |
|
|
|
int ff_mpv_alloc_pic_accessories(AVCodecContext *avctx, MPVWorkPicture *wpic, |
|
ScratchpadContext *sc, |
|
BufferPoolContext *pools, int mb_height) |
|
{ |
|
MPVPicture *pic = wpic->ptr; |
|
int ret; |
|
|
|
ret = ff_mpv_framesize_alloc(avctx, sc, pic->f->linesize[0]); |
|
if (ret < 0) |
|
goto fail; |
|
|
|
ret = alloc_picture_tables(pools, pic, mb_height); |
|
if (ret < 0) |
|
goto fail; |
|
|
|
set_workpic_from_pic(wpic, pic); |
|
|
|
return 0; |
|
fail: |
|
av_log(avctx, AV_LOG_ERROR, "Error allocating picture accessories.\n"); |
|
return ret; |
|
}
|
|
|