From f3ab3e1aeec318763065303a1569796131d3a561 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Wed, 21 Mar 2012 16:36:23 -0400 Subject: [PATCH 1/7] avconv: make the async buffer global and free it in exit_program() --- avconv.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/avconv.c b/avconv.c index 9a3c75d59e..f1da50fbae 100644 --- a/avconv.c +++ b/avconv.c @@ -142,6 +142,8 @@ static int print_stats = 1; static uint8_t *audio_buf; static unsigned int allocated_audio_buf_size; +static uint8_t *async_buf; +static unsigned int allocated_async_buf_size; #define DEFAULT_PASS_LOGFILENAME_PREFIX "av2pass" @@ -718,6 +720,8 @@ void exit_program(int ret) uninit_opts(); av_free(audio_buf); allocated_audio_buf_size = 0; + av_free(async_buf); + allocated_async_buf_size = 0; #if CONFIG_AVFILTER avfilter_uninit(); @@ -1117,8 +1121,12 @@ need_realloc: return; ist->is_start = 0; } else { - static uint8_t *input_tmp = NULL; - input_tmp = av_realloc(input_tmp, byte_delta + size); + av_fast_malloc(&async_buf, &allocated_async_buf_size, + byte_delta + size); + if (!async_buf) { + av_log(NULL, AV_LOG_FATAL, "Out of memory in do_audio_out\n"); + exit_program(1); + } if (byte_delta > allocated_for_size - size) { allocated_for_size = byte_delta + (int64_t)size; @@ -1126,9 +1134,9 @@ need_realloc: } ist->is_start = 0; - generate_silence(input_tmp, dec->sample_fmt, byte_delta); - memcpy(input_tmp + byte_delta, buf, size); - buf = input_tmp; + generate_silence(async_buf, dec->sample_fmt, byte_delta); + memcpy(async_buf + byte_delta, buf, size); + buf = async_buf; size += byte_delta; av_log(NULL, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", idelta); } From 9869e963a6a6bd3a8bd118cee698df08d84cbfba Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Wed, 21 Mar 2012 16:55:30 -0400 Subject: [PATCH 2/7] avconv: move audio output buffer allocation to a separate function Allows for removing a goto and makes the code easier to follow. --- avconv.c | 52 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/avconv.c b/avconv.c index f1da50fbae..d3f9540d04 100644 --- a/avconv.c +++ b/avconv.c @@ -1011,11 +1011,37 @@ static int encode_audio_frame(AVFormatContext *s, OutputStream *ost, return pkt.size; } +static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc, + int nb_samples) +{ + int64_t audio_buf_samples; + int audio_buf_size; + + /* calculate required number of samples to allocate */ + audio_buf_samples = ((int64_t)nb_samples * enc->sample_rate + dec->sample_rate) / + dec->sample_rate; + audio_buf_samples = audio_buf_samples * 2 + 10000; // safety factors for the deprecated resampling API + audio_buf_samples = FFMAX(audio_buf_samples, enc->frame_size); + if (audio_buf_samples > INT_MAX) + return AVERROR(EINVAL); + + audio_buf_size = av_samples_get_buffer_size(NULL, enc->channels, + audio_buf_samples, + enc->sample_fmt, 32); + if (audio_buf_size < 0) + return audio_buf_size; + + av_fast_malloc(&audio_buf, &allocated_audio_buf_size, audio_buf_size); + if (!audio_buf) + return AVERROR(ENOMEM); + + return 0; +} + static void do_audio_out(AVFormatContext *s, OutputStream *ost, InputStream *ist, AVFrame *decoded_frame) { uint8_t *buftmp; - int64_t audio_buf_size; int size_out, frame_bytes, resample_changed; AVCodecContext *enc = ost->st->codec; @@ -1024,23 +1050,9 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, int isize = av_get_bytes_per_sample(dec->sample_fmt); uint8_t *buf = decoded_frame->data[0]; int size = decoded_frame->nb_samples * dec->channels * isize; - int64_t allocated_for_size = size; -need_realloc: - audio_buf_size = (allocated_for_size + isize * dec->channels - 1) / (isize * dec->channels); - audio_buf_size = (audio_buf_size * enc->sample_rate + dec->sample_rate) / dec->sample_rate; - audio_buf_size = audio_buf_size * 2 + 10000; // safety factors for the deprecated resampling API - audio_buf_size = FFMAX(audio_buf_size, enc->frame_size); - audio_buf_size *= osize * enc->channels; - - if (audio_buf_size > INT_MAX) { - av_log(NULL, AV_LOG_FATAL, "Buffer sizes too large\n"); - exit_program(1); - } - - av_fast_malloc(&audio_buf, &allocated_audio_buf_size, audio_buf_size); - if (!audio_buf) { - av_log(NULL, AV_LOG_FATAL, "Out of memory in do_audio_out\n"); + if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples) < 0) { + av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); exit_program(1); } @@ -1128,9 +1140,9 @@ need_realloc: exit_program(1); } - if (byte_delta > allocated_for_size - size) { - allocated_for_size = byte_delta + (int64_t)size; - goto need_realloc; + if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples + idelta) < 0) { + av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); + exit_program(1); } ist->is_start = 0; From 4094fc9971058b5a11c38d3294141c3220a2b691 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Wed, 21 Mar 2012 16:56:49 -0400 Subject: [PATCH 3/7] avconv: fix the resampling safety factors for output audio buffer allocation This matches the output size required for audio_resample() --- avconv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avconv.c b/avconv.c index d3f9540d04..b83662c893 100644 --- a/avconv.c +++ b/avconv.c @@ -1020,7 +1020,7 @@ static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc, /* calculate required number of samples to allocate */ audio_buf_samples = ((int64_t)nb_samples * enc->sample_rate + dec->sample_rate) / dec->sample_rate; - audio_buf_samples = audio_buf_samples * 2 + 10000; // safety factors for the deprecated resampling API + audio_buf_samples = 4 * audio_buf_samples + 16; // safety factors for resampling audio_buf_samples = FFMAX(audio_buf_samples, enc->frame_size); if (audio_buf_samples > INT_MAX) return AVERROR(EINVAL); From afa612901615cca6c0160b5e6c18ffcacf0add46 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Thu, 22 Mar 2012 15:50:58 -0400 Subject: [PATCH 4/7] zerocodec: factorize loop Signed-off-by: Diego Biurrun --- libavcodec/zerocodec.c | 45 ++++++++++++------------------------------ 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/libavcodec/zerocodec.c b/libavcodec/zerocodec.c index 3bf1fd93f4..6c57e05197 100644 --- a/libavcodec/zerocodec.c +++ b/libavcodec/zerocodec.c @@ -62,49 +62,30 @@ static int zerocodec_decode_frame(AVCodecContext *avctx, void *data, */ if (avpkt->flags & AV_PKT_FLAG_KEY) { - pic->key_frame = 1; pic->pict_type = AV_PICTURE_TYPE_I; - - for (i = 0; i < avctx->height; i++) { - - zstream->next_out = dst; - zstream->avail_out = avctx->width << 1; - - zret = inflate(zstream, Z_SYNC_FLUSH); - - if (zret != Z_OK && zret != Z_STREAM_END) { - av_log(avctx, AV_LOG_ERROR, - "Inflate failed with return code: %d\n", zret); - return AVERROR(EINVAL); - } - - dst += pic->linesize[0]; - } } else { - pic->key_frame = 0; pic->pict_type = AV_PICTURE_TYPE_P; + } - for (i = 0; i < avctx->height; i++) { + for (i = 0; i < avctx->height; i++) { + zstream->next_out = dst; + zstream->avail_out = avctx->width << 1; - zstream->next_out = dst; - zstream->avail_out = avctx->width << 1; - - zret = inflate(zstream, Z_SYNC_FLUSH); - - if (zret != Z_OK && zret != Z_STREAM_END) { - av_log(avctx, AV_LOG_ERROR, - "Inflate failed with return code: %d\n", zret); - return AVERROR(EINVAL); - } + zret = inflate(zstream, Z_SYNC_FLUSH); + if (zret != Z_OK && zret != Z_STREAM_END) { + av_log(avctx, AV_LOG_ERROR, + "Inflate failed with return code: %d\n", zret); + return AVERROR(EINVAL); + } + if (!(avpkt->flags & AV_PKT_FLAG_KEY)) for (j = 0; j < avctx->width << 1; j++) dst[j] += prev[j] & -!dst[j]; - prev += prev_pic->linesize[0]; - dst += pic->linesize[0]; - } + prev += prev_pic->linesize[0]; + dst += pic->linesize[0]; } /* Release the previous buffer if need be */ From 4a584edad7cd9be8241e8b6fe1fadf8340cd292b Mon Sep 17 00:00:00 2001 From: Josh Allmann Date: Wed, 21 Mar 2012 08:01:37 -0700 Subject: [PATCH 5/7] configure: die if x11grab dependencies are unavailable Signed-off-by: Diego Biurrun --- configure | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/configure b/configure index 34a5f12ab2..8c227aae92 100755 --- a/configure +++ b/configure @@ -1496,7 +1496,6 @@ v4l2_indev_deps_any="linux_videodev2_h sys_videoio_h" vfwcap_indev_deps="capCreateCaptureWindow vfwcap_defines" vfwcap_indev_extralibs="-lavicap32" x11_grab_device_indev_deps="x11grab XShmCreateImage" -x11_grab_device_indev_extralibs="-lX11 -lXext -lXfixes" # protocols gopher_protocol_deps="network" @@ -3026,13 +3025,10 @@ enabled_any sndio_indev sndio_outdev && check_lib2 sndio.h sio_open -lsndio enabled libcdio && check_lib2 "cdio/cdda.h cdio/paranoia.h" cdio_cddap_open "-lcdio_paranoia -lcdio_cdda -lcdio" -enabled x11grab && -check_header X11/Xlib.h && -check_header X11/extensions/XShm.h && -check_header X11/extensions/Xfixes.h && -check_func XOpenDisplay -lX11 && -check_func XShmCreateImage -lX11 -lXext && -check_func XFixesGetCursorImage -lX11 -lXext -lXfixes +enabled x11grab && +require X11 X11/Xlib.h XOpenDisplay -lX11 && +require Xext X11/extensions/XShm.h XShmCreateImage -lXext && +require Xfixes X11/extensions/Xfixes.h XFixesGetCursorImage -lXfixes # check for VDA header if ! disabled vda && check_header VideoDecodeAcceleration/VDADecoder.h; then From 5ab506a5c83afe67ae0f0a8d7586764b54aeac27 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 20 Mar 2012 14:44:28 +0100 Subject: [PATCH 6/7] MPV: set reference frame pointers to NULL when allocation of dummy pictures fails --- libavcodec/mpegvideo.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 720997fb63..280207530b 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -1267,8 +1267,10 @@ int ff_MPV_frame_start(MpegEncContext *s, AVCodecContext *avctx) /* Allocate a dummy frame */ i = ff_find_unused_picture(s, 0); s->last_picture_ptr = &s->picture[i]; - if (ff_alloc_picture(s, s->last_picture_ptr, 0) < 0) + if (ff_alloc_picture(s, s->last_picture_ptr, 0) < 0) { + s->last_picture_ptr = NULL; return -1; + } ff_thread_report_progress(&s->last_picture_ptr->f, INT_MAX, 0); ff_thread_report_progress(&s->last_picture_ptr->f, INT_MAX, 1); s->last_picture_ptr->f.reference = 3; @@ -1279,8 +1281,10 @@ int ff_MPV_frame_start(MpegEncContext *s, AVCodecContext *avctx) /* Allocate a dummy frame */ i = ff_find_unused_picture(s, 0); s->next_picture_ptr = &s->picture[i]; - if (ff_alloc_picture(s, s->next_picture_ptr, 0) < 0) + if (ff_alloc_picture(s, s->next_picture_ptr, 0) < 0) { + s->next_picture_ptr = NULL; return -1; + } ff_thread_report_progress(&s->next_picture_ptr->f, INT_MAX, 0); ff_thread_report_progress(&s->next_picture_ptr->f, INT_MAX, 1); s->next_picture_ptr->f.reference = 3; From 73ad4471a48bd02b2c2a55de116161b87e061023 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 16 Mar 2012 16:18:57 +0100 Subject: [PATCH 7/7] rv34: Handle only complete frames in frame-mt. Correct handling of errors to prevent hags or crashes is very complex otherwise. The frame initializing is also moved from decode_slice() to decode_frame() for clarity. --- libavcodec/rv34.c | 191 +++++++++++++++++++++++++++------------------- 1 file changed, 112 insertions(+), 79 deletions(-) diff --git a/libavcodec/rv34.c b/libavcodec/rv34.c index 83a9b9bc7b..f9ea40d6c8 100644 --- a/libavcodec/rv34.c +++ b/libavcodec/rv34.c @@ -1396,7 +1396,7 @@ static int rv34_decode_slice(RV34DecContext *r, int end, const uint8_t* buf, int { MpegEncContext *s = &r->s; GetBitContext *gb = &s->gb; - int mb_pos; + int mb_pos, slice_type; int res; init_get_bits(&r->s.gb, buf, buf_size*8); @@ -1406,60 +1406,10 @@ static int rv34_decode_slice(RV34DecContext *r, int end, const uint8_t* buf, int return -1; } - if ((s->mb_x == 0 && s->mb_y == 0) || s->current_picture_ptr==NULL) { - if (s->width != r->si.width || s->height != r->si.height) { - int err; - - av_log(s->avctx, AV_LOG_WARNING, "Changing dimensions to %dx%d\n", - r->si.width, r->si.height); - ff_MPV_common_end(s); - s->width = r->si.width; - s->height = r->si.height; - avcodec_set_dimensions(s->avctx, s->width, s->height); - if ((err = ff_MPV_common_init(s)) < 0) - return err; - if ((err = rv34_decoder_realloc(r)) < 0) - return err; - } - s->pict_type = r->si.type ? r->si.type : AV_PICTURE_TYPE_I; - if(ff_MPV_frame_start(s, s->avctx) < 0) - return -1; - ff_er_frame_start(s); - if (!r->tmp_b_block_base) { - int i; - - r->tmp_b_block_base = av_malloc(s->linesize * 48); - for (i = 0; i < 2; i++) - r->tmp_b_block_y[i] = r->tmp_b_block_base + i * 16 * s->linesize; - for (i = 0; i < 4; i++) - r->tmp_b_block_uv[i] = r->tmp_b_block_base + 32 * s->linesize - + (i >> 1) * 8 * s->uvlinesize + (i & 1) * 16; - } - r->cur_pts = r->si.pts; - if(s->pict_type != AV_PICTURE_TYPE_B){ - r->last_pts = r->next_pts; - r->next_pts = r->cur_pts; - }else{ - int refdist = GET_PTS_DIFF(r->next_pts, r->last_pts); - int dist0 = GET_PTS_DIFF(r->cur_pts, r->last_pts); - int dist1 = GET_PTS_DIFF(r->next_pts, r->cur_pts); - - if(!refdist){ - r->weight1 = r->weight2 = 8192; - }else{ - r->weight1 = (dist0 << 14) / refdist; - r->weight2 = (dist1 << 14) / refdist; - } - } - s->mb_x = s->mb_y = 0; - ff_thread_finish_setup(s->avctx); - } else { - int slice_type = r->si.type ? r->si.type : AV_PICTURE_TYPE_I; - - if (slice_type != s->pict_type) { - av_log(s->avctx, AV_LOG_ERROR, "Slice type mismatch\n"); - return AVERROR_INVALIDDATA; - } + slice_type = r->si.type ? r->si.type : AV_PICTURE_TYPE_I; + if (slice_type != s->pict_type) { + av_log(s->avctx, AV_LOG_ERROR, "Slice type mismatch\n"); + return AVERROR_INVALIDDATA; } r->si.end = end; @@ -1609,10 +1559,6 @@ int ff_rv34_decode_update_thread_context(AVCodecContext *dst, const AVCodecConte memset(&r->si, 0, sizeof(r->si)); - /* necessary since it is it the condition checked for in decode_slice - * to call ff_MPV_frame_start. cmp. comment at the end of decode_frame */ - s->current_picture_ptr = NULL; - return 0; } @@ -1622,8 +1568,33 @@ static int get_slice_offset(AVCodecContext *avctx, const uint8_t *buf, int n) else return AV_RL32(buf + n*8 - 4) == 1 ? AV_RL32(buf + n*8) : AV_RB32(buf + n*8); } +static int finish_frame(AVCodecContext *avctx, AVFrame *pict) +{ + RV34DecContext *r = avctx->priv_data; + MpegEncContext *s = &r->s; + int got_picture = 0; + + ff_er_frame_end(s); + ff_MPV_frame_end(s); + + if (HAVE_THREADS && (s->avctx->active_thread_type & FF_THREAD_FRAME)) + ff_thread_report_progress(&s->current_picture_ptr->f, INT_MAX, 0); + + if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) { + *pict = s->current_picture_ptr->f; + got_picture = 1; + } else if (s->last_picture_ptr != NULL) { + *pict = s->last_picture_ptr->f; + got_picture = 1; + } + if (got_picture) + ff_print_debug_info(s, pict); + + return got_picture; +} + int ff_rv34_decode_frame(AVCodecContext *avctx, - void *data, int *data_size, + void *data, int *got_picture_ptr, AVPacket *avpkt) { const uint8_t *buf = avpkt->data; @@ -1644,7 +1615,7 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, *pict = s->next_picture_ptr->f; s->next_picture_ptr = NULL; - *data_size = sizeof(AVFrame); + *got_picture_ptr = 1; } return 0; } @@ -1679,6 +1650,70 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, || avctx->skip_frame >= AVDISCARD_ALL) return avpkt->size; + /* first slice */ + if (si.start == 0) { + if (s->mb_num_left > 0) { + av_log(avctx, AV_LOG_ERROR, "New frame but still %d MB left.", + s->mb_num_left); + ff_er_frame_end(s); + ff_MPV_frame_end(s); + } + + if (s->width != si.width || s->height != si.height) { + int err; + + av_log(s->avctx, AV_LOG_WARNING, "Changing dimensions to %dx%d\n", + si.width, si.height); + ff_MPV_common_end(s); + s->width = si.width; + s->height = si.height; + avcodec_set_dimensions(s->avctx, s->width, s->height); + if ((err = ff_MPV_common_init(s)) < 0) + return err; + if ((err = rv34_decoder_realloc(r)) < 0) + return err; + } + s->pict_type = si.type ? si.type : AV_PICTURE_TYPE_I; + if (ff_MPV_frame_start(s, s->avctx) < 0) + return -1; + ff_er_frame_start(s); + if (!r->tmp_b_block_base) { + int i; + + r->tmp_b_block_base = av_malloc(s->linesize * 48); + for (i = 0; i < 2; i++) + r->tmp_b_block_y[i] = r->tmp_b_block_base + + i * 16 * s->linesize; + for (i = 0; i < 4; i++) + r->tmp_b_block_uv[i] = r->tmp_b_block_base + 32 * s->linesize + + (i >> 1) * 8 * s->uvlinesize + + (i & 1) * 16; + } + r->cur_pts = si.pts; + if (s->pict_type != AV_PICTURE_TYPE_B) { + r->last_pts = r->next_pts; + r->next_pts = r->cur_pts; + } else { + int refdist = GET_PTS_DIFF(r->next_pts, r->last_pts); + int dist0 = GET_PTS_DIFF(r->cur_pts, r->last_pts); + int dist1 = GET_PTS_DIFF(r->next_pts, r->cur_pts); + + if (!refdist) { + r->weight1 = r->weight2 = 8192; + } else { + r->weight1 = (dist0 << 14) / refdist; + r->weight2 = (dist1 << 14) / refdist; + } + } + s->mb_x = s->mb_y = 0; + ff_thread_finish_setup(s->avctx); + } else if (HAVE_THREADS && + (s->avctx->active_thread_type & FF_THREAD_FRAME)) { + av_log(s->avctx, AV_LOG_ERROR, "Decoder needs full frames in frame " + "multithreading mode (start MB is %d).\n", si.start); + return AVERROR_INVALIDDATA; + } + for(i = 0; i < slice_count; i++){ int offset = get_slice_offset(avctx, slices_hdr, i); int size; @@ -1693,6 +1728,8 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, } r->si.end = s->mb_width * s->mb_height; + s->mb_num_left = r->s.mb_x + r->s.mb_y*r->s.mb_width - r->si.start; + if(i+1 < slice_count){ if (get_slice_offset(avctx, slices_hdr, i+1) < 0 || get_slice_offset(avctx, slices_hdr, i+1) > buf_size) { @@ -1713,32 +1750,28 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, break; } last = rv34_decode_slice(r, r->si.end, buf + offset, size); - s->mb_num_left = r->s.mb_x + r->s.mb_y*r->s.mb_width - r->si.start; if(last) break; } - if(last && s->current_picture_ptr){ - if(r->loop_filter) - r->loop_filter(r, s->mb_height - 1); - ff_er_frame_end(s); - ff_MPV_frame_end(s); + if (s->current_picture_ptr) { + if (last) { + if(r->loop_filter) + r->loop_filter(r, s->mb_height - 1); - if (HAVE_THREADS && (s->avctx->active_thread_type & FF_THREAD_FRAME)) + *got_picture_ptr = finish_frame(avctx, pict); + } else if (HAVE_THREADS && + (s->avctx->active_thread_type & FF_THREAD_FRAME)) { + av_log(avctx, AV_LOG_INFO, "marking unfished frame as finished\n"); + /* always mark the current frame as finished, frame-mt supports + * only complete frames */ + ff_er_frame_end(s); + ff_MPV_frame_end(s); ff_thread_report_progress(&s->current_picture_ptr->f, INT_MAX, 0); - - if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) { - *pict = s->current_picture_ptr->f; - } else if (s->last_picture_ptr != NULL) { - *pict = s->last_picture_ptr->f; + return AVERROR_INVALIDDATA; } - - if(s->last_picture_ptr || s->low_delay){ - *data_size = sizeof(AVFrame); - ff_print_debug_info(s, pict); - } - s->current_picture_ptr = NULL; //so we can detect if frame_end wasnt called (find some nicer solution...) } + return avpkt->size; }