diff --git a/cmdutils.c b/cmdutils.c index 1f7ecc4887..3b9cfaa3d9 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; @@ -86,6 +88,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) @@ -290,6 +296,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; @@ -322,7 +365,7 @@ int opt_default(const char *opt, const char *arg){ goto out; 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); } @@ -345,11 +388,50 @@ int opt_default(const char *opt, const char *arg){ exit(1); } if (!o) { +//<<<<<<< HEAD fprintf(stderr, "Unrecognized option '%s'\n", opt); exit(1); +/*||||||| merged common ancestors + AVCodec *p = NULL; + 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)) + 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)) + break; + } + } + if(!p && !oformat){ + fprintf(stderr, "Unrecognized option '%s'\n", opt); + exit(1); + } +======= + AVCodec *p = NULL; + AVOutputFormat *oformat = NULL; + while ((p=av_codec_next(p))){ + const AVClass *c = p->priv_class; + 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_opt_find(&c, opt, NULL, 0, 0)) + break; + } + } +>>>>>>> qatar/master*/ } out: + 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)); opt_values= av_realloc(opt_values, sizeof(void*)*(opt_name_count+1)); diff --git a/cmdutils.h b/cmdutils.h index 5fd398d054..c0c3ce07d9 100644 --- a/cmdutils.h +++ b/cmdutils.h @@ -47,6 +47,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 diff --git a/doc/APIchanges b/doc/APIchanges index e8dc0642fa..e07951fe05 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -23,6 +23,16 @@ API changes, most recent first: 2011-06-12 - xxxxxxx - lavfi 2.16.0 - avfilter_graph_parse() Change avfilter_graph_parse() signature. +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/ffmpeg.c b/ffmpeg.c index 6ce127e903..4e8ac200da 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -2261,6 +2261,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); @@ -2272,7 +2274,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; @@ -2287,6 +2289,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); @@ -2297,6 +2303,10 @@ static int transcode(AVFormatContext **output_files, if (ost->video_resample) { codec->bits_per_raw_sample= frame_bits_per_raw_sample; } + 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; @@ -2305,9 +2315,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}; @@ -2375,8 +2385,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); @@ -3397,17 +3405,12 @@ static int opt_input_file(const char *opt, const char *filename) if(!input_codecs[nb_input_codecs-1]) input_codecs[nb_input_codecs-1] = avcodec_find_decoder(dec->codec_id); 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) { 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; @@ -3452,9 +3455,12 @@ 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; top_field_first = -1; + 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; @@ -3578,8 +3584,6 @@ static void new_video_stream(AVFormatContext *oc, int file_idx) video_enc->bits_per_raw_sample = frame_bits_per_raw_sample; 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) { @@ -3985,6 +3989,8 @@ static int opt_output_file(const char *opt, 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; diff --git a/ffprobe.c b/ffprobe.c index e945a9a54d..f0ec9e4739 100644 --- a/ffprobe.c +++ b/ffprobe.c @@ -262,18 +262,18 @@ static void show_format(AVFormatContext *fmt_ctx) static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename) { int err, i; - AVFormatParameters fmt_params; - AVFormatContext *fmt_ctx; + AVFormatContext *fmt_ctx = NULL; + AVDictionaryEntry *t; - memset(&fmt_params, 0, sizeof(fmt_params)); - fmt_params.prealloced_context = 1; - 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, &fmt_params)) < 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) { diff --git a/ffserver.c b/ffserver.c index e222887c65..15ea00f4f8 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); } @@ -3944,7 +3941,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/libavcodec/h264.c b/libavcodec/h264.c index 0919c12b92..b88622d432 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -3784,8 +3784,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 || - (h->sps.bitstream_restriction_flag && !h->sps.num_reorder_frames)) + 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) diff --git a/libavcodec/options.c b/libavcodec/options.c index 78a7bc8a40..b6ad5d8763 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; diff --git a/libavfilter/vsrc_movie.c b/libavfilter/vsrc_movie.c index 6c5c831fed..7a3babbec8 100644 --- a/libavfilter/vsrc_movie.c +++ b/libavfilter/vsrc_movie.c @@ -92,9 +92,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 050d99c6d7..ddf97e9d31 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 f00fce4a38..1734649a95 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. @@ -751,10 +751,12 @@ 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_MP4A_LATM 0x0080 ///< Enable RTP MP4A-LATM payload +#define AVFMT_FLAG_CUSTOM_IO 0x0080 ///< The caller has supplied a custom AVIOContext, don't avio_close() it. +#define AVFMT_FLAG_MP4A_LATM 0x8000 ///< Enable RTP MP4A-LATM payload #define AVFMT_FLAG_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down) #define AVFMT_FLAG_PRIV_OPT 0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted) #define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Dont merge side data but keep it seperate. + int loop_input; /** @@ -1054,11 +1056,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); @@ -1073,11 +1077,35 @@ 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. + * 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); int av_demuxer_open(AVFormatContext *ic, AVFormatParameters *ap); @@ -1365,7 +1393,12 @@ int64_t av_gen_search(AVFormatContext *s, int stream_index, /** * media file output */ +#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. @@ -1393,6 +1426,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. @@ -1401,8 +1452,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/avidec.c b/libavformat/avidec.c index b7d09d799e..0bcdd3fdec 100644 --- a/libavformat/avidec.c +++ b/libavformat/avidec.c @@ -800,7 +800,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; @@ -1393,7 +1397,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/options.c b/libavformat/options.c index ed06ea0e44..e09fc97a25 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 @@ -75,6 +102,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/rdt.c b/libavformat/rdt.c index 5c35b7453b..bbdb899578 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 58c9068a87..4f776453d7 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/rtpenc_chain.c b/libavformat/rtpenc_chain.c index 7f1a8868eb..ed96d72f62 100644 --- a/libavformat/rtpenc_chain.c +++ b/libavformat/rtpenc_chain.c @@ -67,7 +67,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/sapdec.c b/libavformat/sapdec.c index ea4b982041..f6897fbb0b 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 1a10887029..3be8706d87 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -28,6 +28,7 @@ #include "libavcodec/raw.h" #include "libavutil/opt.h" #include "libavutil/dict.h" +#include "libavutil/pixdesc.h" #include "metadata.h" #include "id3v2.h" #include "libavutil/avstring.h" @@ -393,6 +394,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. */ @@ -401,6 +443,7 @@ int av_open_input_stream(AVFormatContext **ic_ptr, AVInputFormat *fmt, AVFormatParameters *ap) { int err; + AVDictionary *opts; AVFormatContext *ic; AVFormatParameters default_ap; @@ -408,6 +451,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(); @@ -417,63 +461,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->flags&AVFMT_FLAG_PRIV_OPT) && ic->iformat->read_header) { - err = ic->iformat->read_header(ic, ap); - if (err < 0) - goto fail; - } - - if (!(ic->flags&AVFMT_FLAG_PRIV_OPT) && 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 int av_demuxer_open(AVFormatContext *ic, AVFormatParameters *ap){ int err; @@ -562,68 +558,124 @@ 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); + + 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) +{ + 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; } - /* 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 ( (s->iformat && s->iformat->flags & AVFMT_NOFILE) || + (!s->iformat && (s->iformat = av_probe_input_format(&pd, 0)))) + return 0; - /* if still no format found, error */ - if (!fmt) { - err = AVERROR_INVALIDDATA; + 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 (fmt->flags & AVFMT_NEEDNUMBER) { + if (s->iformat->flags & AVFMT_NEEDNUMBER) { if (!av_filename_number_test(filename)) { - err = AVERROR(EINVAL); + ret = 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; - return err; + 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->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header) + if ((ret = s->iformat->read_header(s, &ap)) < 0) + goto fail; + + if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && 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; } /*******************************************************/ @@ -2615,7 +2667,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); @@ -2722,6 +2775,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) { if (s->oformat->priv_data_size > 0) { @@ -2737,6 +2791,7 @@ int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap) return 0; } +#endif int avformat_alloc_output_context2(AVFormatContext **avctx, AVOutputFormat *oformat, const char *format, const char *filename) @@ -2834,15 +2889,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++) { @@ -2852,7 +2921,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 * @@ -2861,15 +2931,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; } @@ -2886,7 +2959,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); @@ -2899,8 +2973,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 */ @@ -2911,7 +2993,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 */ @@ -2930,12 +3012,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 diff --git a/libavformat/version.h b/libavformat/version.h index 48224f8506..691f9c0569 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 3 -#define LIBAVFORMAT_VERSION_MICRO 1 +#define LIBAVFORMAT_VERSION_MINOR 4 +#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 500c700851..36dcf8f718 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 8 +#define LIBAVUTIL_VERSION_MINOR 9 #define LIBAVUTIL_VERSION_MICRO 0 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ @@ -63,6 +63,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/dict.c b/libavutil/dict.c index 332eccd679..74301fbf11 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 19cc0915d8..421be32244 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; diff --git a/libavutil/intreadwrite.h b/libavutil/intreadwrite.h index 1849a64661..09d796c8b8 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 { \ diff --git a/libavutil/log.h b/libavutil/log.h index c87125d2d5..149225dadf 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 d57a547377..8c351488a8 100644 --- a/libavutil/opt.c +++ b/libavutil/opt.c @@ -29,7 +29,9 @@ #include "avstring.h" #include "opt.h" #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) { @@ -41,6 +43,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) { @@ -51,7 +54,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; @@ -114,7 +117,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) @@ -161,7 +164,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; @@ -226,7 +229,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; @@ -259,7 +262,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 && o->type != FF_OPT_TYPE_CONST)) goto error; @@ -538,6 +541,45 @@ 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; +} + +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 872b5547c1..97a1cb5774 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, @@ -91,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, @@ -102,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. @@ -191,4 +197,46 @@ 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); + +#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 */