From 62940bb42f39b98c45105b036055dacdbe47a175 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 16 Jun 2011 06:24:54 +0200 Subject: [PATCH 01/20] ffmpeg: initialise encoders earlier. Fixes choosing supported samplerate and framerate. --- ffmpeg.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ffmpeg.c b/ffmpeg.c index 652fbfce32..5b1702edc7 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -2164,6 +2164,8 @@ static int transcode(AVFormatContext **output_files, abort(); } } else { + if (!ost->enc) + ost->enc = avcodec_find_encoder(ost->st->codec->codec_id); switch(codec->codec_type) { case AVMEDIA_TYPE_AUDIO: ost->fifo= av_fifo_alloc(1024); @@ -2175,7 +2177,7 @@ static int transcode(AVFormatContext **output_files, if (icodec->lowres) codec->sample_rate >>= icodec->lowres; } - choose_sample_rate(ost->st, codec->codec); + choose_sample_rate(ost->st, ost->enc); codec->time_base = (AVRational){1, codec->sample_rate}; if (!codec->channels) codec->channels = icodec->channels; @@ -2228,9 +2230,9 @@ static int transcode(AVFormatContext **output_files, if (!ost->frame_rate.num) ost->frame_rate = ist->st->r_frame_rate.num ? ist->st->r_frame_rate : (AVRational){25,1}; - if (codec->codec && codec->codec->supported_framerates && !force_fps) { - int idx = av_find_nearest_q_idx(ost->frame_rate, codec->codec->supported_framerates); - ost->frame_rate = codec->codec->supported_framerates[idx]; + if (ost->enc && ost->enc->supported_framerates && !force_fps) { + int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates); + ost->frame_rate = ost->enc->supported_framerates[idx]; } codec->time_base = (AVRational){ost->frame_rate.den, ost->frame_rate.num}; @@ -2297,8 +2299,6 @@ static int transcode(AVFormatContext **output_files, if (ost->encoding_needed) { AVCodec *codec = ost->enc; AVCodecContext *dec = input_streams[ost->source_index].st->codec; - if (!codec) - codec = avcodec_find_encoder(ost->st->codec->codec_id); if (!codec) { snprintf(error, sizeof(error), "Encoder (codec id %d) not found for output stream #%d.%d", ost->st->codec->codec_id, ost->file_index, ost->index); From 10de86b882f980a7e856a903bcb45a8fa7816cfd Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 15 Jun 2011 08:00:03 +0200 Subject: [PATCH 02/20] ffmpeg: don't abuse a global for passing pixel format from input to output It's broken with multiple files or video streams. --- ffmpeg.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ffmpeg.c b/ffmpeg.c index 5b1702edc7..952707d9eb 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -2192,6 +2192,10 @@ static int transcode(AVFormatContext **output_files, ost->resample_channels = icodec->channels; break; case AVMEDIA_TYPE_VIDEO: + if (codec->pix_fmt == PIX_FMT_NONE) + codec->pix_fmt = icodec->pix_fmt; + choose_pixel_fmt(ost->st, ost->enc); + if (ost->st->codec->pix_fmt == PIX_FMT_NONE) { fprintf(stderr, "Video pixel format is unknown, stream cannot be encoded\n"); ffmpeg_exit(1); @@ -3295,7 +3299,6 @@ static int opt_input_file(const char *opt, const char *filename) set_context_opts(dec, avcodec_opts[AVMEDIA_TYPE_VIDEO], AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM, input_codecs[nb_input_codecs-1]); frame_height = dec->height; frame_width = dec->width; - frame_pix_fmt = dec->pix_fmt; rfps = ic->streams[i]->r_frame_rate.num; rfps_base = ic->streams[i]->r_frame_rate.den; if (dec->lowres) { @@ -3348,6 +3351,7 @@ static int opt_input_file(const char *opt, const char *filename) video_channel = 0; frame_rate = (AVRational){0, 0}; + frame_pix_fmt = PIX_FMT_NONE; audio_sample_rate = 0; audio_channels = 0; @@ -3471,8 +3475,6 @@ static void new_video_stream(AVFormatContext *oc, int file_idx) video_enc->pix_fmt = frame_pix_fmt; st->sample_aspect_ratio = video_enc->sample_aspect_ratio; - choose_pixel_fmt(st, codec); - if (intra_only) video_enc->gop_size = 0; if (video_qscale || same_quality) { From 0b7ccad6bf79cebe5cd8392105276a4ba19d19f9 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 15 Jun 2011 08:00:03 +0200 Subject: [PATCH 03/20] ffmpeg: don't abuse a global for passing frame size from input to output It's broken with multiple files or video streams. --- ffmpeg.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/ffmpeg.c b/ffmpeg.c index 952707d9eb..6a4fb5358f 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -2226,6 +2226,10 @@ static int transcode(AVFormatContext **output_files, #endif codec->bits_per_raw_sample= 0; } + if (!codec->width || !codec->height) { + codec->width = icodec->width; + codec->height = icodec->height; + } ost->resample_height = icodec->height; ost->resample_width = icodec->width; ost->resample_pix_fmt= icodec->pix_fmt; @@ -3297,16 +3301,12 @@ static int opt_input_file(const char *opt, const char *filename) case AVMEDIA_TYPE_VIDEO: input_codecs[nb_input_codecs-1] = avcodec_find_decoder_by_name(video_codec_name); set_context_opts(dec, avcodec_opts[AVMEDIA_TYPE_VIDEO], AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM, input_codecs[nb_input_codecs-1]); - frame_height = dec->height; - frame_width = dec->width; rfps = ic->streams[i]->r_frame_rate.num; rfps_base = ic->streams[i]->r_frame_rate.den; if (dec->lowres) { dec->flags |= CODEC_FLAG_EMU_EDGE; - frame_height >>= dec->lowres; - frame_width >>= dec->lowres; - dec->height = frame_height; - dec->width = frame_width; + dec->height >>= dec->lowres; + dec->width >>= dec->lowres; } if(me_threshold) dec->debug |= FF_DEBUG_MV; @@ -3352,6 +3352,8 @@ static int opt_input_file(const char *opt, const char *filename) video_channel = 0; frame_rate = (AVRational){0, 0}; frame_pix_fmt = PIX_FMT_NONE; + frame_height = 0; + frame_width = 0; audio_sample_rate = 0; audio_channels = 0; @@ -3893,6 +3895,8 @@ static void opt_output_file(const char *filename) set_context_opts(oc, avformat_opts, AV_OPT_FLAG_ENCODING_PARAM, NULL); frame_rate = (AVRational){0, 0}; + frame_width = 0; + frame_height = 0; audio_sample_rate = 0; audio_channels = 0; From 7e83e1c511baf0d02f3af75b6180d6af4d50aa99 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 22 May 2011 12:52:50 +0200 Subject: [PATCH 04/20] AVOptions: add av_opt_set_dict() mapping a dictionary struct to a context. This way the caller can pass all the options in one nice package. --- libavutil/opt.c | 22 ++++++++++++++++++++++ libavutil/opt.h | 17 +++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/libavutil/opt.c b/libavutil/opt.c index 7775bb2af3..55bb6d24f0 100644 --- a/libavutil/opt.c +++ b/libavutil/opt.c @@ -29,6 +29,7 @@ #include "avstring.h" #include "opt.h" #include "eval.h" +#include "dict.h" //FIXME order them and do a bin search const AVOption *av_find_opt(void *v, const char *name, const char *unit, int mask, int flags) @@ -538,6 +539,27 @@ void av_opt_free(void *obj) av_freep((uint8_t *)obj + o->offset); } +int av_opt_set_dict(void *obj, AVDictionary **options) +{ + AVDictionaryEntry *t = NULL; + AVDictionary *tmp = NULL; + int ret = 0; + + while ((t = av_dict_get(*options, "", t, AV_DICT_IGNORE_SUFFIX))) { + ret = av_set_string3(obj, t->key, t->value, 1, NULL); + if (ret == AVERROR_OPTION_NOT_FOUND) + av_dict_set(&tmp, t->key, t->value, 0); + else if (ret < 0) { + av_log(obj, AV_LOG_ERROR, "Error setting option %s to value %s.\n", t->key, t->value); + break; + } + ret = 0; + } + av_dict_free(options); + *options = tmp; + return ret; +} + #ifdef TEST #undef printf diff --git a/libavutil/opt.h b/libavutil/opt.h index 46ad8acce1..ef984d9a9c 100644 --- a/libavutil/opt.h +++ b/libavutil/opt.h @@ -29,6 +29,7 @@ #include "rational.h" #include "avutil.h" +#include "dict.h" enum AVOptionType{ FF_OPT_TYPE_FLAGS, @@ -191,4 +192,20 @@ void av_opt_free(void *obj); */ int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name); +/* + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict(void *obj, struct AVDictionary **options); + #endif /* AVUTIL_OPT_H */ From dc59ec5e79d813228e3dfbc8942a5fe424b399a0 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 22 May 2011 13:25:19 +0200 Subject: [PATCH 05/20] AVOptions: add av_opt_find() as a replacement for av_find_opt. --- cmdutils.c | 6 +++--- ffserver.c | 2 +- libavutil/avutil.h | 3 +++ libavutil/log.h | 7 +++++++ libavutil/opt.c | 30 +++++++++++++++++++++++++----- libavutil/opt.h | 31 +++++++++++++++++++++++++++++++ 6 files changed, 70 insertions(+), 9 deletions(-) diff --git a/cmdutils.c b/cmdutils.c index c73d5a1ca2..9422fc1f03 100644 --- a/cmdutils.c +++ b/cmdutils.c @@ -299,7 +299,7 @@ int opt_default(const char *opt, const char *arg){ int opt_types[]={AV_OPT_FLAG_VIDEO_PARAM, AV_OPT_FLAG_AUDIO_PARAM, 0, AV_OPT_FLAG_SUBTITLE_PARAM, 0}; for(type=0; *avcodec_opts && type= 0; type++){ - const AVOption *o2 = av_find_opt(avcodec_opts[0], opt, NULL, opt_types[type], opt_types[type]); + const AVOption *o2 = av_opt_find(avcodec_opts[0], opt, NULL, opt_types[type], 0); if(o2) ret = av_set_string3(avcodec_opts[type], opt, arg, 1, &o); } @@ -324,13 +324,13 @@ int opt_default(const char *opt, const char *arg){ AVOutputFormat *oformat = NULL; while ((p=av_codec_next(p))){ const AVClass *c = p->priv_class; - if(c && av_find_opt(&c, opt, NULL, 0, 0)) + if(c && av_opt_find(&c, opt, NULL, 0, 0)) break; } if (!p) { while ((oformat = av_oformat_next(oformat))) { const AVClass *c = oformat->priv_class; - if (c && av_find_opt(&c, opt, NULL, 0, 0)) + if (c && av_opt_find(&c, opt, NULL, 0, 0)) break; } } diff --git a/ffserver.c b/ffserver.c index 0f57979c9c..2ac7e6abf9 100644 --- a/ffserver.c +++ b/ffserver.c @@ -3944,7 +3944,7 @@ static int ffserver_opt_default(const char *opt, const char *arg, AVCodecContext *avctx, int type) { int ret = 0; - const AVOption *o = av_find_opt(avctx, opt, NULL, type, type); + const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0); if(o) ret = av_set_string3(avctx, opt, arg, 1, NULL); return ret; diff --git a/libavutil/avutil.h b/libavutil/avutil.h index 0299bdf797..21df460c1f 100644 --- a/libavutil/avutil.h +++ b/libavutil/avutil.h @@ -60,6 +60,9 @@ #ifndef FF_API_GET_BITS_PER_SAMPLE_FMT #define FF_API_GET_BITS_PER_SAMPLE_FMT (LIBAVUTIL_VERSION_MAJOR < 52) #endif +#ifndef FF_API_FIND_OPT +#define FF_API_FIND_OPT (LIBAVUTIL_VERSION_MAJOR < 52) +#endif /** * Return the LIBAVUTIL_VERSION_INT constant. diff --git a/libavutil/log.h b/libavutil/log.h index 1cd9269c43..c823a763ee 100644 --- a/libavutil/log.h +++ b/libavutil/log.h @@ -70,6 +70,13 @@ typedef struct { * can be NULL of course */ int parent_log_context_offset; + + /** + * A function for extended searching, e.g. in possible + * children objects. + */ + const struct AVOption* (*opt_find)(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags); } AVClass; /* av_log API */ diff --git a/libavutil/opt.c b/libavutil/opt.c index 55bb6d24f0..518863a8b8 100644 --- a/libavutil/opt.c +++ b/libavutil/opt.c @@ -31,6 +31,7 @@ #include "eval.h" #include "dict.h" +#if FF_API_FIND_OPT //FIXME order them and do a bin search const AVOption *av_find_opt(void *v, const char *name, const char *unit, int mask, int flags) { @@ -43,6 +44,7 @@ const AVOption *av_find_opt(void *v, const char *name, const char *unit, int mas } return NULL; } +#endif const AVOption *av_next_option(void *obj, const AVOption *last) { @@ -53,7 +55,7 @@ const AVOption *av_next_option(void *obj, const AVOption *last) static int av_set_number2(void *obj, const char *name, double num, int den, int64_t intnum, const AVOption **o_out) { - const AVOption *o= av_find_opt(obj, name, NULL, 0, 0); + const AVOption *o = av_opt_find(obj, name, NULL, 0, 0); void *dst; if (o_out) *o_out= o; @@ -116,7 +118,7 @@ static int hexchar2int(char c) { int av_set_string3(void *obj, const char *name, const char *val, int alloc, const AVOption **o_out) { int ret; - const AVOption *o= av_find_opt(obj, name, NULL, 0, 0); + const AVOption *o = av_opt_find(obj, name, NULL, 0, 0); if (o_out) *o_out = o; if (!o) @@ -163,7 +165,7 @@ int av_set_string3(void *obj, const char *name, const char *val, int alloc, cons buf[i]=0; { - const AVOption *o_named= av_find_opt(obj, buf, o->unit, 0, 0); + const AVOption *o_named = av_opt_find(obj, buf, o->unit, 0, 0); if (o_named && o_named->type == FF_OPT_TYPE_CONST) d= o_named->default_val.dbl; else if (!strcmp(buf, "default")) d= o->default_val.dbl; @@ -228,7 +230,7 @@ const AVOption *av_set_int(void *obj, const char *name, int64_t n) */ const char *av_get_string(void *obj, const char *name, const AVOption **o_out, char *buf, int buf_len) { - const AVOption *o= av_find_opt(obj, name, NULL, 0, 0); + const AVOption *o = av_opt_find(obj, name, NULL, 0, 0); void *dst; uint8_t *bin; int len, i; @@ -261,7 +263,7 @@ const char *av_get_string(void *obj, const char *name, const AVOption **o_out, c static int av_get_number(void *obj, const char *name, const AVOption **o_out, double *num, int *den, int64_t *intnum) { - const AVOption *o= av_find_opt(obj, name, NULL, 0, 0); + const AVOption *o = av_opt_find(obj, name, NULL, 0, 0); void *dst; if (!o || o->offset<=0) goto error; @@ -560,6 +562,24 @@ int av_opt_set_dict(void *obj, AVDictionary **options) return ret; } +const AVOption *av_opt_find(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags) +{ + AVClass *c = *(AVClass**)obj; + const AVOption *o = NULL; + + if (c->opt_find && search_flags & AV_OPT_SEARCH_CHILDREN && + (o = c->opt_find(obj, name, unit, opt_flags, search_flags))) + return o; + + while (o = av_next_option(obj, o)) { + if (!strcmp(o->name, name) && (!unit || (o->unit && !strcmp(o->unit, unit))) && + (o->flags & opt_flags) == opt_flags) + return o; + } + return NULL; +} + #ifdef TEST #undef printf diff --git a/libavutil/opt.h b/libavutil/opt.h index ef984d9a9c..30aa54f5b6 100644 --- a/libavutil/opt.h +++ b/libavutil/opt.h @@ -92,6 +92,7 @@ typedef struct AVOption { const char *unit; } AVOption; +#if FF_API_FIND_OPT /** * Look for an option in obj. Look only for the options which * have the flags set as specified in mask and flags (that is, @@ -103,8 +104,12 @@ typedef struct AVOption { * @param[in] unit the unit of the option to look for, or any if NULL * @return a pointer to the option found, or NULL if no option * has been found + * + * @deprecated use av_opt_find. */ +attribute_deprecated const AVOption *av_find_opt(void *obj, const char *name, const char *unit, int mask, int flags); +#endif /** * Set the field of obj with the given name to value. @@ -208,4 +213,30 @@ int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name) */ int av_opt_set_dict(void *obj, struct AVDictionary **options); +#define AV_OPT_SEARCH_CHILDREN 0x0001 /**< Search in possible children of the + given object first. */ + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return A pointer to the option found, or NULL if no option + * was found. + * + * @note Options found with AV_OPT_SEARCH_CHILDREN flag may not be settable + * directly with av_set_string3(). Use special calls which take an options + * AVDictionary (e.g. avformat_open_input()) to set options found with this + * flag. + */ +const AVOption *av_opt_find(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags); + #endif /* AVUTIL_OPT_H */ From 05e84c95c7f0543553af8f0ebd50fb5604e7e2ff Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 22 May 2011 08:37:25 +0200 Subject: [PATCH 06/20] lavf: add avformat_open_input() as a replacement for av_open_input_* Add support for demuxer private options. --- libavformat/avformat.h | 22 +++++++++ libavformat/options.c | 28 +++++++++++ libavformat/utils.c | 104 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 153 insertions(+), 1 deletion(-) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 2b5b50e381..56a9d57a66 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -730,6 +730,7 @@ typedef struct AVFormatContext { #if FF_API_FLAG_RTP_HINT #define AVFMT_FLAG_RTP_HINT 0x0040 ///< Deprecated, use the -movflags rtphint muxer specific AVOption instead #endif +#define AVFMT_FLAG_CUSTOM_IO 0x0080 ///< The caller has supplied a custom AVIOContext, don't avio_close() it. int loop_input; @@ -1040,6 +1041,27 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, int buf_size, AVFormatParameters *ap); +/** + * Open an input stream and read the header. The codecs are not opened. + * The stream must be closed with av_close_input_file(). + * + * @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context). + * May be a pointer to NULL, in which case an AVFormatContext is allocated by this + * function and written into ps. + * Note that a user-supplied AVFormatContext will be freed on failure. + * @param filename Name of the stream to open. + * @param fmt If non-NULL, this parameter forces a specific input format. + * Otherwise the format is autodetected. + * @param options A dictionary filled with AVFormatContext and demuxer-private options. + * On return this parameter will be destroyed and replaced with a dict containing + * options that were not found. May be NULL. + * + * @return 0 on success, a negative AVERROR on failure. + * + * @note If you want to use custom IO, preallocate the format context and set its pb field. + */ +int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options); + /** * Allocate an AVFormatContext. * avformat_free_context() can be used to free the context and everything diff --git a/libavformat/options.c b/libavformat/options.c index c11f19e687..c2729b75d9 100644 --- a/libavformat/options.c +++ b/libavformat/options.c @@ -33,6 +33,33 @@ static const char* format_to_name(void* ptr) else return "NULL"; } +static const AVOption *opt_find(void *obj, const char *name, const char *unit, int opt_flags, int search_flags) +{ + AVFormatContext *s = obj; + AVInputFormat *ifmt = NULL; + AVOutputFormat *ofmt = NULL; + if (s->priv_data) { + if ((s->iformat && !s->iformat->priv_class) || + (s->oformat && !s->oformat->priv_class)) + return NULL; + return av_opt_find(s->priv_data, name, unit, opt_flags, search_flags); + } + + while ((ifmt = av_iformat_next(ifmt))) { + const AVOption *o; + + if (ifmt->priv_class && (o = av_opt_find(&ifmt->priv_class, name, unit, opt_flags, search_flags))) + return o; + } + while ((ofmt = av_oformat_next(ofmt))) { + const AVOption *o; + + if (ofmt->priv_class && (o = av_opt_find(&ofmt->priv_class, name, unit, opt_flags, search_flags))) + return o; + } + return NULL; +} + #define OFFSET(x) offsetof(AVFormatContext,x) #define DEFAULT 0 //should be NAN but it does not work as it is not a constant in glibc as required by ANSI/ISO C //these names are too long to be readable @@ -72,6 +99,7 @@ static const AVClass av_format_context_class = { .item_name = format_to_name, .option = options, .version = LIBAVUTIL_VERSION_INT, + .opt_find = opt_find, }; static void avformat_get_context_defaults(AVFormatContext *s) diff --git a/libavformat/utils.c b/libavformat/utils.c index 60f4d03e4b..31cdde3edb 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -605,6 +605,107 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, } +/* open input file and probe the format if necessary */ +static int init_input(AVFormatContext *s, const char *filename) +{ + int ret; + AVProbeData pd = {filename, NULL, 0}; + + if (s->pb) { + s->flags |= AVFMT_FLAG_CUSTOM_IO; + if (!s->iformat) + return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, 0); + else if (s->iformat->flags & AVFMT_NOFILE) + return AVERROR(EINVAL); + return 0; + } + + if ( (s->iformat && s->iformat->flags & AVFMT_NOFILE) || + (!s->iformat && (s->iformat = av_probe_input_format(&pd, 0)))) + return 0; + + if ((ret = avio_open(&s->pb, filename, AVIO_FLAG_READ)) < 0) + return ret; + if (s->iformat) + return 0; + return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, 0); +} + +int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options) +{ + AVFormatContext *s = *ps; + int ret = 0; + AVFormatParameters ap = { 0 }; + AVDictionary *tmp = NULL; + + if (!s && !(s = avformat_alloc_context())) + return AVERROR(ENOMEM); + if (fmt) + s->iformat = fmt; + + if (options) + av_dict_copy(&tmp, *options, 0); + + if ((ret = av_opt_set_dict(s, &tmp)) < 0) + goto fail; + + if ((ret = init_input(s, filename)) < 0) + goto fail; + + /* check filename in case an image number is expected */ + if (s->iformat->flags & AVFMT_NEEDNUMBER) { + if (!av_filename_number_test(filename)) { + ret = AVERROR(EINVAL); + goto fail; + } + } + + s->duration = s->start_time = AV_NOPTS_VALUE; + av_strlcpy(s->filename, filename, sizeof(s->filename)); + + /* allocate private data */ + if (s->iformat->priv_data_size > 0) { + if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) { + ret = AVERROR(ENOMEM); + goto fail; + } + if (s->iformat->priv_class) { + *(const AVClass**)s->priv_data = s->iformat->priv_class; + av_opt_set_defaults(s->priv_data); + if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0) + goto fail; + } + } + + /* e.g. AVFMT_NOFILE formats will not have a AVIOContext */ + if (s->pb) + ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC); + + if (s->iformat->read_header) + if ((ret = s->iformat->read_header(s, &ap)) < 0) + goto fail; + + if (s->pb && !s->data_offset) + s->data_offset = avio_tell(s->pb); + + s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; + + if (options) { + av_dict_free(options); + *options = tmp; + } + *ps = s; + return 0; + +fail: + av_dict_free(&tmp); + if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO)) + avio_close(s->pb); + avformat_free_context(s); + *ps = NULL; + return ret; +} + /*******************************************************/ static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt, @@ -2573,7 +2674,8 @@ void avformat_free_context(AVFormatContext *s) void av_close_input_file(AVFormatContext *s) { - AVIOContext *pb = s->iformat->flags & AVFMT_NOFILE ? NULL : s->pb; + AVIOContext *pb = (s->iformat->flags & AVFMT_NOFILE) || (s->flags & AVFMT_FLAG_CUSTOM_IO) ? + NULL : s->pb; av_close_input_stream(s); if (pb) avio_close(pb); From 603b8bc2a109978c8499b06d2556f1433306eca7 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 4 Jun 2011 17:36:30 +0200 Subject: [PATCH 07/20] Deprecate av_open_input_* and remove their uses. Deprecate the last remaining member of AVFormatParameters. --- libavfilter/vsrc_movie.c | 4 +- libavformat/applehttp.c | 9 ++- libavformat/avformat.h | 11 ++- libavformat/avidec.c | 8 +- libavformat/rdt.c | 4 +- libavformat/rtpdec_asf.c | 7 +- libavformat/sapdec.c | 7 +- libavformat/utils.c | 159 ++++++++++++++------------------------- 8 files changed, 88 insertions(+), 121 deletions(-) diff --git a/libavfilter/vsrc_movie.c b/libavfilter/vsrc_movie.c index a26787d561..7556fa2e9e 100644 --- a/libavfilter/vsrc_movie.c +++ b/libavfilter/vsrc_movie.c @@ -91,9 +91,9 @@ static int movie_init(AVFilterContext *ctx) iformat = movie->format_name ? av_find_input_format(movie->format_name) : NULL; movie->format_ctx = NULL; - if ((ret = av_open_input_file(&movie->format_ctx, movie->file_name, iformat, 0, NULL)) < 0) { + if ((ret = avformat_open_input(&movie->format_ctx, movie->file_name, iformat, NULL)) < 0) { av_log(ctx, AV_LOG_ERROR, - "Failed to av_open_input_file '%s'\n", movie->file_name); + "Failed to avformat_open_input '%s'\n", movie->file_name); return ret; } if ((ret = av_find_stream_info(movie->format_ctx)) < 0) diff --git a/libavformat/applehttp.c b/libavformat/applehttp.c index 86e8b5fbce..38f33a24f3 100644 --- a/libavformat/applehttp.c +++ b/libavformat/applehttp.c @@ -473,6 +473,11 @@ static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap) if (v->n_segments == 0) continue; + if (!(v->ctx = avformat_alloc_context())) { + ret = AVERROR(ENOMEM); + goto fail; + } + v->index = i; v->needed = 1; v->parent = s; @@ -491,8 +496,8 @@ static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap) NULL, 0, 0); if (ret < 0) goto fail; - ret = av_open_input_stream(&v->ctx, &v->pb, v->segments[0]->url, - in_fmt, NULL); + v->ctx->pb = &v->pb; + ret = avformat_open_input(&v->ctx, v->segments[0]->url, in_fmt, NULL); if (ret < 0) goto fail; v->stream_offset = stream_offset; diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 56a9d57a66..6c5b9c6e56 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -247,8 +247,8 @@ typedef struct AVFormatParameters { attribute_deprecated unsigned int mpeg2ts_compute_pcr:1; attribute_deprecated unsigned int initial_pause:1; /**< Do not begin to play the stream immediately (RTSP only). */ + attribute_deprecated unsigned int prealloced_context:1; #endif - unsigned int prealloced_context:1; } AVFormatParameters; //! Demuxer will use avio_open, no opened file should be provided by the caller. @@ -1016,11 +1016,13 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size); +#if FF_API_FORMAT_PARAMETERS /** * Allocate all the structures needed to read an input stream. * This does not open the needed codecs for decoding the stream[s]. + * @deprecated use avformat_open_input instead. */ -int av_open_input_stream(AVFormatContext **ic_ptr, +attribute_deprecated int av_open_input_stream(AVFormatContext **ic_ptr, AVIOContext *pb, const char *filename, AVInputFormat *fmt, AVFormatParameters *ap); @@ -1035,11 +1037,14 @@ int av_open_input_stream(AVFormatContext **ic_ptr, * @param ap Additional parameters needed when opening the file * (NULL if default). * @return 0 if OK, AVERROR_xxx otherwise + * + * @deprecated use avformat_open_input instead. */ -int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, +attribute_deprecated int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, AVInputFormat *fmt, int buf_size, AVFormatParameters *ap); +#endif /** * Open an input stream and read the header. The codecs are not opened. diff --git a/libavformat/avidec.c b/libavformat/avidec.c index dacd230613..85fc794362 100644 --- a/libavformat/avidec.c +++ b/libavformat/avidec.c @@ -774,7 +774,11 @@ static int read_gab2_sub(AVStream *st, AVPacket *pkt) { if (!(sub_demuxer = av_probe_input_format2(&pd, 1, &score))) goto error; - if (!av_open_input_stream(&ast->sub_ctx, pb, "", sub_demuxer, NULL)) { + if (!(ast->sub_ctx = avformat_alloc_context())) + goto error; + + ast->sub_ctx->pb = pb; + if (!avformat_open_input(&ast->sub_ctx, "", sub_demuxer, NULL)) { av_read_packet(ast->sub_ctx, &ast->sub_pkt); *st->codec = *ast->sub_ctx->streams[0]->codec; ast->sub_ctx->streams[0]->codec->extradata = NULL; @@ -1334,7 +1338,7 @@ static int avi_read_close(AVFormatContext *s) if (ast) { if (ast->sub_ctx) { av_freep(&ast->sub_ctx->pb); - av_close_input_stream(ast->sub_ctx); + av_close_input_file(ast->sub_ctx); } av_free(ast->sub_buffer); av_free_packet(&ast->sub_pkt); diff --git a/libavformat/rdt.c b/libavformat/rdt.c index bc3c17bd0d..9155cfc480 100644 --- a/libavformat/rdt.c +++ b/libavformat/rdt.c @@ -523,7 +523,7 @@ rdt_new_context (void) { PayloadContext *rdt = av_mallocz(sizeof(PayloadContext)); - av_open_input_stream(&rdt->rmctx, NULL, "", &ff_rdt_demuxer, NULL); + avformat_open_input(&rdt->rmctx, "", &ff_rdt_demuxer, NULL); return rdt; } @@ -539,7 +539,7 @@ rdt_free_context (PayloadContext *rdt) av_freep(&rdt->rmst[i]); } if (rdt->rmctx) - av_close_input_stream(rdt->rmctx); + av_close_input_file(rdt->rmctx); av_freep(&rdt->mlti_data); av_freep(&rdt->rmst); av_free(rdt); diff --git a/libavformat/rtpdec_asf.c b/libavformat/rtpdec_asf.c index ef78426f1f..287025f377 100644 --- a/libavformat/rtpdec_asf.c +++ b/libavformat/rtpdec_asf.c @@ -107,10 +107,13 @@ int ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p) "Failed to fix invalid RTSP-MS/ASF min_pktsize\n"); init_packetizer(&pb, buf, len); if (rt->asf_ctx) { - av_close_input_stream(rt->asf_ctx); + av_close_input_file(rt->asf_ctx); rt->asf_ctx = NULL; } - ret = av_open_input_stream(&rt->asf_ctx, &pb, "", &ff_asf_demuxer, NULL); + if (!(rt->asf_ctx = avformat_alloc_context())) + return AVERROR(ENOMEM); + rt->asf_ctx->pb = &pb; + ret = avformat_open_input(&rt->asf_ctx, "", &ff_asf_demuxer, NULL); if (ret < 0) return ret; av_dict_copy(&s->metadata, rt->asf_ctx->metadata, 0); diff --git a/libavformat/sapdec.c b/libavformat/sapdec.c index 88150fc772..15d772c780 100644 --- a/libavformat/sapdec.c +++ b/libavformat/sapdec.c @@ -52,7 +52,7 @@ static int sap_read_close(AVFormatContext *s) { struct SAPState *sap = s->priv_data; if (sap->sdp_ctx) - av_close_input_stream(sap->sdp_ctx); + av_close_input_file(sap->sdp_ctx); if (sap->ann_fd) ffurl_close(sap->ann_fd); av_freep(&sap->sdp); @@ -156,9 +156,8 @@ static int sap_read_header(AVFormatContext *s, goto fail; } sap->sdp_ctx->max_delay = s->max_delay; - ap->prealloced_context = 1; - ret = av_open_input_stream(&sap->sdp_ctx, &sap->sdp_pb, "temp.sdp", - infmt, ap); + sap->sdp_ctx->pb = &sap->sdp_pb; + ret = avformat_open_input(&sap->sdp_ctx, "temp.sdp", infmt, NULL); if (ret < 0) goto fail; if (sap->sdp_ctx->ctx_flags & AVFMTCTX_NOHEADER) diff --git a/libavformat/utils.c b/libavformat/utils.c index 31cdde3edb..5865495954 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -27,6 +27,7 @@ #include "libavcodec/internal.h" #include "libavutil/opt.h" #include "libavutil/dict.h" +#include "libavutil/pixdesc.h" #include "metadata.h" #include "id3v2.h" #include "libavutil/avstring.h" @@ -388,6 +389,47 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeDa /************************************************************/ /* input media file */ +#if FF_API_FORMAT_PARAMETERS +static AVDictionary *convert_format_parameters(AVFormatParameters *ap) +{ + char buf[1024]; + AVDictionary *opts = NULL; + + if (ap->time_base.num) { + snprintf(buf, sizeof(buf), "%d/%d", ap->time_base.den, ap->time_base.num); + av_dict_set(&opts, "framerate", buf, 0); + } + if (ap->sample_rate) { + snprintf(buf, sizeof(buf), "%d", ap->sample_rate); + av_dict_set(&opts, "sample_rate", buf, 0); + } + if (ap->channels) { + snprintf(buf, sizeof(buf), "%d", ap->channels); + av_dict_set(&opts, "channels", buf, 0); + } + if (ap->width || ap->height) { + snprintf(buf, sizeof(buf), "%dx%d", ap->width, ap->height); + av_dict_set(&opts, "video_size", buf, 0); + } + if (ap->pix_fmt != PIX_FMT_NONE) { + av_dict_set(&opts, "pixel_format", av_get_pix_fmt_name(ap->pix_fmt), 0); + } + if (ap->channel) { + snprintf(buf, sizeof(buf), "%d", ap->channel); + av_dict_set(&opts, "channel", buf, 0); + } + if (ap->standard) { + av_dict_set(&opts, "standard", ap->standard, 0); + } + if (ap->mpeg2ts_compute_pcr) { + av_dict_set(&opts, "mpeg2ts_compute_pcr", "1", 0); + } + if (ap->initial_pause) { + av_dict_set(&opts, "initial_pause", "1", 0); + } + return opts; +} + /** * Open a media file from an IO stream. 'fmt' must be specified. */ @@ -396,6 +438,7 @@ int av_open_input_stream(AVFormatContext **ic_ptr, AVInputFormat *fmt, AVFormatParameters *ap) { int err; + AVDictionary *opts; AVFormatContext *ic; AVFormatParameters default_ap; @@ -403,6 +446,7 @@ int av_open_input_stream(AVFormatContext **ic_ptr, ap=&default_ap; memset(ap, 0, sizeof(default_ap)); } + opts = convert_format_parameters(ap); if(!ap->prealloced_context) ic = avformat_alloc_context(); @@ -412,63 +456,15 @@ int av_open_input_stream(AVFormatContext **ic_ptr, err = AVERROR(ENOMEM); goto fail; } - ic->iformat = fmt; ic->pb = pb; - ic->duration = AV_NOPTS_VALUE; - ic->start_time = AV_NOPTS_VALUE; - av_strlcpy(ic->filename, filename, sizeof(ic->filename)); - /* allocate private data */ - if (fmt->priv_data_size > 0) { - ic->priv_data = av_mallocz(fmt->priv_data_size); - if (!ic->priv_data) { - err = AVERROR(ENOMEM); - goto fail; - } - if (fmt->priv_class) { - *(const AVClass**)ic->priv_data = fmt->priv_class; - av_opt_set_defaults(ic->priv_data); - } - } else { - ic->priv_data = NULL; - } + err = avformat_open_input(ic_ptr, filename, fmt, &opts); - // e.g. AVFMT_NOFILE formats will not have a AVIOContext - if (ic->pb) - ff_id3v2_read(ic, ID3v2_DEFAULT_MAGIC); - - if (ic->iformat->read_header) { - err = ic->iformat->read_header(ic, ap); - if (err < 0) - goto fail; - } - - if (pb && !ic->data_offset) - ic->data_offset = avio_tell(ic->pb); - - ic->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; - - *ic_ptr = ic; - return 0; - fail: - if (ic) { - int i; - av_freep(&ic->priv_data); - for(i=0;inb_streams;i++) { - AVStream *st = ic->streams[i]; - if (st) { - av_free(st->priv_data); - av_free(st->codec->extradata); - av_free(st->codec); - av_free(st->info); - } - av_free(st); - } - } - av_free(ic); - *ic_ptr = NULL; +fail: + av_dict_free(&opts); return err; } +#endif /** size of probe buffer, for guessing file type from file contents */ #define PROBE_BUF_MIN 2048 @@ -541,69 +537,24 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, return ret; } +#if FF_API_FORMAT_PARAMETERS int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, AVInputFormat *fmt, int buf_size, AVFormatParameters *ap) { int err; - AVProbeData probe_data, *pd = &probe_data; - AVIOContext *pb = NULL; - void *logctx= ap && ap->prealloced_context ? *ic_ptr : NULL; + AVDictionary *opts = convert_format_parameters(ap); - pd->filename = ""; - if (filename) - pd->filename = filename; - pd->buf = NULL; - pd->buf_size = 0; + if (!ap->prealloced_context) + *ic_ptr = NULL; - if (!fmt) { - /* guess format if no file can be opened */ - fmt = av_probe_input_format(pd, 0); - } + err = avformat_open_input(ic_ptr, filename, fmt, &opts); - /* Do not open file if the format does not need it. XXX: specific - hack needed to handle RTSP/TCP */ - if (!fmt || !(fmt->flags & AVFMT_NOFILE)) { - /* if no file needed do not try to open one */ - if ((err=avio_open(&pb, filename, AVIO_FLAG_READ)) < 0) { - goto fail; - } - if (buf_size > 0) { - ffio_set_buf_size(pb, buf_size); - } - if (!fmt && (err = av_probe_input_buffer(pb, &fmt, filename, logctx, 0, logctx ? (*ic_ptr)->probesize : 0)) < 0) { - goto fail; - } - } - - /* if still no format found, error */ - if (!fmt) { - err = AVERROR_INVALIDDATA; - goto fail; - } - - /* check filename in case an image number is expected */ - if (fmt->flags & AVFMT_NEEDNUMBER) { - if (!av_filename_number_test(filename)) { - err = AVERROR(EINVAL); - goto fail; - } - } - err = av_open_input_stream(ic_ptr, pb, filename, fmt, ap); - if (err) - goto fail; - return 0; - fail: - av_freep(&pd->buf); - if (pb) - avio_close(pb); - if (ap && ap->prealloced_context) - av_free(*ic_ptr); - *ic_ptr = NULL; + av_dict_free(&opts); return err; - } +#endif /* open input file and probe the format if necessary */ static int init_input(AVFormatContext *s, const char *filename) From 25de5958c8fd727777ebf8c4f7a9df6f9b8eb82d Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 22 May 2011 13:53:33 +0200 Subject: [PATCH 08/20] lavf: add avformat_write_header() as a replacement for av_write_header(). It supports more convenient setting of AVOptions. --- libavformat/avformat.h | 30 ++++++++++++++++-- libavformat/rtpenc_chain.c | 2 +- libavformat/utils.c | 63 ++++++++++++++++++++++++++++++-------- 3 files changed, 80 insertions(+), 15 deletions(-) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 6c5b9c6e56..9abc9c51a4 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -1322,7 +1322,12 @@ int64_t av_gen_search(AVFormatContext *s, int stream_index, /** * media file output */ -int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap); +#if FF_API_FORMAT_PARAMETERS +/** + * @deprecated pass the options to avformat_write_header directly. + */ +attribute_deprecated int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap); +#endif /** * Split a URL string into components. @@ -1350,6 +1355,24 @@ void av_url_split(char *proto, int proto_size, char *path, int path_size, const char *url); +/** + * Allocate the stream private data and write the stream header to + * an output media file. + * + * @param s Media file handle, must be allocated with avformat_alloc_context(). + * Its oformat field must be set to the desired output format; + * Its pb field must be set to an already openened AVIOContext. + * @param options An AVDictionary filled with AVFormatContext and muxer-private options. + * On return this parameter will be destroyed and replaced with a dict containing + * options that were not found. May be NULL. + * + * @return 0 on success, negative AVERROR on failure. + * + * @see av_opt_find, av_dict_set, avio_open, av_oformat_next. + */ +int avformat_write_header(AVFormatContext *s, AVDictionary **options); + +#if FF_API_FORMAT_PARAMETERS /** * Allocate the stream private data and write the stream header to an * output media file. @@ -1358,8 +1381,11 @@ void av_url_split(char *proto, int proto_size, * * @param s media file handle * @return 0 if OK, AVERROR_xxx on error + * + * @deprecated use avformat_write_header. */ -int av_write_header(AVFormatContext *s); +attribute_deprecated int av_write_header(AVFormatContext *s); +#endif /** * Write a packet to an output media file. diff --git a/libavformat/rtpenc_chain.c b/libavformat/rtpenc_chain.c index 87c1688dfc..0fb47f6234 100644 --- a/libavformat/rtpenc_chain.c +++ b/libavformat/rtpenc_chain.c @@ -66,7 +66,7 @@ AVFormatContext *ff_rtp_chain_mux_open(AVFormatContext *s, AVStream *st, ffio_fdopen(&rtpctx->pb, handle); } else ffio_open_dyn_packet_buf(&rtpctx->pb, packet_size); - ret = av_write_header(rtpctx); + ret = avformat_write_header(rtpctx, NULL); if (ret) { if (handle) { diff --git a/libavformat/utils.c b/libavformat/utils.c index 5865495954..e3485e6ffa 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -2733,6 +2733,7 @@ AVChapter *ff_new_chapter(AVFormatContext *s, int id, AVRational time_base, int6 /************************************************************/ /* output media file */ +#if FF_API_FORMAT_PARAMETERS int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap) { int ret; @@ -2755,6 +2756,7 @@ int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap) } return 0; } +#endif static int validate_codec_tag(AVFormatContext *s, AVStream *st) { @@ -2789,15 +2791,29 @@ static int validate_codec_tag(AVFormatContext *s, AVStream *st) return 1; } +#if FF_API_FORMAT_PARAMETERS int av_write_header(AVFormatContext *s) { - int ret, i; + return avformat_write_header(s, NULL); +} +#endif + +int avformat_write_header(AVFormatContext *s, AVDictionary **options) +{ + int ret = 0, i; AVStream *st; + AVDictionary *tmp = NULL; + + if (options) + av_dict_copy(&tmp, *options, 0); + if ((ret = av_opt_set_dict(s, &tmp)) < 0) + goto fail; // some sanity checks if (s->nb_streams == 0 && !(s->oformat->flags & AVFMT_NOSTREAMS)) { av_log(s, AV_LOG_ERROR, "no streams\n"); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto fail; } for(i=0;inb_streams;i++) { @@ -2807,7 +2823,8 @@ int av_write_header(AVFormatContext *s) case AVMEDIA_TYPE_AUDIO: if(st->codec->sample_rate<=0){ av_log(s, AV_LOG_ERROR, "sample rate not set\n"); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto fail; } if(!st->codec->block_align) st->codec->block_align = st->codec->channels * @@ -2816,15 +2833,18 @@ int av_write_header(AVFormatContext *s) case AVMEDIA_TYPE_VIDEO: if(st->codec->time_base.num<=0 || st->codec->time_base.den<=0){ //FIXME audio too? av_log(s, AV_LOG_ERROR, "time base not set\n"); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto fail; } if((st->codec->width<=0 || st->codec->height<=0) && !(s->oformat->flags & AVFMT_NODIMENSIONS)){ av_log(s, AV_LOG_ERROR, "dimensions not set\n"); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto fail; } if(av_cmp_q(st->sample_aspect_ratio, st->codec->sample_aspect_ratio)){ av_log(s, AV_LOG_ERROR, "Aspect ratio mismatch between encoder and muxer layer\n"); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto fail; } break; } @@ -2841,7 +2861,8 @@ int av_write_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "Tag %s/0x%08x incompatible with output codec id '%d'\n", tagbuf, st->codec->codec_tag, st->codec->codec_id); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } }else st->codec->codec_tag= av_codec_get_tag(s->oformat->codec_tag, st->codec->codec_id); @@ -2854,8 +2875,16 @@ int av_write_header(AVFormatContext *s) if (!s->priv_data && s->oformat->priv_data_size > 0) { s->priv_data = av_mallocz(s->oformat->priv_data_size); - if (!s->priv_data) - return AVERROR(ENOMEM); + if (!s->priv_data) { + ret = AVERROR(ENOMEM); + goto fail; + } + if (s->oformat->priv_class) { + *(const AVClass**)s->priv_data= s->oformat->priv_class; + av_opt_set_defaults(s->priv_data); + if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0) + goto fail; + } } /* set muxer identification string */ @@ -2866,7 +2895,7 @@ int av_write_header(AVFormatContext *s) if(s->oformat->write_header){ ret = s->oformat->write_header(s); if (ret < 0) - return ret; + goto fail; } /* init PTS generation */ @@ -2885,12 +2914,22 @@ int av_write_header(AVFormatContext *s) break; } if (den != AV_NOPTS_VALUE) { - if (den <= 0) - return AVERROR_INVALIDDATA; + if (den <= 0) { + ret = AVERROR_INVALIDDATA; + goto fail; + } av_frac_init(&st->pts, 0, 0, den); } } + + if (options) { + av_dict_free(options); + *options = tmp; + } return 0; +fail: + av_dict_free(&tmp); + return ret; } //FIXME merge with compute_pkt_fields From 1b9b37b8a416e77b4c6425dcdcee21cf8a1f5d67 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 4 Jun 2011 18:43:05 +0200 Subject: [PATCH 09/20] dict: add AV_DICT_APPEND flag. --- libavutil/dict.c | 13 ++++++++++++- libavutil/dict.h | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/libavutil/dict.c b/libavutil/dict.c index 56f1513d32..3ea7e55b30 100644 --- a/libavutil/dict.c +++ b/libavutil/dict.c @@ -19,6 +19,7 @@ */ #include +#include "avstring.h" #include "dict.h" #include "internal.h" #include "mem.h" @@ -51,6 +52,7 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags { AVDictionary *m = *pm; AVDictionaryEntry *tag = av_dict_get(m, key, NULL, flags); + char *oldval = NULL; if(!m) m = *pm = av_mallocz(sizeof(*m)); @@ -58,7 +60,10 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags if(tag) { if (flags & AV_DICT_DONT_OVERWRITE) return 0; - av_free(tag->value); + if (flags & AV_DICT_APPEND) + oldval = tag->value; + else + av_free(tag->value); av_free(tag->key); *tag = m->elems[--m->count]; } else { @@ -75,6 +80,12 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags m->elems[m->count].key = av_strdup(key ); if (flags & AV_DICT_DONT_STRDUP_VAL) { m->elems[m->count].value = value; + } else if (oldval && flags & AV_DICT_APPEND) { + int len = strlen(oldval) + strlen(value) + 1; + if (!(oldval = av_realloc(oldval, len))) + return AVERROR(ENOMEM); + av_strlcat(oldval, value, len); + m->elems[m->count].value = oldval; } else m->elems[m->count].value = av_strdup(value); m->count++; diff --git a/libavutil/dict.h b/libavutil/dict.h index bfd7f2682c..ff24b36f81 100644 --- a/libavutil/dict.h +++ b/libavutil/dict.h @@ -29,6 +29,8 @@ #define AV_DICT_DONT_STRDUP_KEY 4 #define AV_DICT_DONT_STRDUP_VAL 8 #define AV_DICT_DONT_OVERWRITE 16 ///< Don't overwrite existing entries. +#define AV_DICT_APPEND 32 /**< If the entry already exists, append to it. Note that no + delimiter is added, the strings are simply concatenated. */ typedef struct { char *key; From 9ba38229e5bd0cf6201a8206b2d8be6335f45f46 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 25 May 2011 16:42:41 +0200 Subject: [PATCH 10/20] cmdutils: add opt_default2(). It stores options in a dictionary to be passed to new open calls. It will replace opt_default once all the pieces are in place. --- cmdutils.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- cmdutils.h | 1 + 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/cmdutils.c b/cmdutils.c index 9422fc1f03..943a77c82c 100644 --- a/cmdutils.c +++ b/cmdutils.c @@ -38,6 +38,7 @@ #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" #include "libavutil/eval.h" +#include "libavutil/dict.h" #include "libavutil/opt.h" #include "cmdutils.h" #include "version.h" @@ -54,6 +55,7 @@ static int opt_name_count; AVCodecContext *avcodec_opts[AVMEDIA_TYPE_NB]; AVFormatContext *avformat_opts; struct SwsContext *sws_opts; +AVDictionary *format_opts, *video_opts, *audio_opts, *sub_opts; static const int this_year = 2011; @@ -90,6 +92,10 @@ void uninit_opts(void) av_freep(&opt_names); av_freep(&opt_values); opt_name_count = 0; + av_dict_free(&format_opts); + av_dict_free(&video_opts); + av_dict_free(&audio_opts); + av_dict_free(&sub_opts); } void log_callback_help(void* ptr, int level, const char* fmt, va_list vl) @@ -292,6 +298,43 @@ unknown_opt: } } +#define FLAGS (o->type == FF_OPT_TYPE_FLAGS) ? AV_DICT_APPEND : 0 +#define SET_PREFIXED_OPTS(ch, flag, output) \ + if (opt[0] == ch && avcodec_opts[0] && (o = av_opt_find(avcodec_opts[0], opt+1, NULL, flag, 0)))\ + av_dict_set(&output, opt+1, arg, FLAGS); +static int opt_default2(const char *opt, const char *arg) +{ + const AVOption *o; + if ((o = av_opt_find(avcodec_opts[0], opt, NULL, 0, AV_OPT_SEARCH_CHILDREN))) { + if (o->flags & AV_OPT_FLAG_VIDEO_PARAM) + av_dict_set(&video_opts, opt, arg, FLAGS); + if (o->flags & AV_OPT_FLAG_AUDIO_PARAM) + av_dict_set(&audio_opts, opt, arg, FLAGS); + if (o->flags & AV_OPT_FLAG_SUBTITLE_PARAM) + av_dict_set(&sub_opts, opt, arg, FLAGS); + } else if ((o = av_opt_find(avformat_opts, opt, NULL, 0, AV_OPT_SEARCH_CHILDREN))) + av_dict_set(&format_opts, opt, arg, FLAGS); + else if ((o = av_opt_find(sws_opts, opt, NULL, 0, AV_OPT_SEARCH_CHILDREN))) { + // XXX we only support sws_flags, not arbitrary sws options + int ret = av_set_string3(sws_opts, opt, arg, 1, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error setting option %s.\n", opt); + return ret; + } + } + + if (!o) { + SET_PREFIXED_OPTS('v', AV_OPT_FLAG_VIDEO_PARAM, video_opts) + SET_PREFIXED_OPTS('a', AV_OPT_FLAG_AUDIO_PARAM, audio_opts) + SET_PREFIXED_OPTS('s', AV_OPT_FLAG_SUBTITLE_PARAM, sub_opts) + } + + if (o) + return 0; + fprintf(stderr, "Unrecognized option '%s'\n", opt); + return AVERROR_OPTION_NOT_FOUND; +} + int opt_default(const char *opt, const char *arg){ int type; int ret= 0; @@ -334,12 +377,11 @@ int opt_default(const char *opt, const char *arg){ break; } } - if(!p && !oformat){ - fprintf(stderr, "Unrecognized option '%s'\n", opt); - exit(1); - } } + if ((ret = opt_default2(opt, arg)) < 0) + return ret; + // av_log(NULL, AV_LOG_ERROR, "%s:%s: %f 0x%0X\n", opt, arg, av_get_double(avcodec_opts, opt, NULL), (int)av_get_int(avcodec_opts, opt, NULL)); //FIXME we should always use avcodec_opts, ... for storing options so there will not be any need to keep track of what i set over this diff --git a/cmdutils.h b/cmdutils.h index e231b1ff84..02fcea4426 100644 --- a/cmdutils.h +++ b/cmdutils.h @@ -43,6 +43,7 @@ extern const char **opt_names; extern AVCodecContext *avcodec_opts[AVMEDIA_TYPE_NB]; extern AVFormatContext *avformat_opts; extern struct SwsContext *sws_opts; +extern AVDictionary *format_opts, *video_opts, *audio_opts, *sub_opts; /** * Initialize the cmdutils option system, in particular From d0e142bb68fdc817fb84f2395ae416d43ca141ce Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 9 Jun 2011 10:58:23 +0200 Subject: [PATCH 11/20] ffplay: use new avformat_open_* API. --- ffplay.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/ffplay.c b/ffplay.c index 5700883828..c9891d3cdc 100644 --- a/ffplay.c +++ b/ffplay.c @@ -27,6 +27,7 @@ #include "libavutil/colorspace.h" #include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" +#include "libavutil/dict.h" #include "libavutil/parseutils.h" #include "libavutil/samplefmt.h" #include "libavformat/avformat.h" @@ -2309,15 +2310,13 @@ static int decode_interrupt_cb(void) static int decode_thread(void *arg) { VideoState *is = arg; - AVFormatContext *ic; + AVFormatContext *ic = NULL; int err, i, ret; int st_index[AVMEDIA_TYPE_NB]; AVPacket pkt1, *pkt = &pkt1; - AVFormatParameters params, *ap = ¶ms; int eof=0; int pkt_in_play_range = 0; - - ic = avformat_alloc_context(); + AVDictionaryEntry *t; memset(st_index, -1, sizeof(st_index)); is->video_stream = -1; @@ -2327,22 +2326,17 @@ static int decode_thread(void *arg) global_video_state = is; avio_set_interrupt_cb(decode_interrupt_cb); - memset(ap, 0, sizeof(*ap)); - - ap->prealloced_context = 1; - ap->width = frame_width; - ap->height= frame_height; - ap->time_base= (AVRational){1, 25}; - ap->pix_fmt = frame_pix_fmt; - - set_context_opts(ic, avformat_opts, AV_OPT_FLAG_DECODING_PARAM, NULL); - - err = av_open_input_file(&ic, is->filename, is->iformat, 0, ap); + err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts); if (err < 0) { print_error(is->filename, err); ret = -1; goto fail; } + if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { + av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key); + ret = AVERROR_OPTION_NOT_FOUND; + goto fail; + } is->ic = ic; if(genpts) From e0518705c8f575488a50407eee3edcc94c905973 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 9 Jun 2011 10:58:23 +0200 Subject: [PATCH 12/20] ffprobe: use new avformat_open_* API. --- ffprobe.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ffprobe.c b/ffprobe.c index e00790f54b..711a17246d 100644 --- a/ffprobe.c +++ b/ffprobe.c @@ -262,15 +262,18 @@ static void show_format(AVFormatContext *fmt_ctx) static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename) { int err, i; - AVFormatContext *fmt_ctx; + AVFormatContext *fmt_ctx = NULL; + AVDictionaryEntry *t; - fmt_ctx = avformat_alloc_context(); - set_context_opts(fmt_ctx, avformat_opts, AV_OPT_FLAG_DECODING_PARAM, NULL); - - if ((err = av_open_input_file(&fmt_ctx, filename, iformat, 0, NULL)) < 0) { + if ((err = avformat_open_input(&fmt_ctx, filename, iformat, &format_opts)) < 0) { print_error(filename, err); return err; } + if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { + av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key); + return AVERROR_OPTION_NOT_FOUND; + } + /* fill the streams in the format context */ if ((err = av_find_stream_info(fmt_ctx)) < 0) { From 50f2dfad679747d417879d6b49c929286aff69b1 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 9 Jun 2011 10:58:23 +0200 Subject: [PATCH 13/20] ffserver: use new avformat_open_* API. --- ffserver.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/ffserver.c b/ffserver.c index 2ac7e6abf9..65a97b20cc 100644 --- a/ffserver.c +++ b/ffserver.c @@ -205,7 +205,7 @@ typedef struct FFStream { char filename[1024]; /* stream filename */ struct FFStream *feed; /* feed we are using (can be null if coming from file) */ - AVFormatParameters *ap_in; /* input parameters */ + AVDictionary *in_opts; /* input parameters */ AVInputFormat *ifmt; /* if non NULL, force input format */ AVOutputFormat *fmt; IPAddressACL *acl; @@ -2126,7 +2126,7 @@ static int open_input_stream(HTTPContext *c, const char *info) { char buf[128]; char input_filename[1024]; - AVFormatContext *s; + AVFormatContext *s = NULL; int buf_size, i, ret; int64_t stream_pos; @@ -2157,8 +2157,7 @@ static int open_input_stream(HTTPContext *c, const char *info) return -1; /* open stream */ - if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt, - buf_size, c->stream->ap_in)) < 0) { + if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) { http_log("could not open %s: %d\n", input_filename, ret); return -1; } @@ -2268,8 +2267,7 @@ static int http_prepare_data(HTTPContext *c) c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE); c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE); - av_set_parameters(&c->fmt_ctx, NULL); - if (av_write_header(&c->fmt_ctx) < 0) { + if (avformat_write_header(&c->fmt_ctx, NULL) < 0) { http_log("Error writing output header\n"); return -1; } @@ -2709,11 +2707,14 @@ static int http_receive_data(HTTPContext *c) } } else { /* We have a header in our hands that contains useful data */ - AVFormatContext *s = NULL; + AVFormatContext *s = avformat_alloc_context(); AVIOContext *pb; AVInputFormat *fmt_in; int i; + if (!s) + goto fail; + /* use feed output format name to find corresponding input format */ fmt_in = av_find_input_format(feed->fmt->name); if (!fmt_in) @@ -2723,7 +2724,8 @@ static int http_receive_data(HTTPContext *c) 0, NULL, NULL, NULL, NULL); pb->seekable = 0; - if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) { + s->pb = pb; + if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) { av_free(pb); goto fail; } @@ -3442,8 +3444,7 @@ static int rtp_new_av_stream(HTTPContext *c, /* XXX: close stream */ goto fail; } - av_set_parameters(ctx, NULL); - if (av_write_header(ctx) < 0) { + if (avformat_write_header(ctx, NULL) < 0) { fail: if (h) url_close(h); @@ -3597,28 +3598,25 @@ static void extract_mpeg4_header(AVFormatContext *infile) static void build_file_streams(void) { FFStream *stream, *stream_next; - AVFormatContext *infile; int i, ret; /* gather all streams */ for(stream = first_stream; stream != NULL; stream = stream_next) { + AVFormatContext *infile = NULL; stream_next = stream->next; if (stream->stream_type == STREAM_TYPE_LIVE && !stream->feed) { /* the stream comes from a file */ /* try to open the file */ /* open stream */ - stream->ap_in = av_mallocz(sizeof(AVFormatParameters)); if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) { /* specific case : if transport stream output to RTP, we use a raw transport stream reader */ - stream->ap_in->mpeg2ts_raw = 1; - stream->ap_in->mpeg2ts_compute_pcr = 1; + av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0); } http_log("Opening file '%s'\n", stream->feed_filename); - if ((ret = av_open_input_file(&infile, stream->feed_filename, - stream->ifmt, 0, stream->ap_in)) < 0) { + if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) { http_log("Could not open '%s': %d\n", stream->feed_filename, ret); /* remove stream (no need to spend more time on it) */ fail: @@ -3678,10 +3676,10 @@ static void build_feed_streams(void) if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) { /* See if it matches */ - AVFormatContext *s; + AVFormatContext *s = NULL; int matches = 0; - if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) { + if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) { /* Now see if it matches */ if (s->nb_streams == feed->nb_streams) { matches = 1; @@ -3767,8 +3765,7 @@ static void build_feed_streams(void) s->oformat = feed->fmt; s->nb_streams = feed->nb_streams; s->streams = feed->streams; - av_set_parameters(s, NULL); - if (av_write_header(s) < 0) { + if (avformat_write_header(s, NULL) < 0) { http_log("Container doesn't supports the required parameters\n"); exit(1); } From 8035f429684e368fe54af8ccedc2d4776a2d6154 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 9 Jun 2011 10:58:23 +0200 Subject: [PATCH 14/20] ffmpeg: use new avformat_open_* API. --- ffmpeg.c | 77 ++++++++++++++++++++++++++++++------------------- tests/fate2.mak | 2 +- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/ffmpeg.c b/ffmpeg.c index 6a4fb5358f..91783708cf 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -113,6 +113,7 @@ static int nb_input_codecs = 0; static int nb_input_files_ts_scale[MAX_FILES] = {0}; static AVFormatContext *output_files[MAX_FILES]; +static AVDictionary *output_opts[MAX_FILES]; static int nb_output_files = 0; static AVStreamMap *stream_maps = NULL; @@ -465,6 +466,7 @@ static int ffmpeg_exit(int ret) avio_close(s->pb); avformat_free_context(s); av_free(output_streams_for_file[i]); + av_dict_free(&output_opts[i]); } for(i=0;ikey); + ffmpeg_exit(1); + } +} + /* similar to ff_dynarray_add() and av_fast_realloc() */ static void *grow_array(void *array, int elem_size, int *size, int new_size) { @@ -666,10 +677,10 @@ static AVOutputStream *new_output_stream(AVFormatContext *oc, int file_idx) static int read_ffserver_streams(AVFormatContext *s, const char *filename) { int i, err; - AVFormatContext *ic; + AVFormatContext *ic = NULL; int nopts = 0; - err = av_open_input_file(&ic, filename, NULL, FFM_PACKET_SIZE, NULL); + err = avformat_open_input(&ic, filename, NULL, NULL); if (err < 0) return err; /* copy stream format */ @@ -2470,11 +2481,12 @@ static int transcode(AVFormatContext **output_files, /* open files and write file headers */ for(i=0;ioformat->name, "rtp")) { want_sdp = 0; } @@ -3148,10 +3160,10 @@ static enum CodecID find_codec_or_die(const char *name, int type, int encoder, i static int opt_input_file(const char *opt, const char *filename) { AVFormatContext *ic; - AVFormatParameters params, *ap = ¶ms; AVInputFormat *file_iformat = NULL; int err, i, ret, rfps, rfps_base; int64_t timestamp; + uint8_t buf[128]; if (last_asked_format) { if (!(file_iformat = av_find_input_format(last_asked_format))) { @@ -3173,21 +3185,24 @@ static int opt_input_file(const char *opt, const char *filename) print_error(filename, AVERROR(ENOMEM)); ffmpeg_exit(1); } - - memset(ap, 0, sizeof(*ap)); - ap->prealloced_context = 1; - ap->sample_rate = audio_sample_rate; - ap->channels = audio_channels; - ap->time_base.den = frame_rate.num; - ap->time_base.num = frame_rate.den; - ap->width = frame_width; - ap->height = frame_height; - ap->pix_fmt = frame_pix_fmt; - // ap->sample_fmt = audio_sample_fmt; //FIXME:not implemented in libavformat - ap->channel = video_channel; - ap->standard = video_standard; - - set_context_opts(ic, avformat_opts, AV_OPT_FLAG_DECODING_PARAM, NULL); + if (audio_sample_rate) { + snprintf(buf, sizeof(buf), "%d", audio_sample_rate); + av_dict_set(&format_opts, "sample_rate", buf, 0); + } + if (audio_channels) { + snprintf(buf, sizeof(buf), "%d", audio_channels); + av_dict_set(&format_opts, "channels", buf, 0); + } + if (frame_rate.num) { + snprintf(buf, sizeof(buf), "%d/%d", frame_rate.num, frame_rate.den); + av_dict_set(&format_opts, "framerate", buf, 0); + } + if (frame_width && frame_height) { + snprintf(buf, sizeof(buf), "%dx%d", frame_width, frame_height); + av_dict_set(&format_opts, "video_size", buf, 0); + } + if (frame_pix_fmt != PIX_FMT_NONE) + av_dict_set(&format_opts, "pixel_format", av_get_pix_fmt_name(frame_pix_fmt), 0); ic->video_codec_id = find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0, @@ -3201,11 +3216,13 @@ static int opt_input_file(const char *opt, const char *filename) ic->flags |= AVFMT_FLAG_NONBLOCK; /* open the input file with generic libav function */ - err = av_open_input_file(&ic, filename, file_iformat, 0, ap); + err = avformat_open_input(&ic, filename, file_iformat, &format_opts); if (err < 0) { print_error(filename, err); ffmpeg_exit(1); } + assert_avoptions(format_opts); + if(opt_programid) { int i, j; int found=0; @@ -3760,7 +3777,6 @@ static void opt_output_file(const char *filename) AVFormatContext *oc; int err, use_video, use_audio, use_subtitle, use_data; int input_has_video, input_has_audio, input_has_subtitle, input_has_data; - AVFormatParameters params, *ap = ¶ms; AVOutputFormat *file_oformat; if (!strcmp(filename, "-")) @@ -3841,6 +3857,7 @@ static void opt_output_file(const char *filename) av_dict_free(&metadata); } + av_dict_copy(&output_opts[nb_output_files], format_opts, 0); output_files[nb_output_files++] = oc; /* check filename in case of an image number is expected */ @@ -3880,20 +3897,11 @@ static void opt_output_file(const char *filename) } } - memset(ap, 0, sizeof(*ap)); - if (av_set_parameters(oc, ap) < 0) { - fprintf(stderr, "%s: Invalid encoding parameters\n", - oc->filename); - ffmpeg_exit(1); - } - oc->preload= (int)(mux_preload*AV_TIME_BASE); oc->max_delay= (int)(mux_max_delay*AV_TIME_BASE); oc->loop_output = loop_output; oc->flags |= AVFMT_FLAG_NONBLOCK; - set_context_opts(oc, avformat_opts, AV_OPT_FLAG_ENCODING_PARAM, NULL); - frame_rate = (AVRational){0, 0}; frame_width = 0; frame_height = 0; @@ -3988,6 +3996,7 @@ static void show_help(void) { AVCodec *c; AVOutputFormat *oformat = NULL; + AVInputFormat *iformat = NULL; av_log_set_callback(log_callback_help); show_usage(); @@ -4038,6 +4047,14 @@ static void show_help(void) } } + /* individual demuxer options */ + while ((iformat = av_iformat_next(iformat))) { + if (iformat->priv_class) { + av_opt_show2(&iformat->priv_class, NULL, AV_OPT_FLAG_DECODING_PARAM, 0); + printf("\n"); + } + } + av_opt_show2(sws_opts, NULL, AV_OPT_FLAG_ENCODING_PARAM|AV_OPT_FLAG_DECODING_PARAM, 0); } diff --git a/tests/fate2.mak b/tests/fate2.mak index 066f9ef583..b4139f35f7 100644 --- a/tests/fate2.mak +++ b/tests/fate2.mak @@ -165,7 +165,7 @@ fate-wmapro-2ch: CMP = oneoff fate-wmapro-2ch: REF = $(SAMPLES)/wmapro/Beethovens_9th-1_small.pcm FATE_TESTS += fate-ansi -fate-ansi: CMD = framecrc -ar 44100 -i $(SAMPLES)/ansi/TRE-IOM5.ANS -pix_fmt rgb24 +fate-ansi: CMD = framecrc -chars_per_frame 44100 -i $(SAMPLES)/ansi/TRE-IOM5.ANS -pix_fmt rgb24 FATE_TESTS += fate-wmv8-drm # discard last packet to avoid fails due to overread of VC-1 decoder From 55ba12e3009fd6c8f78102f7c747496d500d0bac Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 15 Jun 2011 07:34:12 +0200 Subject: [PATCH 15/20] ffmpeg: deprecate -vc and -tvstd They've been replaced by demuxer private options. --- ffmpeg.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/ffmpeg.c b/ffmpeg.c index 91783708cf..b28408741c 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -213,9 +213,6 @@ static int copy_initial_nonkeyframes = 0; static int rate_emu = 0; -static int video_channel = 0; -static char *video_standard; - static int audio_volume = 256; static int exit_on_error = 0; @@ -493,8 +490,6 @@ static int ffmpeg_exit(int ret) av_free(subtitle_codec_name); av_free(data_codec_name); - av_free(video_standard); - uninit_opts(); av_free(audio_buf); av_free(audio_out); @@ -2922,13 +2917,15 @@ static int opt_audio_channels(const char *opt, const char *arg) static int opt_video_channel(const char *opt, const char *arg) { - video_channel = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX); + av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -channel.\n"); + opt_default("channel", arg); return 0; } static int opt_video_standard(const char *opt, const char *arg) { - video_standard = av_strdup(arg); + av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -standard.\n"); + opt_default("standard", arg); return 0; } @@ -3366,7 +3363,6 @@ static int opt_input_file(const char *opt, const char *filename) input_files[nb_input_files - 1].ctx = ic; input_files[nb_input_files - 1].ist_index = nb_input_streams - ic->nb_streams; - video_channel = 0; frame_rate = (AVRational){0, 0}; frame_pix_fmt = PIX_FMT_NONE; frame_height = 0; @@ -4397,8 +4393,8 @@ static const OptionDef options[] = { { "stag", HAS_ARG | OPT_EXPERT | OPT_SUBTITLE, {(void*)opt_codec_tag}, "force subtitle tag/fourcc", "fourcc/tag" }, /* grab options */ - { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, {(void*)opt_video_channel}, "set video grab channel (DV1394 only)", "channel" }, - { "tvstd", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, {(void*)opt_video_standard}, "set television standard (NTSC, PAL (SECAM))", "standard" }, + { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, {(void*)opt_video_channel}, "deprecated, use -channel", "channel" }, + { "tvstd", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, {(void*)opt_video_standard}, "deprecated, use -standard", "standard" }, { "isync", OPT_BOOL | OPT_EXPERT | OPT_GRAB, {(void*)&input_sync}, "sync read on input", "" }, /* muxer options */ From 7c44d716e76cbd1c29369563a8b384addd5e7c03 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 16 Jun 2011 17:21:46 +0200 Subject: [PATCH 16/20] Add minor bumps and APIChanges entries for lavf private options. --- doc/APIchanges | 10 ++++++++++ libavformat/version.h | 4 ++-- libavutil/avutil.h | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/doc/APIchanges b/doc/APIchanges index 0ab658d89c..460e8dde83 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -13,6 +13,16 @@ libavutil: 2011-04-18 API changes, most recent first: +2011-06-xx - xxxxxxx - lavf 53.2.0 - avformat.h + Add avformat_open_input and avformat_write_header(). + Deprecate av_open_input_stream, av_open_input_file, + AVFormatParameters and av_write_header. + +2011-06-xx - xxxxxxx - lavu 51.7.0 - opt.h + Add av_opt_set_dict() and av_opt_find(). + Deprecate av_find_opt(). + Add AV_DICT_APPEND flag. + 2011-06-xx - xxxxxxx - lavu 51.6.0 - opt.h Add av_opt_flag_is_set(). diff --git a/libavformat/version.h b/libavformat/version.h index 83fa431246..3cc1718f2b 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -24,8 +24,8 @@ #include "libavutil/avutil.h" #define LIBAVFORMAT_VERSION_MAJOR 53 -#define LIBAVFORMAT_VERSION_MINOR 1 -#define LIBAVFORMAT_VERSION_MICRO 3 +#define LIBAVFORMAT_VERSION_MINOR 2 +#define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ diff --git a/libavutil/avutil.h b/libavutil/avutil.h index 21df460c1f..18461467b4 100644 --- a/libavutil/avutil.h +++ b/libavutil/avutil.h @@ -40,7 +40,7 @@ #define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c) #define LIBAVUTIL_VERSION_MAJOR 51 -#define LIBAVUTIL_VERSION_MINOR 6 +#define LIBAVUTIL_VERSION_MINOR 7 #define LIBAVUTIL_VERSION_MICRO 0 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ From aa15e68721b15f8020da9d392954b343f195f22c Mon Sep 17 00:00:00 2001 From: Mike Scheutzow Date: Thu, 28 Apr 2011 10:14:26 -0400 Subject: [PATCH 17/20] Fix decoding of mpegts streams with h264 video that does *NOT* have b frames One of the causes of this bug is that the h264 parser defaults low_delay to 1, but the h264 codec defaults low_delay to 0. Really Ugly. After many hours of looking at this, I'm still not sure how has_b_frames is *intended* to behave, but to me the implementation appears way more complicated than it ought to be. My patch relies on the encoder to set an optional field in the SPS. This works for libx264 streams, but I'm not sure that all h264 encoders will set it. Signed-off-by: Anton Khirnov --- libavcodec/h264.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libavcodec/h264.c b/libavcodec/h264.c index 78ca4141a4..0aac09754a 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -3768,7 +3768,8 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size){ init_get_bits(&s->gb, ptr, bit_length); ff_h264_decode_seq_parameter_set(h); - if(s->flags& CODEC_FLAG_LOW_DELAY) + if (s->flags& CODEC_FLAG_LOW_DELAY || + (h->sps.bitstream_restriction_flag && !h->sps.num_reorder_frames)) s->low_delay=1; if(avctx->has_b_frames < 2) From c98b928fa7dea6418c24a163e7bcd36b0eb922a3 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Tue, 14 Jun 2011 21:53:30 +0000 Subject: [PATCH 18/20] intreadwrite.h: fix AV_RL32/AV_RB32 signedness. The output type of the AV_RL32/AV_RB32 macros was signed int. The resulting overflow broke at least some ASF streams with large timestamps. Fix by adding a cast to uint32_t. Signed-off-by: Ronald S. Bultje Signed-off-by: Anton Khirnov --- libavutil/intreadwrite.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libavutil/intreadwrite.h b/libavutil/intreadwrite.h index c8489f1138..01eb27804a 100644 --- a/libavutil/intreadwrite.h +++ b/libavutil/intreadwrite.h @@ -229,11 +229,11 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; #endif #ifndef AV_RB32 -# define AV_RB32(x) \ - ((((const uint8_t*)(x))[0] << 24) | \ - (((const uint8_t*)(x))[1] << 16) | \ - (((const uint8_t*)(x))[2] << 8) | \ - ((const uint8_t*)(x))[3]) +# define AV_RB32(x) \ + (((uint32_t)((const uint8_t*)(x))[0] << 24) | \ + (((const uint8_t*)(x))[1] << 16) | \ + (((const uint8_t*)(x))[2] << 8) | \ + ((const uint8_t*)(x))[3]) #endif #ifndef AV_WB32 # define AV_WB32(p, d) do { \ @@ -245,11 +245,11 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; #endif #ifndef AV_RL32 -# define AV_RL32(x) \ - ((((const uint8_t*)(x))[3] << 24) | \ - (((const uint8_t*)(x))[2] << 16) | \ - (((const uint8_t*)(x))[1] << 8) | \ - ((const uint8_t*)(x))[0]) +# define AV_RL32(x) \ + (((uint32_t)((const uint8_t*)(x))[3] << 24) | \ + (((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) #endif #ifndef AV_WL32 # define AV_WL32(p, d) do { \ From 3803af22d8e1092e658110e77db093922ce63e80 Mon Sep 17 00:00:00 2001 From: Alexander Strange Date: Sun, 12 Jun 2011 20:40:00 +0000 Subject: [PATCH 19/20] h264: Complexify frame num gap shortening code By observation it did not seem to handle prev_frame_num > frame_num. This does not affect any files I have. Signed-off-by: Ronald S. Bultje Signed-off-by: Anton Khirnov --- libavcodec/h264.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/libavcodec/h264.c b/libavcodec/h264.c index 0aac09754a..ad591269c6 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -2681,9 +2681,20 @@ static int decode_slice_header(H264Context *h, H264Context *h0){ h->mb_field_decoding_flag= s->picture_structure != PICT_FRAME; if(h0->current_slice == 0){ - if(h->frame_num != h->prev_frame_num && - (h->prev_frame_num+1)%(1<sps.log2_max_frame_num) < (h->frame_num - h->sps.ref_frame_count)) - h->prev_frame_num = h->frame_num - h->sps.ref_frame_count - 1; + // Shorten frame num gaps so we don't have to allocate reference frames just to throw them away + if(h->frame_num != h->prev_frame_num) { + int unwrap_prev_frame_num = h->prev_frame_num, max_frame_num = 1<sps.log2_max_frame_num; + + if (unwrap_prev_frame_num > h->frame_num) unwrap_prev_frame_num -= max_frame_num; + + if ((h->frame_num - unwrap_prev_frame_num) > h->sps.ref_frame_count) { + unwrap_prev_frame_num = (h->frame_num - h->sps.ref_frame_count) - 1; + if (unwrap_prev_frame_num < 0) + unwrap_prev_frame_num += max_frame_num; + + h->prev_frame_num = unwrap_prev_frame_num; + } + } while(h->frame_num != h->prev_frame_num && h->frame_num != (h->prev_frame_num+1)%(1<sps.log2_max_frame_num)){ From 78440c007cd310bb27ac2af5fb7ea5b7555efc84 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Fri, 17 Jun 2011 06:39:42 +0200 Subject: [PATCH 20/20] lavc: add opt_find to AVCodecContext class. Fixes encoder private options, which are broken now in ffmpeg, because opt_default2() can't find them, thus making opt_default() to fail. --- libavcodec/options.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/libavcodec/options.c b/libavcodec/options.c index 8f9aec4ac2..ae9e0c902d 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -37,6 +37,25 @@ static const char* context_to_name(void* ptr) { return "NULL"; } +static const AVOption *opt_find(void *obj, const char *name, const char *unit, int opt_flags, int search_flags) +{ + AVCodecContext *s = obj; + AVCodec *c = NULL; + + if (s->priv_data) { + if (s->codec->priv_class) + return av_opt_find(s->priv_data, name, unit, opt_flags, search_flags); + return NULL; + } + + while ((c = av_codec_next(c))) { + const AVOption *o; + if (c->priv_class && (o = av_opt_find(&c->priv_class, name, unit, opt_flags, search_flags))) + return o; + } + return NULL; +} + #define OFFSET(x) offsetof(AVCodecContext,x) #define DEFAULT 0 //should be NAN but it does not work as it is not a constant in glibc as required by ANSI/ISO C //these names are too long to be readable @@ -457,7 +476,7 @@ static const AVOption options[]={ #undef D #undef DEFAULT -static const AVClass av_codec_context_class = { "AVCodecContext", context_to_name, options, LIBAVUTIL_VERSION_INT, OFFSET(log_level_offset) }; +static const AVClass av_codec_context_class = { "AVCodecContext", context_to_name, options, LIBAVUTIL_VERSION_INT, OFFSET(log_level_offset), .opt_find = opt_find}; void avcodec_get_context_defaults2(AVCodecContext *s, enum AVMediaType codec_type){ int flags=0;