diff --git a/doc/APIchanges b/doc/APIchanges index 0d365aa5fd671f0c1fe63f70e12696992236e294..2f4435d9bbf26539d2a4a5c93f67c6f1ffa0bb5a 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -13,6 +13,9 @@ libavutil: 2009-03-08 API changes, most recent first: +2010-12-XX - r26104 - lavformat 52.91.0 - av_find_best_stream() + Add av_find_best_stream to libavformat/avformat.h. + 2010-12-27 - r26103 - lavf 52.90.0 Add AVFMT_NOSTREAMS flag for formats with no streams, like e.g. text metadata. diff --git a/libavformat/avformat.h b/libavformat/avformat.h index f166c090db0059faf7895d48ca243575be9aa64f..c6f282710c6adbbb1108cdc5c1d5824670d2a15c 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -22,7 +22,7 @@ #define AVFORMAT_AVFORMAT_H #define LIBAVFORMAT_VERSION_MAJOR 52 -#define LIBAVFORMAT_VERSION_MINOR 90 +#define LIBAVFORMAT_VERSION_MINOR 91 #define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ @@ -1140,6 +1140,37 @@ AVFormatContext *avformat_alloc_context(void); */ int av_find_stream_info(AVFormatContext *ic); +/** + * Find the "best" stream in the file. + * The best stream is determined according to various heuristics as the most + * likely to be what the user expects. + * If the decoder parameter is non-NULL, av_find_best_stream will find the + * default decoder for the stream's codec; streams for which no decoder can + * be found are ignored. + * + * @param ic media file handle + * @param type stream type: video, audio, subtitles, etc. + * @param wanted_stream_nb user-requested stream number, + * or -1 for automatic selection + * @param related_stream try to find a stream related (eg. in the same + * program) to this one, or -1 if none + * @param decoder_ret if non-NULL, returns the decoder for the + * selected stream + * @param flags flags; none are currently defined + * @return the non-negative stream number in case of success, + * AVERROR_STREAM_NOT_FOUND if no stream with the requested type + * could be found, + * AVERROR_DECODER_NOT_FOUND if streams were found but no decoder + * @note If av_find_best_stream returns successfully and decoder_ret is not + * NULL, then *decoder_ret is guaranteed to be set to a valid AVCodec. + */ +int av_find_best_stream(AVFormatContext *ic, + enum AVMediaType type, + int wanted_stream_nb, + int related_stream, + AVCodec **decoder_ret, + int flags); + /** * Read a transport packet from a media file. * diff --git a/libavformat/utils.c b/libavformat/utils.c index e9a8099c956ff71f1a0e57cc9d75b28c9b2c29c0..6f994a1b707c7712af91950b68f5a949b2f90256 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -2458,6 +2458,67 @@ int av_find_stream_info(AVFormatContext *ic) return ret; } +static AVProgram *find_program_from_stream(AVFormatContext *ic, int s) +{ + int i, j; + + for (i = 0; i < ic->nb_programs; i++) + for (j = 0; j < ic->programs[i]->nb_stream_indexes; j++) + if (ic->programs[i]->stream_index[j] == s) + return ic->programs[i]; + return NULL; +} + +int av_find_best_stream(AVFormatContext *ic, + enum AVMediaType type, + int wanted_stream_nb, + int related_stream, + AVCodec **decoder_ret, + int flags) +{ + int i, nb_streams = ic->nb_streams, stream_number = 0; + int ret = AVERROR_STREAM_NOT_FOUND, best_count = -1; + unsigned *program = NULL; + AVCodec *decoder = NULL, *best_decoder = NULL; + + if (related_stream >= 0 && wanted_stream_nb < 0) { + AVProgram *p = find_program_from_stream(ic, related_stream); + if (p) { + program = p->stream_index; + nb_streams = p->nb_stream_indexes; + } + } + for (i = 0; i < nb_streams; i++) { + AVStream *st = ic->streams[program ? program[i] : i]; + AVCodecContext *avctx = st->codec; + if (avctx->codec_type != type) + continue; + if (wanted_stream_nb >= 0 && stream_number++ != wanted_stream_nb) + continue; + if (decoder_ret) { + decoder = avcodec_find_decoder(ic->streams[i]->codec->codec_id); + if (!decoder) { + if (ret < 0) + ret = AVERROR_DECODER_NOT_FOUND; + continue; + } + } + if (best_count >= st->codec_info_nb_frames) + continue; + best_count = st->codec_info_nb_frames; + ret = i; + best_decoder = decoder; + if (program && i == nb_streams - 1 && ret < 0) { + program = NULL; + nb_streams = ic->nb_streams; + i = 0; /* no related stream found, try again with everything */ + } + } + if (decoder_ret) + *decoder_ret = best_decoder; + return ret; +} + /*******************************************************/ int av_read_play(AVFormatContext *s)