diff options
author | Justin Ruggles <justin.ruggles@gmail.com> | 2011-04-24 16:48:42 -0400 |
---|---|---|
committer | Justin Ruggles <justin.ruggles@gmail.com> | 2011-05-18 17:27:06 -0400 |
commit | bc778a0cea3027941afa1ff6bbb424b3159a0b27 (patch) | |
tree | 0a65284095508e83a60149b62ba7d2cbe6a673c0 | |
parent | 00e5da893dc8f67cbc9ed940c4da9423a01e4f8c (diff) | |
download | ffmpeg-bc778a0cea3027941afa1ff6bbb424b3159a0b27.tar.gz |
Add support for request_sample_format in ffmpeg and ffplay.
-rw-r--r-- | ffmpeg.c | 72 | ||||
-rw-r--r-- | ffplay.c | 17 |
2 files changed, 87 insertions, 2 deletions
@@ -546,6 +546,46 @@ static void choose_sample_fmt(AVStream *st, AVCodec *codec) } } +/** + * Update the requested input sample format based on the output sample format. + * This is currently only used to request float output from decoders which + * support multiple sample formats, one of which is AV_SAMPLE_FMT_FLT. + * Ideally this will be removed in the future when decoders do not do format + * conversion and only output in their native format. + */ +static void update_sample_fmt(AVCodecContext *dec, AVCodec *dec_codec, + AVCodecContext *enc) +{ + /* if sample formats match or a decoder sample format has already been + requested, just return */ + if (enc->sample_fmt == dec->sample_fmt || + dec->request_sample_fmt > AV_SAMPLE_FMT_NONE) + return; + + /* if decoder supports more than one output format */ + if (dec_codec && dec_codec->sample_fmts && + dec_codec->sample_fmts[0] != AV_SAMPLE_FMT_NONE && + dec_codec->sample_fmts[1] != AV_SAMPLE_FMT_NONE) { + enum AVSampleFormat *p; + int min_dec = -1, min_inc = -1; + + /* find a matching sample format in the encoder */ + for (p = dec_codec->sample_fmts; *p != AV_SAMPLE_FMT_NONE; p++) { + if (*p == enc->sample_fmt) { + dec->request_sample_fmt = *p; + return; + } else if (*p > enc->sample_fmt) { + min_inc = FFMIN(min_inc, *p - enc->sample_fmt); + } else + min_dec = FFMIN(min_dec, enc->sample_fmt - *p); + } + + /* if none match, provide the one that matches quality closest */ + dec->request_sample_fmt = min_inc > 0 ? enc->sample_fmt + min_inc : + enc->sample_fmt - min_dec; + } +} + static void choose_sample_rate(AVStream *st, AVCodec *codec) { if(codec && codec->supported_samplerates){ @@ -751,7 +791,7 @@ need_realloc: ffmpeg_exit(1); } - if (enc->channels != dec->channels) + if (enc->channels != dec->channels || enc->sample_rate != dec->sample_rate) ost->audio_resample = 1; resample_changed = ost->resample_sample_fmt != dec->sample_fmt || @@ -777,7 +817,7 @@ need_realloc: ost->resample_sample_rate == enc->sample_rate) { ost->resample = NULL; ost->audio_resample = 0; - } else { + } else if (ost->audio_resample) { if (dec->sample_fmt != AV_SAMPLE_FMT_S16) fprintf(stderr, "Warning, using s16 intermediate sample format for resampling\n"); ost->resample = av_audio_resample_init(enc->channels, dec->channels, @@ -2308,6 +2348,17 @@ static int transcode(AVFormatContext **output_files, ret = AVERROR(EINVAL); goto dump_format; } + + /* update requested sample format for the decoder based on the + corresponding encoder sample format */ + for (j = 0; j < nb_ostreams; j++) { + ost = ost_table[j]; + if (ost->source_index == i) { + update_sample_fmt(ist->st->codec, codec, ost->st->codec); + break; + } + } + if (avcodec_open(ist->st->codec, codec) < 0) { snprintf(error, sizeof(error), "Error while opening decoder for input stream #%d.%d", ist->file_index, ist->index); @@ -3179,6 +3230,23 @@ static void opt_input_file(const char *filename) ic->loop_input = loop_input; + /* Set AVCodecContext options so they will be seen by av_find_stream_info() */ + for (i = 0; i < ic->nb_streams; i++) { + AVCodecContext *dec = ic->streams[i]->codec; + switch (dec->codec_type) { + case AVMEDIA_TYPE_AUDIO: + set_context_opts(dec, avcodec_opts[AVMEDIA_TYPE_AUDIO], + AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM, + NULL); + break; + case AVMEDIA_TYPE_VIDEO: + set_context_opts(dec, avcodec_opts[AVMEDIA_TYPE_VIDEO], + AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM, + NULL); + break; + } + } + /* If not enough info to get the stream parameters, we decode the first frames to get it. (used in mpeg case for example) */ ret = av_find_stream_info(ic); @@ -2412,6 +2412,23 @@ static int decode_thread(void *arg) if(genpts) ic->flags |= AVFMT_FLAG_GENPTS; + /* Set AVCodecContext options so they will be seen by av_find_stream_info() */ + for (i = 0; i < ic->nb_streams; i++) { + AVCodecContext *dec = ic->streams[i]->codec; + switch (dec->codec_type) { + case AVMEDIA_TYPE_AUDIO: + set_context_opts(dec, avcodec_opts[AVMEDIA_TYPE_AUDIO], + AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM, + NULL); + break; + case AVMEDIA_TYPE_VIDEO: + set_context_opts(dec, avcodec_opts[AVMEDIA_TYPE_VIDEO], + AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM, + NULL); + break; + } + } + err = av_find_stream_info(ic); if (err < 0) { fprintf(stderr, "%s: could not find codec parameters\n", is->filename); |