X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=avconv.c;h=8f385314e5f97603533f7ca2c1a4622505abbcdd;hb=62b5197f97c67940bc09aea34ad4c0c7a6176fde;hp=1e645b8c756a0b5d55d03ae4f2c5373de6cad8a2;hpb=7f92f3d8129f44bc2ed935e9d81735ffdcd9921f;p=ffmpeg diff --git a/avconv.c b/avconv.c index 1e645b8c756..8f385314e5f 100644 --- a/avconv.c +++ b/avconv.c @@ -155,8 +155,6 @@ static uint8_t *audio_buf; static uint8_t *audio_out; static unsigned int allocated_audio_out_size, allocated_audio_buf_size; -static void *samples; - #define DEFAULT_PASS_LOGFILENAME_PREFIX "av2pass" typedef struct InputStream { @@ -165,6 +163,8 @@ typedef struct InputStream { int discard; /* true if stream data should be discarded */ int decoding_needed; /* true if the packets must be decoded in 'raw_fifo' */ AVCodec *dec; + AVFrame *decoded_frame; + AVFrame *filtered_frame; int64_t start; /* time when read started */ int64_t next_pts; /* synthetic pts for cases where pkt.pts @@ -610,10 +610,13 @@ void exit_program(int ret) av_dict_free(&output_files[i].opts); } for(i=0;ist->codec; @@ -802,6 +801,9 @@ static void do_audio_out(AVFormatContext *s, int osize = av_get_bytes_per_sample(enc->sample_fmt); int isize = av_get_bytes_per_sample(dec->sample_fmt); const int coded_bps = av_get_bits_per_sample(enc->codec->id); + 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); @@ -1697,39 +1699,42 @@ static void rate_emu_sleep(InputStream *ist) static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output) { - static unsigned int samples_size = 0; + AVFrame *decoded_frame; + AVCodecContext *avctx = ist->st->codec; int bps = av_get_bytes_per_sample(ist->st->codec->sample_fmt); - uint8_t *decoded_data_buf = NULL; - int decoded_data_size = 0; int i, ret; - if (pkt && samples_size < FFMAX(pkt->size * bps, AVCODEC_MAX_AUDIO_FRAME_SIZE)) { - av_free(samples); - samples_size = FFMAX(pkt->size * bps, AVCODEC_MAX_AUDIO_FRAME_SIZE); - samples = av_malloc(samples_size); - } - decoded_data_size = samples_size; + if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame())) + return AVERROR(ENOMEM); + else + avcodec_get_frame_defaults(ist->decoded_frame); + decoded_frame = ist->decoded_frame; - ret = avcodec_decode_audio3(ist->st->codec, samples, &decoded_data_size, - pkt); - if (ret < 0) + ret = avcodec_decode_audio4(avctx, decoded_frame, got_output, pkt); + if (ret < 0) { return ret; - *got_output = decoded_data_size > 0; + } - /* Some bug in mpeg audio decoder gives */ - /* decoded_data_size < 0, it seems they are overflows */ if (!*got_output) { /* no audio frame */ return ret; } - decoded_data_buf = (uint8_t *)samples; - ist->next_pts += ((int64_t)AV_TIME_BASE/bps * decoded_data_size) / - (ist->st->codec->sample_rate * ist->st->codec->channels); + /* if the decoder provides a pts, use it instead of the last packet pts. + the decoder could be delaying output by a packet or more. */ + if (decoded_frame->pts != AV_NOPTS_VALUE) + ist->next_pts = decoded_frame->pts; + + /* increment next_pts to use for the case where the input stream does not + have timestamps or there are multiple frames in the packet */ + ist->next_pts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) / + avctx->sample_rate; // preprocess audio (volume) if (audio_volume != 256) { - switch (ist->st->codec->sample_fmt) { + int decoded_data_size = decoded_frame->nb_samples * avctx->channels * bps; + void *samples = decoded_frame->data[0]; + switch (avctx->sample_fmt) { case AV_SAMPLE_FMT_U8: { uint8_t *volp = samples; @@ -1790,9 +1795,9 @@ static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output) if (!check_output_constraints(ist, ost) || !ost->encoding_needed) continue; - do_audio_out(output_files[ost->file_index].ctx, ost, ist, - decoded_data_buf, decoded_data_size); + do_audio_out(output_files[ost->file_index].ctx, ost, ist, decoded_frame); } + return ret; } @@ -1806,8 +1811,11 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int int frame_available = 1; #endif - if (!(decoded_frame = avcodec_alloc_frame())) + if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame())) return AVERROR(ENOMEM); + else + avcodec_get_frame_defaults(ist->decoded_frame); + decoded_frame = ist->decoded_frame; pkt->pts = *pkt_pts; pkt->dts = ist->pts; *pkt_pts = AV_NOPTS_VALUE; @@ -1815,12 +1823,11 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int ret = avcodec_decode_video2(ist->st->codec, decoded_frame, got_output, pkt); if (ret < 0) - goto fail; + return ret; quality = same_quant ? decoded_frame->quality : 0; if (!*got_output) { /* no picture yet */ - av_freep(&decoded_frame); return ret; } ist->next_pts = ist->pts = decoded_frame->best_effort_timestamp; @@ -1852,10 +1859,12 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int decoded_frame->pts = ist->pts; av_vsrc_buffer_add_frame(ost->input_video_filter, decoded_frame, AV_VSRC_BUF_FLAG_OVERWRITE); - if (!(filtered_frame = avcodec_alloc_frame())) { - ret = AVERROR(ENOMEM); - goto fail; - } + if (!ist->filtered_frame && !(ist->filtered_frame = avcodec_alloc_frame())) { + av_free(buffer_to_free); + return AVERROR(ENOMEM); + } else + avcodec_get_frame_defaults(ist->filtered_frame); + filtered_frame = ist->filtered_frame; frame_available = avfilter_poll_frame(ost->output_video_filter->inputs[0]); } while (frame_available) { @@ -1884,13 +1893,10 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int if (ost->picref) avfilter_unref_buffer(ost->picref); } - av_freep(&filtered_frame); #endif } -fail: av_free(buffer_to_free); - av_freep(&decoded_frame); return ret; } @@ -3113,7 +3119,7 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena ic->flags |= AVFMT_FLAG_NONBLOCK; ic->interrupt_callback = int_cb; - /* open the input file with generic libav function */ + /* open the input file with generic avformat function */ err = avformat_open_input(&ic, filename, file_iformat, &format_opts); if (err < 0) { print_error(filename, err); @@ -3134,7 +3140,7 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena ret = avformat_find_stream_info(ic, opts); if (ret < 0) { av_log(NULL, AV_LOG_FATAL, "%s: could not find codec parameters\n", filename); - av_close_input_file(ic); + avformat_close_input(&ic); exit_program(1); } @@ -3629,41 +3635,6 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata) return 0; } -static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename) -{ - int i, err; - AVFormatContext *ic = avformat_alloc_context(); - - ic->interrupt_callback = int_cb; - err = avformat_open_input(&ic, filename, NULL, NULL); - if (err < 0) - return err; - /* copy stream format */ - for(i=0;inb_streams;i++) { - AVStream *st; - OutputStream *ost; - AVCodec *codec; - - codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id); - ost = new_output_stream(o, s, codec->type); - st = ost->st; - - // FIXME: a more elegant solution is needed - memcpy(st, ic->streams[i], sizeof(AVStream)); - st->info = av_malloc(sizeof(*st->info)); - memcpy(st->info, ic->streams[i]->info, sizeof(*st->info)); - avcodec_copy_context(st->codec, ic->streams[i]->codec); - - if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && !ost->stream_copy) - choose_sample_fmt(st, codec); - else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !ost->stream_copy) - choose_pixel_fmt(st, codec); - } - - av_close_input_file(ic); - return 0; -} - static void opt_output_file(void *optctx, const char *filename) { OptionsContext *o = optctx; @@ -3685,16 +3656,7 @@ static void opt_output_file(void *optctx, const char *filename) file_oformat= oc->oformat; oc->interrupt_callback = int_cb; - if (!strcmp(file_oformat->name, "ffm") && - av_strstart(filename, "http:", NULL)) { - /* special case for files sent to ffserver: we get the stream - parameters from ffserver */ - int err = read_ffserver_streams(o, oc, filename); - if (err < 0) { - print_error(filename, err); - exit_program(1); - } - } else if (!o->nb_stream_maps) { + if (!o->nb_stream_maps) { /* pick the "best" stream of each type */ #define NEW_STREAM(type, index)\ if (index >= 0) {\ @@ -3821,7 +3783,7 @@ static void opt_output_file(void *optctx, const char *filename) } if (!(oc->oformat->flags & AVFMT_NOFILE)) { - /* test if it already exists to avoid loosing precious files */ + /* test if it already exists to avoid losing precious files */ assert_file_overwrite(filename); /* open the file */ @@ -4268,7 +4230,7 @@ static const OptionDef options[] = { { "c", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" }, { "codec", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" }, { "pre", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(presets)}, "preset name", "preset" }, - { "map", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map}, "set input stream mapping", "file.stream[:syncfile.syncstream]" }, + { "map", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map}, "set input stream mapping", "[-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]]" }, { "map_metadata", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_metadata}, "set metadata information of outfile from infile", "outfile[,metadata]:infile[,metadata]" }, { "map_chapters", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_OFFSET, {.off = OFFSET(chapters_input_file)}, "set chapters mapping", "input_file_index" },