X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fmpegvideo.c;h=5de0719f831440795f100e0be564b1148bb2e604;hb=3749eede66c3774799766b1f246afae8a6ffc9bb;hp=dbb6ab9b393b731ddcce1bed3ca9ab434a81bcda;hpb=5ca7eb36b7353f9e6af05a5a952eead5f6d326dd;p=ffmpeg diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index dbb6ab9b393..5de0719f831 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -32,7 +32,8 @@ #include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/motion_vector.h" -#include "libavutil/timer.h" +#include "libavutil/video_enc_params.h" + #include "avcodec.h" #include "blockdsp.h" #include "h264chroma.h" @@ -347,9 +348,9 @@ av_cold void ff_mpv_idct_init(MpegEncContext *s) ff_init_scantable(s->idsp.idct_permutation, &s->intra_v_scantable, ff_alternate_vertical_scan); } -static int alloc_picture(MpegEncContext *s, Picture *pic, int shared) +static int alloc_picture(MpegEncContext *s, Picture *pic) { - return ff_alloc_picture(s->avctx, pic, &s->me, &s->sc, shared, 0, + return ff_alloc_picture(s->avctx, pic, &s->me, &s->sc, 0, 0, s->chroma_x_shift, s->chroma_y_shift, s->out_format, s->mb_stride, s->mb_width, s->mb_height, s->b8_stride, &s->linesize, &s->uvlinesize); @@ -365,33 +366,28 @@ static int init_duplicate_context(MpegEncContext *s) if (s->mb_height & 1) yc_size += 2*s->b8_stride + 2*s->mb_stride; - s->sc.edge_emu_buffer = - s->me.scratchpad = - s->me.temp = - s->sc.rd_scratchpad = - s->sc.b_scratchpad = - s->sc.obmc_scratchpad = NULL; - if (s->encoding) { - FF_ALLOCZ_OR_GOTO(s->avctx, s->me.map, - ME_MAP_SIZE * sizeof(uint32_t), fail) - FF_ALLOCZ_OR_GOTO(s->avctx, s->me.score_map, - ME_MAP_SIZE * sizeof(uint32_t), fail) + if (!FF_ALLOCZ_TYPED_ARRAY(s->me.map, ME_MAP_SIZE) || + !FF_ALLOCZ_TYPED_ARRAY(s->me.score_map, ME_MAP_SIZE)) + return AVERROR(ENOMEM); + if (s->noise_reduction) { - FF_ALLOCZ_OR_GOTO(s->avctx, s->dct_error_sum, - 2 * 64 * sizeof(int), fail) + if (!FF_ALLOCZ_TYPED_ARRAY(s->dct_error_sum, 2)) + return AVERROR(ENOMEM); } } - FF_ALLOCZ_OR_GOTO(s->avctx, s->blocks, 64 * 12 * 2 * sizeof(int16_t), fail) + if (!FF_ALLOCZ_TYPED_ARRAY(s->blocks, 2)) + return AVERROR(ENOMEM); s->block = s->blocks[0]; for (i = 0; i < 12; i++) { s->pblocks[i] = &s->block[i]; } - FF_ALLOCZ_OR_GOTO(s->avctx, s->block32, sizeof(*s->block32), fail) + if (!(s->block32 = av_mallocz(sizeof(*s->block32))) || + !(s->dpcm_macroblock = av_mallocz(sizeof(*s->dpcm_macroblock)))) + return AVERROR(ENOMEM); s->dpcm_direction = 0; - FF_ALLOCZ_OR_GOTO(s->avctx, s->dpcm_macroblock, sizeof(*s->dpcm_macroblock), fail) if (s->avctx->codec_tag == AV_RL32("VCR2")) { // exchange uv @@ -400,16 +396,43 @@ static int init_duplicate_context(MpegEncContext *s) if (s->out_format == FMT_H263) { /* ac values */ - FF_ALLOCZ_OR_GOTO(s->avctx, s->ac_val_base, - yc_size * sizeof(int16_t) * 16, fail); + if (!FF_ALLOCZ_TYPED_ARRAY(s->ac_val_base, yc_size)) + return AVERROR(ENOMEM); s->ac_val[0] = s->ac_val_base + s->b8_stride + 1; s->ac_val[1] = s->ac_val_base + y_size + s->mb_stride + 1; s->ac_val[2] = s->ac_val[1] + c_size; } return 0; -fail: - return -1; // free() through ff_mpv_common_end() +} + +/** + * Initialize an MpegEncContext's thread contexts. Presumes that + * slice_context_count is already set and that all the fields + * that are freed/reset in free_duplicate_context() are NULL. + */ +static int init_duplicate_contexts(MpegEncContext *s) +{ + int nb_slices = s->slice_context_count, ret; + + /* We initialize the copies before the original so that + * fields allocated in init_duplicate_context are NULL after + * copying. This prevents double-frees upon allocation error. */ + for (int i = 1; i < nb_slices; i++) { + s->thread_context[i] = av_memdup(s, sizeof(MpegEncContext)); + if (!s->thread_context[i]) + return AVERROR(ENOMEM); + if ((ret = init_duplicate_context(s->thread_context[i])) < 0) + return ret; + s->thread_context[i]->start_mb_y = + (s->mb_height * (i ) + nb_slices / 2) / nb_slices; + s->thread_context[i]->end_mb_y = + (s->mb_height * (i + 1) + nb_slices / 2) / nb_slices; + } + s->start_mb_y = 0; + s->end_mb_y = nb_slices > 1 ? (s->mb_height + nb_slices / 2) / nb_slices + : s->mb_height; + return init_duplicate_context(s); } static void free_duplicate_context(MpegEncContext *s) @@ -434,6 +457,15 @@ static void free_duplicate_context(MpegEncContext *s) s->block = NULL; } +static void free_duplicate_contexts(MpegEncContext *s) +{ + for (int i = 1; i < s->slice_context_count; i++) { + free_duplicate_context(s->thread_context[i]); + av_freep(&s->thread_context[i]); + } + free_duplicate_context(s); +} + static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src) { #define COPY(a) bak->a = src->a @@ -469,7 +501,6 @@ int ff_update_duplicate_context(MpegEncContext *dst, MpegEncContext *src) MpegEncContext bak; int i, ret; // FIXME copy only needed parts - // START_TIMER backup_duplicate_context(&bak, dst); memcpy(dst, src, sizeof(MpegEncContext)); backup_duplicate_context(dst, &bak); @@ -487,8 +518,6 @@ int ff_update_duplicate_context(MpegEncContext *dst, MpegEncContext *src) "scratch buffers.\n"); return ret; } - // STOP_TIMER("update_duplicate_context") - // about 10k cycles / 0.01 sec for 1000frames on 1ghz with 2 threads return 0; } @@ -526,7 +555,6 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst, } if (s->height != s1->height || s->width != s1->width || s->context_reinit) { - s->context_reinit = 0; s->height = s1->height; s->width = s1->width; if ((ret = ff_mpv_common_frame_size_change(s)) < 0) @@ -664,17 +692,14 @@ void ff_mpv_common_defaults(MpegEncContext *s) } /** - * Set the given MpegEncContext to defaults for decoding. + * Initialize the given MpegEncContext for decoding. * the changed fields will not depend upon * the prior state of the MpegEncContext. */ -void ff_mpv_decode_defaults(MpegEncContext *s) +void ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx) { ff_mpv_common_defaults(s); -} -void ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx) -{ s->avctx = avctx; s->width = avctx->coded_width; s->height = avctx->coded_height; @@ -719,8 +744,8 @@ static int init_context_frame(MpegEncContext *s) if (s->mb_height & 1) yc_size += 2*s->b8_stride + 2*s->mb_stride; - FF_ALLOCZ_OR_GOTO(s->avctx, s->mb_index2xy, (s->mb_num + 1) * sizeof(int), - fail); // error resilience code looks cleaner with this + if (!FF_ALLOCZ_TYPED_ARRAY(s->mb_index2xy, s->mb_num + 1)) + return AVERROR(ENOMEM); for (y = 0; y < s->mb_height; y++) for (x = 0; x < s->mb_width; x++) s->mb_index2xy[x + y * s->mb_width] = x + y * s->mb_stride; @@ -729,12 +754,13 @@ static int init_context_frame(MpegEncContext *s) if (s->encoding) { /* Allocate MV tables */ - FF_ALLOCZ_OR_GOTO(s->avctx, s->p_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail) - FF_ALLOCZ_OR_GOTO(s->avctx, s->b_forw_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail) - FF_ALLOCZ_OR_GOTO(s->avctx, s->b_back_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail) - FF_ALLOCZ_OR_GOTO(s->avctx, s->b_bidir_forw_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail) - FF_ALLOCZ_OR_GOTO(s->avctx, s->b_bidir_back_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail) - FF_ALLOCZ_OR_GOTO(s->avctx, s->b_direct_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail) + if (!FF_ALLOCZ_TYPED_ARRAY(s->p_mv_table_base, mv_table_size) || + !FF_ALLOCZ_TYPED_ARRAY(s->b_forw_mv_table_base, mv_table_size) || + !FF_ALLOCZ_TYPED_ARRAY(s->b_back_mv_table_base, mv_table_size) || + !FF_ALLOCZ_TYPED_ARRAY(s->b_bidir_forw_mv_table_base, mv_table_size) || + !FF_ALLOCZ_TYPED_ARRAY(s->b_bidir_back_mv_table_base, mv_table_size) || + !FF_ALLOCZ_TYPED_ARRAY(s->b_direct_mv_table_base, mv_table_size)) + return AVERROR(ENOMEM); s->p_mv_table = s->p_mv_table_base + s->mb_stride + 1; s->b_forw_mv_table = s->b_forw_mv_table_base + s->mb_stride + 1; s->b_back_mv_table = s->b_back_mv_table_base + s->mb_stride + 1; @@ -743,15 +769,11 @@ static int init_context_frame(MpegEncContext *s) s->b_direct_mv_table = s->b_direct_mv_table_base + s->mb_stride + 1; /* Allocate MB type table */ - FF_ALLOCZ_OR_GOTO(s->avctx, s->mb_type, mb_array_size * sizeof(uint16_t), fail) // needed for encoding - - FF_ALLOCZ_OR_GOTO(s->avctx, s->lambda_table, mb_array_size * sizeof(int), fail) - - FF_ALLOC_OR_GOTO(s->avctx, s->cplx_tab, - mb_array_size * sizeof(float), fail); - FF_ALLOC_OR_GOTO(s->avctx, s->bits_tab, - mb_array_size * sizeof(float), fail); - + if (!FF_ALLOCZ_TYPED_ARRAY(s->mb_type, mb_array_size) || + !FF_ALLOCZ_TYPED_ARRAY(s->lambda_table, mb_array_size) || + !FF_ALLOC_TYPED_ARRAY (s->cplx_tab, mb_array_size) || + !FF_ALLOC_TYPED_ARRAY (s->bits_tab, mb_array_size)) + return AVERROR(ENOMEM); } if (s->codec_id == AV_CODEC_ID_MPEG4 || @@ -761,34 +783,34 @@ static int init_context_frame(MpegEncContext *s) int j, k; for (j = 0; j < 2; j++) { for (k = 0; k < 2; k++) { - FF_ALLOCZ_OR_GOTO(s->avctx, - s->b_field_mv_table_base[i][j][k], - mv_table_size * 2 * sizeof(int16_t), - fail); + if (!FF_ALLOCZ_TYPED_ARRAY(s->b_field_mv_table_base[i][j][k], mv_table_size)) + return AVERROR(ENOMEM); s->b_field_mv_table[i][j][k] = s->b_field_mv_table_base[i][j][k] + s->mb_stride + 1; } - FF_ALLOCZ_OR_GOTO(s->avctx, s->b_field_select_table [i][j], mb_array_size * 2 * sizeof(uint8_t), fail) - FF_ALLOCZ_OR_GOTO(s->avctx, s->p_field_mv_table_base[i][j], mv_table_size * 2 * sizeof(int16_t), fail) + if (!FF_ALLOCZ_TYPED_ARRAY(s->b_field_select_table [i][j], mv_table_size * 2) || + !FF_ALLOCZ_TYPED_ARRAY(s->p_field_mv_table_base[i][j], mv_table_size)) + return AVERROR(ENOMEM); s->p_field_mv_table[i][j] = s->p_field_mv_table_base[i][j] + s->mb_stride + 1; } - FF_ALLOCZ_OR_GOTO(s->avctx, s->p_field_select_table[i], mb_array_size * 2 * sizeof(uint8_t), fail) + if (!FF_ALLOCZ_TYPED_ARRAY(s->p_field_select_table[i], mv_table_size * 2)) + return AVERROR(ENOMEM); } } if (s->out_format == FMT_H263) { - /* cbp values */ - FF_ALLOCZ_OR_GOTO(s->avctx, s->coded_block_base, y_size + (s->mb_height&1)*2*s->b8_stride, fail); + /* cbp values, cbp, ac_pred, pred_dir */ + if (!FF_ALLOCZ_TYPED_ARRAY(s->coded_block_base, y_size + (s->mb_height&1)*2*s->b8_stride) || + !FF_ALLOCZ_TYPED_ARRAY(s->cbp_table, mb_array_size) || + !FF_ALLOCZ_TYPED_ARRAY(s->pred_dir_table, mb_array_size)) + return AVERROR(ENOMEM); s->coded_block = s->coded_block_base + s->b8_stride + 1; - - /* cbp, ac_pred, pred_dir */ - FF_ALLOCZ_OR_GOTO(s->avctx, s->cbp_table , mb_array_size * sizeof(uint8_t), fail); - FF_ALLOCZ_OR_GOTO(s->avctx, s->pred_dir_table, mb_array_size * sizeof(uint8_t), fail); } if (s->h263_pred || s->h263_plus || !s->encoding) { /* dc values */ // MN: we need these for error resilience of intra-frames - FF_ALLOCZ_OR_GOTO(s->avctx, s->dc_val_base, yc_size * sizeof(int16_t), fail); + if (!FF_ALLOCZ_TYPED_ARRAY(s->dc_val_base, yc_size)) + return AVERROR(ENOMEM); s->dc_val[0] = s->dc_val_base + s->b8_stride + 1; s->dc_val[1] = s->dc_val_base + y_size + s->mb_stride + 1; s->dc_val[2] = s->dc_val[1] + c_size; @@ -796,17 +818,14 @@ static int init_context_frame(MpegEncContext *s) s->dc_val_base[i] = 1024; } - /* which mb is an intra block */ - FF_ALLOCZ_OR_GOTO(s->avctx, s->mbintra_table, mb_array_size, fail); + /* which mb is an intra block, init macroblock skip table */ + if (!FF_ALLOC_TYPED_ARRAY(s->mbintra_table, mb_array_size) || + // Note the + 1 is for a quicker MPEG-4 slice_end detection + !FF_ALLOCZ_TYPED_ARRAY(s->mbskip_table, mb_array_size + 2)) + return AVERROR(ENOMEM); memset(s->mbintra_table, 1, mb_array_size); - /* init macroblock skip table */ - FF_ALLOCZ_OR_GOTO(s->avctx, s->mbskip_table, mb_array_size + 2, fail); - // Note the + 1 is for a quicker MPEG-4 slice_end detection - return ff_mpeg_er_init(s); -fail: - return AVERROR(ENOMEM); } static void clear_context(MpegEncContext *s) @@ -911,7 +930,7 @@ av_cold int ff_mpv_common_init(MpegEncContext *s) if (s->avctx->pix_fmt == AV_PIX_FMT_NONE) { av_log(s->avctx, AV_LOG_ERROR, "decoding to AV_PIX_FMT_NONE is not supported.\n"); - return -1; + return AVERROR(EINVAL); } if (nb_slices > MAX_THREADS || (nb_slices > s->mb_height && s->mb_height)) { @@ -927,7 +946,7 @@ av_cold int ff_mpv_common_init(MpegEncContext *s) if ((s->width || s->height) && av_image_check_size(s->width, s->height, 0, s->avctx)) - return -1; + return AVERROR(EINVAL); dct_init(s); @@ -938,27 +957,21 @@ av_cold int ff_mpv_common_init(MpegEncContext *s) if (ret) return ret; - FF_ALLOCZ_OR_GOTO(s->avctx, s->picture, - MAX_PICTURE_COUNT * sizeof(Picture), fail); + if (!FF_ALLOCZ_TYPED_ARRAY(s->picture, MAX_PICTURE_COUNT)) + return AVERROR(ENOMEM); for (i = 0; i < MAX_PICTURE_COUNT; i++) { s->picture[i].f = av_frame_alloc(); if (!s->picture[i].f) - goto fail; + goto fail_nomem; } - s->next_picture.f = av_frame_alloc(); - if (!s->next_picture.f) - goto fail; - s->last_picture.f = av_frame_alloc(); - if (!s->last_picture.f) - goto fail; - s->current_picture.f = av_frame_alloc(); - if (!s->current_picture.f) - goto fail; - s->new_picture.f = av_frame_alloc(); - if (!s->new_picture.f) - goto fail; - if (init_context_frame(s)) + if (!(s->next_picture.f = av_frame_alloc()) || + !(s->last_picture.f = av_frame_alloc()) || + !(s->current_picture.f = av_frame_alloc()) || + !(s->new_picture.f = av_frame_alloc())) + goto fail_nomem; + + if ((ret = init_context_frame(s))) goto fail; s->parse_context.state = -1; @@ -966,39 +979,25 @@ av_cold int ff_mpv_common_init(MpegEncContext *s) s->context_initialized = 1; memset(s->thread_context, 0, sizeof(s->thread_context)); s->thread_context[0] = s; + s->slice_context_count = nb_slices; // if (s->width && s->height) { - if (nb_slices > 1) { - for (i = 0; i < nb_slices; i++) { - if (i) { - s->thread_context[i] = av_memdup(s, sizeof(MpegEncContext)); - if (!s->thread_context[i]) - goto fail; - } - if (init_duplicate_context(s->thread_context[i]) < 0) - goto fail; - s->thread_context[i]->start_mb_y = - (s->mb_height * (i) + nb_slices / 2) / nb_slices; - s->thread_context[i]->end_mb_y = - (s->mb_height * (i + 1) + nb_slices / 2) / nb_slices; - } - } else { - if (init_duplicate_context(s) < 0) - goto fail; - s->start_mb_y = 0; - s->end_mb_y = s->mb_height; - } - s->slice_context_count = nb_slices; + ret = init_duplicate_contexts(s); + if (ret < 0) + goto fail; // } return 0; + fail_nomem: + ret = AVERROR(ENOMEM); fail: ff_mpv_common_end(s); - return -1; + return ret; } /** - * Frees and resets MpegEncContext fields depending on the resolution. + * Frees and resets MpegEncContext fields depending on the resolution + * as well as the slice thread contexts. * Is used during resolution changes to avoid a full reinitialization of the * codec. */ @@ -1006,6 +1005,8 @@ static void free_context_frame(MpegEncContext *s) { int i, j, k; + free_duplicate_contexts(s); + av_freep(&s->mb_type); av_freep(&s->p_mv_table_base); av_freep(&s->b_forw_mv_table_base); @@ -1058,16 +1059,6 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s) if (!s->context_initialized) return AVERROR(EINVAL); - if (s->slice_context_count > 1) { - for (i = 0; i < s->slice_context_count; i++) { - free_duplicate_context(s->thread_context[i]); - } - for (i = 1; i < s->slice_context_count; i++) { - av_freep(&s->thread_context[i]); - } - } else - free_duplicate_context(s); - free_context_frame(s); if (s->picture) @@ -1089,6 +1080,13 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s) (err = av_image_check_size(s->width, s->height, 0, s->avctx)) < 0) goto fail; + /* set chroma shifts */ + err = av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt, + &s->chroma_x_shift, + &s->chroma_y_shift); + if (err < 0) + goto fail; + if ((err = init_context_frame(s))) goto fail; @@ -1096,36 +1094,16 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s) s->thread_context[0] = s; if (s->width && s->height) { - int nb_slices = s->slice_context_count; - if (nb_slices > 1) { - for (i = 0; i < nb_slices; i++) { - if (i) { - s->thread_context[i] = av_memdup(s, sizeof(MpegEncContext)); - if (!s->thread_context[i]) { - err = AVERROR(ENOMEM); - goto fail; - } - } - if ((err = init_duplicate_context(s->thread_context[i])) < 0) - goto fail; - s->thread_context[i]->start_mb_y = - (s->mb_height * (i) + nb_slices / 2) / nb_slices; - s->thread_context[i]->end_mb_y = - (s->mb_height * (i + 1) + nb_slices / 2) / nb_slices; - } - } else { - err = init_duplicate_context(s); - if (err < 0) - goto fail; - s->start_mb_y = 0; - s->end_mb_y = s->mb_height; - } - s->slice_context_count = nb_slices; + err = init_duplicate_contexts(s); + if (err < 0) + goto fail; } + s->context_reinit = 0; return 0; fail: - ff_mpv_common_end(s); + free_context_frame(s); + s->context_reinit = 1; return err; } @@ -1135,17 +1113,11 @@ void ff_mpv_common_end(MpegEncContext *s) int i; if (!s) - return ; + return; - if (s->slice_context_count > 1) { - for (i = 0; i < s->slice_context_count; i++) { - free_duplicate_context(s->thread_context[i]); - } - for (i = 1; i < s->slice_context_count; i++) { - av_freep(&s->thread_context[i]); - } + free_context_frame(s); + if (s->slice_context_count > 1) s->slice_context_count = 1; - } else free_duplicate_context(s); av_freep(&s->parse_context.buffer); s->parse_context.buffer_size = 0; @@ -1153,6 +1125,9 @@ void ff_mpv_common_end(MpegEncContext *s) av_freep(&s->bitstream_buffer); s->allocated_bitstream_buffer_size = 0; + if (!s->avctx) + return; + if (s->picture) { for (i = 0; i < MAX_PICTURE_COUNT; i++) { ff_free_picture_tables(&s->picture[i]); @@ -1174,9 +1149,8 @@ void ff_mpv_common_end(MpegEncContext *s) ff_mpeg_unref_picture(s->avctx, &s->new_picture); av_frame_free(&s->new_picture.f); - free_context_frame(s); - s->context_initialized = 0; + s->context_reinit = 0; s->last_picture_ptr = s->next_picture_ptr = s->current_picture_ptr = NULL; @@ -1263,7 +1237,7 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx) pic->f->coded_picture_number = s->coded_picture_number++; - if (alloc_picture(s, pic, 0) < 0) + if (alloc_picture(s, pic) < 0) return -1; s->current_picture_ptr = pic; @@ -1324,7 +1298,7 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx) s->last_picture_ptr->f->key_frame = 0; s->last_picture_ptr->f->pict_type = AV_PICTURE_TYPE_P; - if (alloc_picture(s, s->last_picture_ptr, 0) < 0) { + if (alloc_picture(s, s->last_picture_ptr) < 0) { s->last_picture_ptr = NULL; return -1; } @@ -1365,7 +1339,7 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx) s->next_picture_ptr->f->key_frame = 0; s->next_picture_ptr->f->pict_type = AV_PICTURE_TYPE_P; - if (alloc_picture(s, s->next_picture_ptr, 0) < 0) { + if (alloc_picture(s, s->next_picture_ptr) < 0) { s->next_picture_ptr = NULL; return -1; } @@ -1445,14 +1419,33 @@ void ff_print_debug_info(MpegEncContext *s, Picture *p, AVFrame *pict) int ff_mpv_export_qp_table(MpegEncContext *s, AVFrame *f, Picture *p, int qp_type) { - AVBufferRef *ref = av_buffer_ref(p->qscale_table_buf); - int offset = 2*s->mb_stride + 1; - if(!ref) + AVVideoEncParams *par; + int mult = (qp_type == FF_QSCALE_TYPE_MPEG1) ? 2 : 1; + unsigned int nb_mb = p->alloc_mb_height * p->alloc_mb_width; + unsigned int x, y; + + if (!(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_VIDEO_ENC_PARAMS)) + return 0; + + par = av_video_enc_params_create_side_data(f, AV_VIDEO_ENC_PARAMS_MPEG2, nb_mb); + if (!par) return AVERROR(ENOMEM); - av_assert0(ref->size >= offset + s->mb_stride * ((f->height+15)/16)); - ref->size -= offset; - ref->data += offset; - return av_frame_set_qp_table(f, ref, s->mb_stride, qp_type); + + for (y = 0; y < p->alloc_mb_height; y++) + for (x = 0; x < p->alloc_mb_width; x++) { + const unsigned int block_idx = y * p->alloc_mb_width + x; + const unsigned int mb_xy = y * p->alloc_mb_stride + x; + AVVideoBlockParams *b = av_video_enc_params_block(par, block_idx); + + b->src_x = x * 16; + b->src_y = y * 16; + b->w = 16; + b->h = 16; + + b->delta_qp = p->qscale_table[mb_xy] * mult; + } + + return 0; } static inline int hpel_motion_lowres(MpegEncContext *s,