From 435c0b87d28b48dc2e0360adc404a0e2d66d16a0 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 5 Sep 2012 20:40:12 +0200 Subject: [PATCH] mpegvideo: add reinit function for frame parameter changes This is mainly required for frame parameter changes during frame based multithreading but single threaded usage profits too from avoiding ff_MPV_common_end()/ff_MPV_common_init() cycles. --- libavcodec/mpegvideo.c | 103 +++++++++++++++++++++++++++++++++++++++-- libavcodec/mpegvideo.h | 2 + 2 files changed, 101 insertions(+), 4 deletions(-) diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index a1e59af73d..e2e5276c83 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -1001,6 +1001,77 @@ static int free_context_frame(MpegEncContext *s) return 0; } +int ff_MPV_common_frame_size_change(MpegEncContext *s) +{ + int i, err = 0; + + 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) + for (i = 0; i < s->picture_count; i++) { + s->picture[i].needs_realloc = 1; + } + + s->last_picture_ptr = + s->next_picture_ptr = + s->current_picture_ptr = NULL; + + // init + if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO && !s->progressive_sequence) + s->mb_height = (s->height + 31) / 32 * 2; + else if (s->codec_id != AV_CODEC_ID_H264) + s->mb_height = (s->height + 15) / 16; + + if ((s->width || s->height) && + av_image_check_size(s->width, s->height, 0, s->avctx)) + return AVERROR_INVALIDDATA; + + if ((err = init_context_frame(s))) + goto fail; + + s->thread_context[0] = s; + + if (s->width && s->height) { + int nb_slices = s->slice_context_count; + if (nb_slices > 1) { + for (i = 1; i < nb_slices; i++) { + s->thread_context[i] = av_malloc(sizeof(MpegEncContext)); + memcpy(s->thread_context[i], s, sizeof(MpegEncContext)); + } + + for (i = 0; i < nb_slices; i++) { + if (init_duplicate_context(s->thread_context[i], s) < 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, s) < 0) + goto fail; + s->start_mb_y = 0; + s->end_mb_y = s->mb_height; + } + s->slice_context_count = nb_slices; + } + + return 0; + fail: + ff_MPV_common_end(s); + return err; +} + /* init common structure for both encoder and decoder */ void ff_MPV_common_end(MpegEncContext *s) { @@ -1155,7 +1226,17 @@ void ff_release_unused_pictures(MpegEncContext*s, int remove_current) } } -int ff_find_unused_picture(MpegEncContext *s, int shared) +static inline int pic_is_unused(MpegEncContext *s, Picture *pic) +{ + if (pic->f.data[0] == NULL) + return 1; + if (pic->needs_realloc) + if (!pic->owner2 || pic->owner2 == s) + return 1; + return 0; +} + +static int find_unused_picture(MpegEncContext *s, int shared) { int i; @@ -1166,11 +1247,11 @@ int ff_find_unused_picture(MpegEncContext *s, int shared) } } else { for (i = s->picture_range_start; i < s->picture_range_end; i++) { - if (s->picture[i].f.data[0] == NULL && s->picture[i].f.type != 0) + if (pic_is_unused(s, &s->picture[i]) && s->picture[i].f.type != 0) return i; // FIXME } for (i = s->picture_range_start; i < s->picture_range_end; i++) { - if (s->picture[i].f.data[0] == NULL) + if (pic_is_unused(s, &s->picture[i])) return i; } } @@ -1178,6 +1259,20 @@ int ff_find_unused_picture(MpegEncContext *s, int shared) return AVERROR_INVALIDDATA; } +int ff_find_unused_picture(MpegEncContext *s, int shared) +{ + int ret = find_unused_picture(s, shared); + + if (ret >= 0 && ret < s->picture_range_end) { + if (s->picture[ret].needs_realloc) { + s->picture[ret].needs_realloc = 0; + free_picture(s, &s->picture[ret]); + avcodec_get_frame_defaults(&s->picture[ret].f); + } + } + return ret; +} + static void update_noise_reduction(MpegEncContext *s) { int intra, i; @@ -1225,7 +1320,7 @@ int ff_MPV_frame_start(MpegEncContext *s, AVCodecContext *avctx) if (s->picture[i].owner2 == s && s->picture[i].f.data[0] && &s->picture[i] != s->last_picture_ptr && &s->picture[i] != s->next_picture_ptr && - s->picture[i].f.reference) { + s->picture[i].f.reference && !s->picture[i].needs_realloc) { if (!(avctx->active_thread_type & FF_THREAD_FRAME)) av_log(avctx, AV_LOG_ERROR, "releasing zombie picture\n"); diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 95830bb949..88a1059102 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -139,6 +139,7 @@ typedef struct Picture{ int32_t *mb_cmp_score; ///< Table for MB cmp scores, for mb decision FIXME remove int b_frame_score; /* */ struct MpegEncContext *owner2; ///< pointer to the MpegEncContext that allocated this picture + int needs_realloc; ///< Picture needs to be reallocated (eg due to a frame size change) } Picture; /** @@ -748,6 +749,7 @@ void ff_MPV_common_defaults(MpegEncContext *s); void ff_MPV_decode_defaults(MpegEncContext *s); int ff_MPV_common_init(MpegEncContext *s); +int ff_MPV_common_frame_size_change(MpegEncContext *s); void ff_MPV_common_end(MpegEncContext *s); void ff_MPV_decode_mb(MpegEncContext *s, DCTELEM block[12][64]); int ff_MPV_frame_start(MpegEncContext *s, AVCodecContext *avctx);