From 35e6f8c174908f4c29338f9ba57606d9f9488fec Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 29 Aug 2011 09:16:42 +0200 Subject: [PATCH 01/17] avconv: move codec_names to options context. --- avconv.c | 122 +++++++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 63 deletions(-) diff --git a/avconv.c b/avconv.c index 98eed860ab..f245b2a082 100644 --- a/avconv.c +++ b/avconv.c @@ -99,8 +99,6 @@ static const OptionDef options[]; static AVDictionary *ts_scale; -static AVDictionary *codec_names; - /* first item specifies output metadata, second is input */ static MetadataMap (*meta_data_maps)[2] = NULL; static int nb_meta_data_maps; @@ -314,6 +312,9 @@ typedef struct OptionsContext { int64_t start_time; const char *format; + SpecifierOpt *codec_names; + int nb_codec_names; + /* input options */ int64_t input_ts_offset; @@ -325,6 +326,18 @@ typedef struct OptionsContext { uint64_t limit_filesize; } OptionsContext; +#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\ +{\ + int i, ret;\ + for (i = 0; i < o->nb_ ## name; i++) {\ + char *spec = o->name[i].specifier;\ + if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0)\ + outvar = o->name[i].u.type;\ + else if (ret < 0)\ + exit_program(1);\ + }\ +} + static void reset_options(OptionsContext *o) { const OptionDef *po = options; @@ -2602,29 +2615,24 @@ static int opt_audio_channels(const char *opt, const char *arg) return 0; } -static int opt_codec(const char *opt, const char *arg) +static int opt_audio_codec(OptionsContext *o, const char *opt, const char *arg) { - return av_dict_set(&codec_names, opt, arg, 0); + return parse_option(o, "codec:a", arg, options); } -static int opt_audio_codec(const char *opt, const char *arg) +static int opt_video_codec(OptionsContext *o, const char *opt, const char *arg) { - return opt_codec("codec:a", arg); + return parse_option(o, "codec:v", arg, options); } -static int opt_video_codec(const char *opt, const char *arg) +static int opt_subtitle_codec(OptionsContext *o, const char *opt, const char *arg) { - return opt_codec("codec:v", arg); + return parse_option(o, "codec:s", arg, options); } -static int opt_subtitle_codec(const char *opt, const char *arg) +static int opt_data_codec(OptionsContext *o, const char *opt, const char *arg) { - return opt_codec("codec:s", arg); -} - -static int opt_data_codec(const char *opt, const char *arg) -{ - return opt_codec("codec:d", arg); + return parse_option(o, "codec:d", arg, options); } static int opt_codec_tag(const char *opt, const char *arg) @@ -2802,20 +2810,11 @@ static enum CodecID find_codec_or_die(const char *name, enum AVMediaType type, i return codec->id; } -static AVCodec *choose_codec(AVFormatContext *s, AVStream *st, enum AVMediaType type, AVDictionary *codec_names) +static AVCodec *choose_codec(OptionsContext *o, AVFormatContext *s, AVStream *st, enum AVMediaType type) { - AVDictionaryEntry *e = NULL; char *codec_name = NULL; - int ret; - while (e = av_dict_get(codec_names, "", e, AV_DICT_IGNORE_SUFFIX)) { - char *p = strchr(e->key, ':'); - - if ((ret = check_stream_specifier(s, st, p ? p + 1 : "")) > 0) - codec_name = e->value; - else if (ret < 0) - exit_program(1); - } + MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st); if (!codec_name) { if (s->oformat) { @@ -2837,7 +2836,7 @@ static AVCodec *choose_codec(AVFormatContext *s, AVStream *st, enum AVMediaType * Add all the streams from the given input file to the global * list of input streams. */ -static void add_input_streams(AVFormatContext *ic) +static void add_input_streams(OptionsContext *o, AVFormatContext *ic) { int i, rfps, rfps_base, ret; @@ -2866,7 +2865,7 @@ static void add_input_streams(AVFormatContext *ic) if (scale) ist->ts_scale = strtod(scale, NULL); - ist->dec = choose_codec(ic, st, dec->codec_type, codec_names); + ist->dec = choose_codec(o, ic, st, dec->codec_type); if (!ist->dec) ist->dec = avcodec_find_decoder(dec->codec_id); @@ -2999,7 +2998,7 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena /* apply forced codec ids */ for (i = 0; i < ic->nb_streams; i++) - choose_codec(ic, ic->streams[i], ic->streams[i]->codec->codec_type, codec_names); + choose_codec(o, ic, ic->streams[i], ic->streams[i]->codec->codec_type); /* Set AVCodecContext options for avformat_find_stream_info */ opts = setup_find_stream_info_opts(ic, codec_opts); @@ -3029,7 +3028,7 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena } /* update the current parameters so that they match the one of the input stream */ - add_input_streams(ic); + add_input_streams(o, ic); /* dump the file content */ if (verbose >= 0) @@ -3053,7 +3052,6 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena for (i = 0; i < orig_nb_streams; i++) av_dict_free(&opts[i]); av_freep(&opts); - av_dict_free(&codec_names); reset_options(o); return 0; @@ -3082,7 +3080,7 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost, } } -static OutputStream *new_output_stream(AVFormatContext *oc, enum AVMediaType type) +static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type) { OutputStream *ost; AVStream *st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0); @@ -3100,7 +3098,7 @@ static OutputStream *new_output_stream(AVFormatContext *oc, enum AVMediaType typ ost->index = idx; ost->st = st; st->codec->codec_type = type; - ost->enc = choose_codec(oc, st, type, codec_names); + ost->enc = choose_codec(o, oc, st, type); if (ost->enc) { ost->opts = filter_codec_opts(codec_opts, ost->enc->id, oc, st); } @@ -3112,13 +3110,13 @@ static OutputStream *new_output_stream(AVFormatContext *oc, enum AVMediaType typ return ost; } -static OutputStream *new_video_stream(AVFormatContext *oc) +static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc) { AVStream *st; OutputStream *ost; AVCodecContext *video_enc; - ost = new_output_stream(oc, AVMEDIA_TYPE_VIDEO); + ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO); st = ost->st; if (!st->stream_copy) { ost->frame_aspect_ratio = frame_aspect_ratio; @@ -3223,13 +3221,13 @@ static OutputStream *new_video_stream(AVFormatContext *oc) return ost; } -static OutputStream *new_audio_stream(AVFormatContext *oc) +static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc) { AVStream *st; OutputStream *ost; AVCodecContext *audio_enc; - ost = new_output_stream(oc, AVMEDIA_TYPE_AUDIO); + ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO); st = ost->st; ost->bitstream_filters = audio_bitstream_filters; @@ -3267,13 +3265,13 @@ static OutputStream *new_audio_stream(AVFormatContext *oc) return ost; } -static OutputStream *new_data_stream(AVFormatContext *oc) +static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc) { AVStream *st; OutputStream *ost; AVCodecContext *data_enc; - ost = new_output_stream(oc, AVMEDIA_TYPE_DATA); + ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA); st = ost->st; data_enc = st->codec; if (!st->stream_copy) { @@ -3292,13 +3290,13 @@ static OutputStream *new_data_stream(AVFormatContext *oc) return ost; } -static OutputStream *new_subtitle_stream(AVFormatContext *oc) +static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc) { AVStream *st; OutputStream *ost; AVCodecContext *subtitle_enc; - ost = new_output_stream(oc, AVMEDIA_TYPE_SUBTITLE); + ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE); st = ost->st; subtitle_enc = st->codec; @@ -3385,7 +3383,7 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile) return 0; } -static int read_avserver_streams(AVFormatContext *s, const char *filename) +static int read_avserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename) { int i, err; AVFormatContext *ic = NULL; @@ -3400,7 +3398,7 @@ static int read_avserver_streams(AVFormatContext *s, const char *filename) AVCodec *codec; codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id); - ost = new_output_stream(s, codec->type); + ost = new_output_stream(o, s, codec->type); st = ost->st; // FIXME: a more elegant solution is needed @@ -3458,7 +3456,7 @@ static void opt_output_file(void *optctx, const char *filename) av_strstart(filename, "http:", NULL)) { /* special case for files sent to avserver: we get the stream parameters from avserver */ - int err = read_avserver_streams(oc, filename); + int err = read_avserver_streams(o, oc, filename); if (err < 0) { print_error(filename, err); exit_program(1); @@ -3467,7 +3465,7 @@ static void opt_output_file(void *optctx, const char *filename) /* pick the "best" stream of each type */ #define NEW_STREAM(type, index)\ if (index >= 0) {\ - ost = new_ ## type ## _stream(oc);\ + ost = new_ ## type ## _stream(o, oc);\ ost->source_index = index;\ ost->sync_ist = &input_streams[index];\ input_streams[index].discard = 0;\ @@ -3519,10 +3517,10 @@ static void opt_output_file(void *optctx, const char *filename) ist = &input_streams[input_files[map->file_index].ist_index + map->stream_index]; switch (ist->st->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(oc); break; - case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(oc); break; - case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(oc); break; - case AVMEDIA_TYPE_DATA: ost = new_data_stream(oc); break; + case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc); break; + case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc); break; + case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(o, oc); break; + case AVMEDIA_TYPE_DATA: ost = new_data_stream(o, oc); break; default: av_log(NULL, AV_LOG_ERROR, "Cannot map stream #%d.%d - unsupported type.\n", map->file_index, map->stream_index); @@ -3680,8 +3678,6 @@ static void opt_output_file(void *optctx, const char *filename) av_freep(&streamid_map); nb_streamid_map = 0; - av_dict_free(&codec_names); - av_freep(&forced_key_frames); reset_options(o); } @@ -3892,8 +3888,8 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg) } if(!strcmp(arg, "vcd")) { - opt_codec("c:v", "mpeg1video"); - opt_codec("c:a", "mp2"); + opt_video_codec(o, "c:v", "mpeg1video"); + opt_audio_codec(o, "c:a", "mp2"); parse_option(o, "f", "vcd", options); opt_frame_size("s", norm == PAL ? "352x288" : "352x240"); @@ -3920,8 +3916,8 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg) mux_preload= (36000+3*1200) / 90000.0; //0.44 } else if(!strcmp(arg, "svcd")) { - opt_codec("c:v", "mpeg2video"); - opt_codec("c:a", "mp2"); + opt_video_codec(o, "c:v", "mpeg2video"); + opt_audio_codec(o, "c:a", "mp2"); parse_option(o, "f", "svcd", options); opt_frame_size("s", norm == PAL ? "480x576" : "480x480"); @@ -3942,8 +3938,8 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg) } else if(!strcmp(arg, "dvd")) { - opt_codec("c:v", "mpeg2video"); - opt_codec("c:a", "ac3"); + opt_video_codec(o, "c:v", "mpeg2video"); + opt_audio_codec(o, "c:a", "ac3"); parse_option(o, "f", "dvd", options); opt_frame_size("vcodec", norm == PAL ? "720x576" : "720x480"); @@ -4026,8 +4022,8 @@ static const OptionDef options[] = { { "f", HAS_ARG | OPT_STRING | OPT_OFFSET, {.off = OFFSET(format)}, "force format", "fmt" }, { "i", HAS_ARG | OPT_FUNC2, {(void*)opt_input_file}, "input file name", "filename" }, { "y", OPT_BOOL, {(void*)&file_overwrite}, "overwrite output files" }, - { "c", HAS_ARG, {(void*)opt_codec}, "codec name", "codec" }, - { "codec", HAS_ARG, {(void*)opt_codec}, "codec name", "codec" }, + { "c", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" }, + { "codec", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" }, { "map", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map}, "set input stream mapping", "file.stream[:syncfile.syncstream]" }, { "map_metadata", HAS_ARG | OPT_EXPERT, {(void*)opt_map_metadata}, "set metadata information of outfile from infile", "outfile[,metadata]:infile[,metadata]" }, @@ -4070,7 +4066,7 @@ static const OptionDef options[] = { { "vdt", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)&video_discard}, "discard threshold", "n" }, { "qscale", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_qscale}, "use fixed video quantizer scale (VBR)", "q" }, { "rc_override", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_video_rc_override_string}, "rate control override for specific intervals", "override" }, - { "vcodec", HAS_ARG | OPT_VIDEO, {(void*)opt_video_codec}, "force video codec ('copy' to copy stream)", "codec" }, + { "vcodec", HAS_ARG | OPT_VIDEO | OPT_FUNC2, {(void*)opt_video_codec}, "force video codec ('copy' to copy stream)", "codec" }, { "me_threshold", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_me_threshold}, "motion estimation threshold", "threshold" }, { "same_quant", OPT_BOOL | OPT_VIDEO, {(void*)&same_quant}, "use same quantizer as source (implies VBR)" }, @@ -4101,7 +4097,7 @@ static const OptionDef options[] = { { "ar", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_rate}, "set audio sampling rate (in Hz)", "rate" }, { "ac", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_channels}, "set number of audio channels", "channels" }, { "an", OPT_BOOL | OPT_AUDIO, {(void*)&audio_disable}, "disable audio" }, - { "acodec", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_codec}, "force audio codec ('copy' to copy stream)", "codec" }, + { "acodec", HAS_ARG | OPT_AUDIO | OPT_FUNC2, {(void*)opt_audio_codec}, "force audio codec ('copy' to copy stream)", "codec" }, { "atag", HAS_ARG | OPT_EXPERT | OPT_AUDIO, {(void*)opt_codec_tag}, "force audio tag/fourcc", "fourcc/tag" }, { "vol", OPT_INT | HAS_ARG | OPT_AUDIO, {(void*)&audio_volume}, "change audio volume (256=normal)" , "volume" }, // { "alang", HAS_ARG | OPT_STRING | OPT_AUDIO, {(void *)&audio_language}, "set the ISO 639 language code (3 letters) of the current audio stream" , "code" }, @@ -4109,7 +4105,7 @@ static const OptionDef options[] = { /* subtitle options */ { "sn", OPT_BOOL | OPT_SUBTITLE, {(void*)&subtitle_disable}, "disable subtitle" }, - { "scodec", HAS_ARG | OPT_SUBTITLE, {(void*)opt_subtitle_codec}, "force subtitle codec ('copy' to copy stream)", "codec" }, + { "scodec", HAS_ARG | OPT_SUBTITLE | OPT_FUNC2, {(void*)opt_subtitle_codec}, "force subtitle codec ('copy' to copy stream)", "codec" }, { "slang", HAS_ARG | OPT_STRING | OPT_SUBTITLE, {(void *)&subtitle_language}, "set the ISO 639 language code (3 letters) of the current subtitle stream" , "code" }, { "stag", HAS_ARG | OPT_EXPERT | OPT_SUBTITLE, {(void*)opt_codec_tag}, "force subtitle tag/fourcc", "fourcc/tag" }, @@ -4125,7 +4121,7 @@ static const OptionDef options[] = { { "sbsf", HAS_ARG | OPT_SUBTITLE | OPT_EXPERT, {(void*)opt_bsf}, "", "bitstream_filter" }, /* data codec support */ - { "dcodec", HAS_ARG | OPT_DATA, {(void*)opt_data_codec}, "force data codec ('copy' to copy stream)", "codec" }, + { "dcodec", HAS_ARG | OPT_DATA | OPT_FUNC2, {(void*)opt_data_codec}, "force data codec ('copy' to copy stream)", "codec" }, { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {(void*)opt_default}, "generic catch all option", "" }, { NULL, }, From 847529f84a61ff4f1a98ae92e2931f2ff356a8dd Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 29 Aug 2011 09:16:42 +0200 Subject: [PATCH 02/17] avconv: move metadata maps to options context. --- avconv.c | 56 +++++++++++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/avconv.c b/avconv.c index f245b2a082..85e284c98a 100644 --- a/avconv.c +++ b/avconv.c @@ -99,13 +99,6 @@ static const OptionDef options[]; static AVDictionary *ts_scale; -/* first item specifies output metadata, second is input */ -static MetadataMap (*meta_data_maps)[2] = NULL; -static int nb_meta_data_maps; -static int metadata_global_autocopy = 1; -static int metadata_streams_autocopy = 1; -static int metadata_chapters_autocopy = 1; - static int chapters_input_file = INT_MAX; /* indexed by output file stream index */ @@ -321,6 +314,12 @@ typedef struct OptionsContext { /* output options */ StreamMap *stream_maps; int nb_stream_maps; + /* first item specifies output metadata, second is input */ + MetadataMap (*meta_data_maps)[2]; + int nb_meta_data_maps; + int metadata_global_manual; + int metadata_streams_manual; + int metadata_chapters_manual; int64_t recording_time; uint64_t limit_filesize; @@ -362,6 +361,7 @@ static void reset_options(OptionsContext *o) } av_freep(&o->stream_maps); + av_freep(&o->meta_data_maps); memset(o, 0, sizeof(*o)); @@ -513,8 +513,6 @@ void exit_program(int ret) fclose(vstats_file); av_free(vstats_filename); - av_free(meta_data_maps); - av_freep(&input_streams); av_freep(&input_files); av_freep(&output_streams); @@ -2756,30 +2754,30 @@ static void parse_meta_type(char *arg, char *type, int *index) *type = 'g'; } -static int opt_map_metadata(const char *opt, const char *arg) +static int opt_map_metadata(OptionsContext *o, const char *opt, const char *arg) { MetadataMap *m, *m1; char *p; - meta_data_maps = grow_array(meta_data_maps, sizeof(*meta_data_maps), - &nb_meta_data_maps, nb_meta_data_maps + 1); + o->meta_data_maps = grow_array(o->meta_data_maps, sizeof(*o->meta_data_maps), + &o->nb_meta_data_maps, o->nb_meta_data_maps + 1); - m = &meta_data_maps[nb_meta_data_maps - 1][1]; + m = &o->meta_data_maps[o->nb_meta_data_maps - 1][1]; m->file = strtol(arg, &p, 0); parse_meta_type(p, &m->type, &m->index); - m1 = &meta_data_maps[nb_meta_data_maps - 1][0]; + m1 = &o->meta_data_maps[o->nb_meta_data_maps - 1][0]; if (p = strchr(opt, ':')) parse_meta_type(p, &m1->type, &m1->index); else m1->type = 'g'; if (m->type == 'g' || m1->type == 'g') - metadata_global_autocopy = 0; + o->metadata_global_manual = 1; if (m->type == 's' || m1->type == 's') - metadata_streams_autocopy = 0; + o->metadata_streams_manual = 1; if (m->type == 'c' || m1->type == 'c') - metadata_chapters_autocopy = 0; + o->metadata_chapters_manual = 1; return 0; } @@ -3343,7 +3341,7 @@ static int opt_streamid(const char *opt, const char *arg) return 0; } -static int copy_chapters(InputFile *ifile, OutputFile *ofile) +static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata) { AVFormatContext *is = ifile->ctx; AVFormatContext *os = ofile->ctx; @@ -3371,7 +3369,7 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile) out_ch->start = FFMAX(0, in_ch->start - ts_off); out_ch->end = FFMIN(rt, in_ch->end - ts_off); - if (metadata_chapters_autocopy) + if (copy_metadata) av_dict_copy(&out_ch->metadata, in_ch->metadata, 0); os->nb_chapters++; @@ -3604,10 +3602,11 @@ static void opt_output_file(void *optctx, const char *filename) } } if (chapters_input_file >= 0) - copy_chapters(&input_files[chapters_input_file], &output_files[nb_output_files - 1]); + copy_chapters(&input_files[chapters_input_file], &output_files[nb_output_files - 1], + o->metadata_chapters_manual); /* copy metadata */ - for (i = 0; i < nb_meta_data_maps; i++) { + for (i = 0; i < o->nb_meta_data_maps; i++) { AVFormatContext *files[2]; AVDictionary **meta[2]; int j; @@ -3619,7 +3618,7 @@ static void opt_output_file(void *optctx, const char *filename) exit_program(1);\ } - int in_file_index = meta_data_maps[i][1].file; + int in_file_index = o->meta_data_maps[i][1].file; if (in_file_index < 0) continue; METADATA_CHECK_INDEX(in_file_index, nb_input_files, "input file") @@ -3628,7 +3627,7 @@ static void opt_output_file(void *optctx, const char *filename) files[1] = input_files[in_file_index].ctx; for (j = 0; j < 2; j++) { - MetadataMap *map = &meta_data_maps[i][j]; + MetadataMap *map = &o->meta_data_maps[i][j]; switch (map->type) { case 'g': @@ -3653,10 +3652,10 @@ static void opt_output_file(void *optctx, const char *filename) } /* copy global metadata by default */ - if (metadata_global_autocopy && nb_input_files) + if (!o->metadata_global_manual && nb_input_files) av_dict_copy(&oc->metadata, input_files[0].ctx->metadata, AV_DICT_DONT_OVERWRITE); - if (metadata_streams_autocopy) + if (!o->metadata_streams_manual) for (i = output_files[nb_output_files - 1].ost_index; i < nb_output_streams; i++) { InputStream *ist = &input_streams[output_streams[i].source_index]; av_dict_copy(&output_streams[i].st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE); @@ -3670,11 +3669,6 @@ static void opt_output_file(void *optctx, const char *filename) audio_sample_fmt = AV_SAMPLE_FMT_NONE; chapters_input_file = INT_MAX; - av_freep(&meta_data_maps); - nb_meta_data_maps = 0; - metadata_global_autocopy = 1; - metadata_streams_autocopy = 1; - metadata_chapters_autocopy = 1; av_freep(&streamid_map); nb_streamid_map = 0; @@ -4025,7 +4019,7 @@ static const OptionDef options[] = { { "c", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" }, { "codec", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" }, { "map", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map}, "set input stream mapping", "file.stream[:syncfile.syncstream]" }, - { "map_metadata", HAS_ARG | OPT_EXPERT, {(void*)opt_map_metadata}, "set metadata information of outfile from infile", + { "map_metadata", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_metadata}, "set metadata information of outfile from infile", "outfile[,metadata]:infile[,metadata]" }, { "map_chapters", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&chapters_input_file}, "set chapters mapping", "input_file_index" }, { "t", HAS_ARG | OPT_TIME | OPT_OFFSET, {.off = OFFSET(recording_time)}, "record or transcode \"duration\" seconds of audio/video", "duration" }, From c5bb372e85d56df9974bd568bdb3ad70e0abae58 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 29 Aug 2011 09:16:42 +0200 Subject: [PATCH 03/17] avconv: move chapter maps to options context. --- avconv.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/avconv.c b/avconv.c index 85e284c98a..5370d613c1 100644 --- a/avconv.c +++ b/avconv.c @@ -99,8 +99,6 @@ static const OptionDef options[]; static AVDictionary *ts_scale; -static int chapters_input_file = INT_MAX; - /* indexed by output file stream index */ static int *streamid_map = NULL; static int nb_streamid_map = 0; @@ -321,6 +319,8 @@ typedef struct OptionsContext { int metadata_streams_manual; int metadata_chapters_manual; + int chapters_input_file; + int64_t recording_time; uint64_t limit_filesize; } OptionsContext; @@ -367,6 +367,7 @@ static void reset_options(OptionsContext *o) o->recording_time = INT64_MAX; o->limit_filesize = UINT64_MAX; + o->chapters_input_file = INT_MAX; uninit_opts(); init_opts(); @@ -3586,23 +3587,23 @@ static void opt_output_file(void *optctx, const char *filename) oc->flags |= AVFMT_FLAG_NONBLOCK; /* copy chapters */ - if (chapters_input_file >= nb_input_files) { - if (chapters_input_file == INT_MAX) { + if (o->chapters_input_file >= nb_input_files) { + if (o->chapters_input_file == INT_MAX) { /* copy chapters from the first input file that has them*/ - chapters_input_file = -1; + o->chapters_input_file = -1; for (i = 0; i < nb_input_files; i++) if (input_files[i].ctx->nb_chapters) { - chapters_input_file = i; + o->chapters_input_file = i; break; } } else { av_log(NULL, AV_LOG_ERROR, "Invalid input file index %d in chapter mapping.\n", - chapters_input_file); + o->chapters_input_file); exit_program(1); } } - if (chapters_input_file >= 0) - copy_chapters(&input_files[chapters_input_file], &output_files[nb_output_files - 1], + if (o->chapters_input_file >= 0) + copy_chapters(&input_files[o->chapters_input_file], &output_files[nb_output_files - 1], o->metadata_chapters_manual); /* copy metadata */ @@ -3667,7 +3668,6 @@ static void opt_output_file(void *optctx, const char *filename) audio_sample_rate = 0; audio_channels = 0; audio_sample_fmt = AV_SAMPLE_FMT_NONE; - chapters_input_file = INT_MAX; av_freep(&streamid_map); nb_streamid_map = 0; @@ -4021,7 +4021,7 @@ static const OptionDef options[] = { { "map", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map}, "set input stream mapping", "file.stream[:syncfile.syncstream]" }, { "map_metadata", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_metadata}, "set metadata information of outfile from infile", "outfile[,metadata]:infile[,metadata]" }, - { "map_chapters", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&chapters_input_file}, "set chapters mapping", "input_file_index" }, + { "map_chapters", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_OFFSET, {.off = OFFSET(chapters_input_file)}, "set chapters mapping", "input_file_index" }, { "t", HAS_ARG | OPT_TIME | OPT_OFFSET, {.off = OFFSET(recording_time)}, "record or transcode \"duration\" seconds of audio/video", "duration" }, { "fs", HAS_ARG | OPT_INT64 | OPT_OFFSET, {.off = OFFSET(limit_filesize)}, "set the limit file size in bytes", "limit_size" }, // { "ss", HAS_ARG | OPT_TIME | OPT_OFFSET, {.off = OFFSET(start_time)}, "set the start time offset", "time_off" }, From 33f75d72e6769c071899be545cc861620c88fddb Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 29 Aug 2011 09:16:42 +0200 Subject: [PATCH 04/17] avconv: move ts scale to options context. --- avconv.c | 40 ++++++++++++---------------------------- cmdutils.c | 2 ++ cmdutils.h | 2 ++ 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/avconv.c b/avconv.c index 5370d613c1..e72d090b06 100644 --- a/avconv.c +++ b/avconv.c @@ -97,8 +97,6 @@ typedef struct MetadataMap { static const OptionDef options[]; -static AVDictionary *ts_scale; - /* indexed by output file stream index */ static int *streamid_map = NULL; static int nb_streamid_map = 0; @@ -309,6 +307,9 @@ typedef struct OptionsContext { /* input options */ int64_t input_ts_offset; + SpecifierOpt *ts_scale; + int nb_ts_scale; + /* output options */ StreamMap *stream_maps; int nb_stream_maps; @@ -2360,12 +2361,10 @@ static int transcode(OutputFile *output_files, if (pkt.pts != AV_NOPTS_VALUE) pkt.pts += av_rescale_q(input_files[ist->file_index].ts_offset, AV_TIME_BASE_Q, ist->st->time_base); - if (ist->ts_scale) { - if(pkt.pts != AV_NOPTS_VALUE) - pkt.pts *= ist->ts_scale; - if(pkt.dts != AV_NOPTS_VALUE) - pkt.dts *= ist->ts_scale; - } + if(pkt.pts != AV_NOPTS_VALUE) + pkt.pts *= ist->ts_scale; + if(pkt.dts != AV_NOPTS_VALUE) + pkt.dts *= ist->ts_scale; // fprintf(stderr, "next:%"PRId64" dts:%"PRId64" off:%"PRId64" %d\n", ist->next_pts, pkt.dts, input_files[ist->file_index].ts_offset, ist->st->codec->codec_type); if (pkt.dts != AV_NOPTS_VALUE && ist->next_pts != AV_NOPTS_VALUE @@ -2783,11 +2782,6 @@ static int opt_map_metadata(OptionsContext *o, const char *opt, const char *arg) return 0; } -static int opt_input_ts_scale(const char *opt, const char *arg) -{ - return av_dict_set(&ts_scale, opt, arg, 0); -} - static enum CodecID find_codec_or_die(const char *name, enum AVMediaType type, int encoder) { const char *codec_string = encoder ? "encoder" : "decoder"; @@ -2837,14 +2831,13 @@ static AVCodec *choose_codec(OptionsContext *o, AVFormatContext *s, AVStream *st */ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) { - int i, rfps, rfps_base, ret; + int i, rfps, rfps_base; for (i = 0; i < ic->nb_streams; i++) { AVStream *st = ic->streams[i]; AVCodecContext *dec = st->codec; - AVDictionaryEntry *e = NULL; InputStream *ist; - char *scale = NULL; + double scale = 1.0; input_streams = grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, nb_input_streams + 1); ist = &input_streams[nb_input_streams - 1]; @@ -2853,16 +2846,8 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) ist->discard = 1; ist->opts = filter_codec_opts(codec_opts, ist->st->codec->codec_id, ic, st); - while (e = av_dict_get(ts_scale, "", e, AV_DICT_IGNORE_SUFFIX)) { - char *p = strchr(e->key, ':'); - - if ((ret = check_stream_specifier(ic, st, p ? p + 1 : "")) > 0) - scale = e->value; - else if (ret < 0) - exit_program(1); - } - if (scale) - ist->ts_scale = strtod(scale, NULL); + MATCH_PER_STREAM_OPT(ts_scale, dbl, scale, ic, st); + ist->ts_scale = scale; ist->dec = choose_codec(o, ic, st, dec->codec_type); if (!ist->dec) @@ -3046,7 +3031,6 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena audio_sample_rate = 0; audio_channels = 0; audio_sample_fmt = AV_SAMPLE_FMT_NONE; - av_dict_free(&ts_scale); for (i = 0; i < orig_nb_streams; i++) av_dict_free(&opts[i]); @@ -4026,7 +4010,7 @@ static const OptionDef options[] = { { "fs", HAS_ARG | OPT_INT64 | OPT_OFFSET, {.off = OFFSET(limit_filesize)}, "set the limit file size in bytes", "limit_size" }, // { "ss", HAS_ARG | OPT_TIME | OPT_OFFSET, {.off = OFFSET(start_time)}, "set the start time offset", "time_off" }, { "itsoffset", HAS_ARG | OPT_TIME | OPT_OFFSET, {.off = OFFSET(input_ts_offset)}, "set the input ts offset", "time_off" }, - { "itsscale", HAS_ARG, {(void*)opt_input_ts_scale}, "set the input ts scale", "scale" }, + { "itsscale", HAS_ARG | OPT_DOUBLE | OPT_SPEC, {.off = OFFSET(ts_scale)}, "set the input ts scale", "scale" }, { "metadata", HAS_ARG, {(void*)opt_metadata}, "add metadata", "string=string" }, { "dframes", OPT_INT | HAS_ARG, {(void*)&max_frames[AVMEDIA_TYPE_DATA]}, "set the number of data frames to record", "number" }, { "benchmark", OPT_BOOL | OPT_EXPERT, {(void*)&do_benchmark}, diff --git a/cmdutils.c b/cmdutils.c index 3a41f45dbd..52ec96f951 100644 --- a/cmdutils.c +++ b/cmdutils.c @@ -258,6 +258,8 @@ unknown_opt: *(int64_t*)dst = parse_time_or_die(opt, arg, 1); } else if (po->flags & OPT_FLOAT) { *(float*)dst = parse_number_or_die(opt, arg, OPT_FLOAT, -INFINITY, INFINITY); + } else if (po->flags & OPT_DOUBLE) { + *(double*)dst = parse_number_or_die(opt, arg, OPT_DOUBLE, -INFINITY, INFINITY); } else if (po->u.func_arg) { int ret = po->flags & OPT_FUNC2 ? po->u.func2_arg(optctx, opt, arg) : po->u.func_arg(opt, arg); diff --git a/cmdutils.h b/cmdutils.h index 61cfc229b7..989d769dfe 100644 --- a/cmdutils.h +++ b/cmdutils.h @@ -115,6 +115,7 @@ typedef struct SpecifierOpt { int i; int64_t i64; float f; + double dbl; } u; } SpecifierOpt; @@ -140,6 +141,7 @@ typedef struct { Implies OPT_OFFSET. Next element after the offset is an int containing element count in the array. */ #define OPT_TIME 0x10000 +#define OPT_DOUBLE 0x20000 union { void *dst_ptr; int (*func_arg)(const char *, const char *); From 039267f192f335144d9251e6f05a1513dd1e8ef1 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 29 Aug 2011 09:16:42 +0200 Subject: [PATCH 05/17] avconv: move metadata to options context. It is now possible to set metadata on streams and chapters. --- avconv.c | 72 ++++++++++++++++++++++++++++++++----------------- doc/avconv.texi | 14 +++++++++- 2 files changed, 61 insertions(+), 25 deletions(-) diff --git a/avconv.c b/avconv.c index e72d090b06..3930eb6c46 100644 --- a/avconv.c +++ b/avconv.c @@ -145,7 +145,6 @@ static float mux_preload= 0.5; static float mux_max_delay= 0.7; static int file_overwrite = 0; -static AVDictionary *metadata; static int do_benchmark = 0; static int do_hex_dump = 0; static int do_pkt_dump = 0; @@ -324,6 +323,9 @@ typedef struct OptionsContext { int64_t recording_time; uint64_t limit_filesize; + + SpecifierOpt *metadata; + int nb_metadata; } OptionsContext; #define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\ @@ -2552,21 +2554,6 @@ static int opt_frame_aspect_ratio(const char *opt, const char *arg) return 0; } -static int opt_metadata(const char *opt, const char *arg) -{ - char *mid= strchr(arg, '='); - - if(!mid){ - fprintf(stderr, "Missing =\n"); - exit_program(1); - } - *mid++= 0; - - av_dict_set(&metadata, arg, mid, 0); - - return 0; -} - static int opt_qscale(const char *opt, const char *arg) { video_qscale = parse_number_or_die(opt, arg, OPT_FLOAT, 0, 255); @@ -2735,7 +2722,7 @@ static int opt_map(OptionsContext *o, const char *opt, const char *arg) static void parse_meta_type(char *arg, char *type, int *index) { - if (*arg == ':') { + if (*arg) { *type = *(++arg); switch (*arg) { case 'g': @@ -2764,11 +2751,11 @@ static int opt_map_metadata(OptionsContext *o, const char *opt, const char *arg) m = &o->meta_data_maps[o->nb_meta_data_maps - 1][1]; m->file = strtol(arg, &p, 0); - parse_meta_type(p, &m->type, &m->index); + parse_meta_type(*p ? p + 1 : p, &m->type, &m->index); m1 = &o->meta_data_maps[o->nb_meta_data_maps - 1][0]; if (p = strchr(opt, ':')) - parse_meta_type(p, &m1->type, &m1->index); + parse_meta_type(p + 1, &m1->type, &m1->index); else m1->type = 'g'; @@ -3517,10 +3504,6 @@ static void opt_output_file(void *optctx, const char *filename) } } - av_dict_copy(&oc->metadata, metadata, 0); - av_dict_free(&metadata); - - output_files = grow_array(output_files, sizeof(*output_files), &nb_output_files, nb_output_files + 1); output_files[nb_output_files - 1].ctx = oc; output_files[nb_output_files - 1].ost_index = nb_output_streams - oc->nb_streams; @@ -3646,6 +3629,47 @@ static void opt_output_file(void *optctx, const char *filename) av_dict_copy(&output_streams[i].st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE); } + /* process manually set metadata */ + for (i = 0; i < o->nb_metadata; i++) { + AVDictionary **m; + char type, *val; + int index = 0; + + val = strchr(o->metadata[i].u.str, '='); + if (!val) { + av_log(NULL, AV_LOG_ERROR, "No '=' character in metadata string %s.\n", + o->metadata[i].u.str); + exit_program(1); + } + *val++ = 0; + + parse_meta_type(o->metadata[i].specifier, &type, &index); + switch (type) { + case 'g': + m = &oc->metadata; + break; + case 's': + if (index < 0 || index >= oc->nb_streams) { + av_log(NULL, AV_LOG_ERROR, "Invalid stream index %d in metadata specifier.\n", index); + exit_program(1); + } + m = &oc->streams[i]->metadata; + break; + case 'c': + if (index < 0 || index >= oc->nb_chapters) { + av_log(NULL, AV_LOG_ERROR, "Invalid chapter index %d in metadata specifier.\n", index); + exit_program(1); + } + m = &oc->chapters[i]->metadata; + break; + default: + av_log(NULL, AV_LOG_ERROR, "Invalid metadata specifier %s.\n", o->metadata[i].specifier); + exit_program(1); + } + + av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0); + } + frame_rate = (AVRational){0, 0}; frame_width = 0; frame_height = 0; @@ -4011,7 +4035,7 @@ static const OptionDef options[] = { { "ss", HAS_ARG | OPT_TIME | OPT_OFFSET, {.off = OFFSET(start_time)}, "set the start time offset", "time_off" }, { "itsoffset", HAS_ARG | OPT_TIME | OPT_OFFSET, {.off = OFFSET(input_ts_offset)}, "set the input ts offset", "time_off" }, { "itsscale", HAS_ARG | OPT_DOUBLE | OPT_SPEC, {.off = OFFSET(ts_scale)}, "set the input ts scale", "scale" }, - { "metadata", HAS_ARG, {(void*)opt_metadata}, "add metadata", "string=string" }, + { "metadata", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(metadata)}, "add metadata", "string=string" }, { "dframes", OPT_INT | HAS_ARG, {(void*)&max_frames[AVMEDIA_TYPE_DATA]}, "set the number of data frames to record", "number" }, { "benchmark", OPT_BOOL | OPT_EXPERT, {(void*)&do_benchmark}, "add timings for benchmarking" }, diff --git a/doc/avconv.texi b/doc/avconv.texi index 959b781349..0b560440e9 100644 --- a/doc/avconv.texi +++ b/doc/avconv.texi @@ -160,14 +160,26 @@ interpreted as UTC. If the year-month-day part is not specified it takes the current year-month-day. -@item -metadata @var{key}=@var{value} +@item -metadata[:metadata_specifier] @var{key}=@var{value} Set a metadata key/value pair. +An optional @var{metadata_specifier} may be given to set metadata +on streams or chapters. See @code{-map_metadata} documentation for +details. + +This option overrides metadata set with @code{-map_metadata}. It is +also possible to delete metadata by using an empty value. + For example, for setting the title in the output file: @example avconv -i in.avi -metadata title="my title" out.flv @end example +To set the language of the second stream: +@example +avconv -i INPUT -metadata:s:1 language=eng OUTPUT +@end example + @item -v @var{number} Set the logging verbosity level. From 96139b5e32618c4370bf5173ba0570503eda5a8c Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 29 Aug 2011 09:16:42 +0200 Subject: [PATCH 06/17] avconv: move max_frames to options context. Add a -frames option that uses generic stream specifiers, change -[vad]frames into aliases to it. --- avconv.c | 40 ++++++++++++++++++++++++++++++++-------- doc/avconv.texi | 9 ++++++--- tests/fate/h264.mak | 2 +- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/avconv.c b/avconv.c index 3930eb6c46..c045f465a6 100644 --- a/avconv.c +++ b/avconv.c @@ -106,7 +106,6 @@ static int frame_height = 0; static float frame_aspect_ratio = 0; static enum PixelFormat frame_pix_fmt = PIX_FMT_NONE; static enum AVSampleFormat audio_sample_fmt = AV_SAMPLE_FMT_NONE; -static int max_frames[4] = {INT_MAX, INT_MAX, INT_MAX, INT_MAX}; static AVRational frame_rate; static float video_qscale = 0; static uint16_t *intra_matrix = NULL; @@ -234,6 +233,7 @@ typedef struct OutputStream { int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ //FIXME look at frame_number AVBitStreamFilterContext *bitstream_filters; AVCodec *enc; + int64_t max_frames; /* video only */ int video_resample; @@ -326,6 +326,8 @@ typedef struct OptionsContext { SpecifierOpt *metadata; int nb_metadata; + SpecifierOpt *max_frames; + int nb_max_frames; } OptionsContext; #define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\ @@ -1174,7 +1176,7 @@ static void do_video_out(AVFormatContext *s, }else ost->sync_opts= lrintf(sync_ipts); - nb_frames= FFMIN(nb_frames, max_frames[AVMEDIA_TYPE_VIDEO] - ost->frame_number); + nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number); if (nb_frames <= 0) return; @@ -2310,9 +2312,11 @@ static int transcode(OutputFile *output_files, if(!input_sync) file_index = ist->file_index; } } - if(ost->frame_number >= max_frames[ost->st->codec->codec_type]){ - file_index= -1; - break; + if (ost->frame_number >= ost->max_frames) { + int j; + for (j = of->ost_index; j < of->ctx->nb_streams; j++) + output_streams[j].is_past_recording_time = 1; + continue; } } /* if none, if is finished */ @@ -3055,6 +3059,7 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e OutputStream *ost; AVStream *st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0); int idx = oc->nb_streams - 1; + int64_t max_frames = INT64_MAX; if (!st) { av_log(NULL, AV_LOG_ERROR, "Could not alloc stream.\n"); @@ -3076,6 +3081,9 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e avcodec_get_context_defaults3(st->codec, ost->enc); st->codec->codec_type = type; // XXX hack, avcodec_get_context_defaults2() sets type to unknown for stream copy + MATCH_PER_STREAM_OPT(max_frames, i64, max_frames, oc, st); + ost->max_frames = max_frames; + ost->sws_flags = av_get_int(sws_opts, "sws_flags", NULL); return ost; } @@ -4017,6 +4025,21 @@ static int opt_bsf(const char *opt, const char *arg) return 0; } +static int opt_video_frames(OptionsContext *o, const char *opt, const char *arg) +{ + return parse_option(o, "frames:v", arg, options); +} + +static int opt_audio_frames(OptionsContext *o, const char *opt, const char *arg) +{ + return parse_option(o, "frames:a", arg, options); +} + +static int opt_data_frames(OptionsContext *o, const char *opt, const char *arg) +{ + return parse_option(o, "frames:d", arg, options); +} + #define OFFSET(x) offsetof(OptionsContext, x) static const OptionDef options[] = { /* main options */ @@ -4036,7 +4059,7 @@ static const OptionDef options[] = { { "itsoffset", HAS_ARG | OPT_TIME | OPT_OFFSET, {.off = OFFSET(input_ts_offset)}, "set the input ts offset", "time_off" }, { "itsscale", HAS_ARG | OPT_DOUBLE | OPT_SPEC, {.off = OFFSET(ts_scale)}, "set the input ts scale", "scale" }, { "metadata", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(metadata)}, "add metadata", "string=string" }, - { "dframes", OPT_INT | HAS_ARG, {(void*)&max_frames[AVMEDIA_TYPE_DATA]}, "set the number of data frames to record", "number" }, + { "dframes", HAS_ARG | OPT_FUNC2, {(void*)opt_data_frames}, "set the number of data frames to record", "number" }, { "benchmark", OPT_BOOL | OPT_EXPERT, {(void*)&do_benchmark}, "add timings for benchmarking" }, { "timelimit", HAS_ARG, {(void*)opt_timelimit}, "set max runtime in seconds", "limit" }, @@ -4057,9 +4080,10 @@ static const OptionDef options[] = { { "programid", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&opt_programid}, "desired program number", "" }, { "xerror", OPT_BOOL, {(void*)&exit_on_error}, "exit on error", "error" }, { "copyinkf", OPT_BOOL | OPT_EXPERT, {(void*)©_initial_nonkeyframes}, "copy initial non-keyframes" }, + { "frames", OPT_INT64 | HAS_ARG | OPT_SPEC, {.off = OFFSET(max_frames)}, "set the number of frames to record", "number" }, /* video options */ - { "vframes", OPT_INT | HAS_ARG | OPT_VIDEO, {(void*)&max_frames[AVMEDIA_TYPE_VIDEO]}, "set the number of video frames to record", "number" }, + { "vframes", HAS_ARG | OPT_VIDEO | OPT_FUNC2, {(void*)opt_video_frames}, "set the number of video frames to record", "number" }, { "r", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_rate}, "set frame rate (Hz value, fraction or abbreviation)", "rate" }, { "s", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_size}, "set frame size (WxH or abbreviation)", "size" }, { "aspect", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_aspect_ratio}, "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" }, @@ -4094,7 +4118,7 @@ static const OptionDef options[] = { { "force_key_frames", OPT_STRING | HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void *)&forced_key_frames}, "force key frames at specified timestamps", "timestamps" }, /* audio options */ - { "aframes", OPT_INT | HAS_ARG | OPT_AUDIO, {(void*)&max_frames[AVMEDIA_TYPE_AUDIO]}, "set the number of audio frames to record", "number" }, + { "aframes", HAS_ARG | OPT_AUDIO | OPT_FUNC2, {(void*)opt_audio_frames}, "set the number of audio frames to record", "number" }, { "aq", OPT_FLOAT | HAS_ARG | OPT_AUDIO, {(void*)&audio_qscale}, "set audio quality (codec-specific)", "quality", }, { "ar", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_rate}, "set audio sampling rate (in Hz)", "rate" }, { "ac", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_channels}, "set number of audio channels", "channels" }, diff --git a/doc/avconv.texi b/doc/avconv.texi index 0b560440e9..3ee606a16f 100644 --- a/doc/avconv.texi +++ b/doc/avconv.texi @@ -200,18 +200,21 @@ avconv -i myfile.avi -target vcd -bf 2 /tmp/vcd.mpg @end example @item -dframes @var{number} -Set the number of data frames to record. +Set the number of data frames to record. This is an alias for @code{-frames:d}. @item -slang @var{code} Set the ISO 639 language code (3 letters) of the current subtitle stream. +@item -frames[:stream_specifier] @var{framecount} +Stop writing to the stream after @var{framecount} frames. + @end table @section Video Options @table @option @item -vframes @var{number} -Set the number of video frames to record. +Set the number of video frames to record. This is an alias for @code{-frames:v}. @item -r @var{fps} Set frame rate (Hz value, fraction or abbreviation), (default = 25). @item -s @var{size} @@ -581,7 +584,7 @@ The timestamps must be specified in ascending order. @table @option @item -aframes @var{number} -Set the number of audio frames to record. +Set the number of audio frames to record. This is an alias for @code{-frames:a}. @item -ar @var{freq} Set the audio sampling frequency. For output streams it is set by default to the frequency of the corresponding input stream. For input diff --git a/tests/fate/h264.mak b/tests/fate/h264.mak index 969bf413e4..d0f1a62d60 100644 --- a/tests/fate/h264.mak +++ b/tests/fate/h264.mak @@ -352,6 +352,6 @@ fate-h264-conformance-sva_fm1_e: CMD = framecrc -vsync 0 -i $(SAMPLES)/h264-conf fate-h264-conformance-sva_nl1_b: CMD = framecrc -vsync 0 -i $(SAMPLES)/h264-conformance/SVA_NL1_B.264 fate-h264-conformance-sva_nl2_e: CMD = framecrc -vsync 0 -i $(SAMPLES)/h264-conformance/SVA_NL2_E.264 -fate-h264-interlace-crop: CMD = framecrc -vsync 0 -vframes 3 -i $(SAMPLES)/h264/interlaced_crop.mp4 +fate-h264-interlace-crop: CMD = framecrc -vsync 0 -i $(SAMPLES)/h264/interlaced_crop.mp4 -vframes 3 fate-h264-lossless: CMD = framecrc -vsync 0 -i $(SAMPLES)/h264/lossless.h264 fate-h264-extreme-plane-pred: CMD = framemd5 -strict 1 -vsync 0 -i $(SAMPLES)/h264/extreme-plane-pred.h264 From f48053282280e8d72f020264b3ce894c0cd99703 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 29 Aug 2011 09:16:42 +0200 Subject: [PATCH 07/17] avconv: move rate_emu to options context. Make it work properly with multiple input files. --- avconv.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/avconv.c b/avconv.c index c045f465a6..d336cf8561 100644 --- a/avconv.c +++ b/avconv.c @@ -161,8 +161,6 @@ static FILE *vstats_file; static int opt_programid = 0; static int copy_initial_nonkeyframes = 0; -static int rate_emu = 0; - static int audio_volume = 256; static int exit_on_error = 0; @@ -217,6 +215,7 @@ typedef struct InputFile { int64_t ts_offset; int nb_streams; /* number of stream that avconv is aware of; may be different from ctx.nb_streams if new streams appear during av_read_frame() */ + int rate_emu; } InputFile; typedef struct OutputStream { @@ -305,6 +304,7 @@ typedef struct OptionsContext { /* input options */ int64_t input_ts_offset; + int rate_emu; SpecifierOpt *ts_scale; int nb_ts_scale; @@ -1680,7 +1680,7 @@ static int output_packet(InputStream *ist, int ist_index, } /* frame rate emulation */ - if (rate_emu) { + if (input_files[ist->file_index].rate_emu) { int64_t pts = av_rescale(ist->pts, 1000000, AV_TIME_BASE); int64_t now = av_gettime() - ist->start; if (pts > now) @@ -1897,7 +1897,7 @@ static int transcode_init(OutputFile *output_files, InputFile *input_files, int nb_input_files) { - int ret = 0, i; + int ret = 0, i, j; AVFormatContext *os; AVCodecContext *codec, *icodec; OutputStream *ost; @@ -1905,9 +1905,13 @@ static int transcode_init(OutputFile *output_files, char error[1024]; int want_sdp = 1; - if (rate_emu) - for (i = 0; i < nb_input_streams; i++) - input_streams[i].start = av_gettime(); + /* init framerate emulation */ + for (i = 0; i < nb_input_files; i++) { + InputFile *ifile = &input_files[i]; + if (ifile->rate_emu) + for (j = 0; j < ifile->nb_streams; j++) + input_streams[j + ifile->ist_index].start = av_gettime(); + } /* output stream init */ for(i=0;i Date: Wed, 31 Aug 2011 08:45:25 +0200 Subject: [PATCH 08/17] avconv: move bitstream filters to options context. Change syntax -- -[vas]bsf are replaced by -bsf:[stream specifier], the argument is now a comma-separated list of bitstream filters. --- avconv.c | 59 ++++++++++++++++++------------------------------- doc/avconv.texi | 23 +++++++++---------- 2 files changed, 33 insertions(+), 49 deletions(-) diff --git a/avconv.c b/avconv.c index d336cf8561..52b92f80c7 100644 --- a/avconv.c +++ b/avconv.c @@ -183,10 +183,6 @@ static unsigned int allocated_audio_out_size, allocated_audio_buf_size; static short *samples; -static AVBitStreamFilterContext *video_bitstream_filters=NULL; -static AVBitStreamFilterContext *audio_bitstream_filters=NULL; -static AVBitStreamFilterContext *subtitle_bitstream_filters=NULL; - #define DEFAULT_PASS_LOGFILENAME_PREFIX "av2pass" typedef struct InputStream { @@ -328,6 +324,8 @@ typedef struct OptionsContext { int nb_metadata; SpecifierOpt *max_frames; int nb_max_frames; + SpecifierOpt *bitstream_filters; + int nb_bitstream_filters; } OptionsContext; #define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\ @@ -3064,6 +3062,8 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e AVStream *st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0); int idx = oc->nb_streams - 1; int64_t max_frames = INT64_MAX; + char *bsf = NULL, *next; + AVBitStreamFilterContext *bsfc, *bsfc_prev = NULL; if (!st) { av_log(NULL, AV_LOG_ERROR, "Could not alloc stream.\n"); @@ -3088,6 +3088,23 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e MATCH_PER_STREAM_OPT(max_frames, i64, max_frames, oc, st); ost->max_frames = max_frames; + MATCH_PER_STREAM_OPT(bitstream_filters, str, bsf, oc, st); + while (bsf) { + if (next = strchr(bsf, ',')) + *next++ = 0; + if (!(bsfc = av_bitstream_filter_init(bsf))) { + av_log(NULL, AV_LOG_ERROR, "Unknown bitstream filter %s\n", bsf); + exit_program(1); + } + if (bsfc_prev) + bsfc_prev->next = bsfc; + else + ost->bitstream_filters = bsfc; + + bsfc_prev = bsfc; + bsf = next; + } + ost->sws_flags = av_get_int(sws_opts, "sws_flags", NULL); return ost; } @@ -3109,9 +3126,6 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc) #endif } - ost->bitstream_filters = video_bitstream_filters; - video_bitstream_filters= NULL; - video_enc = st->codec; if(video_codec_tag) @@ -3212,9 +3226,6 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc) ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO); st = ost->st; - ost->bitstream_filters = audio_bitstream_filters; - audio_bitstream_filters= NULL; - audio_enc = st->codec; audio_enc->codec_type = AVMEDIA_TYPE_AUDIO; @@ -3282,9 +3293,6 @@ static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc) st = ost->st; subtitle_enc = st->codec; - ost->bitstream_filters = subtitle_bitstream_filters; - subtitle_bitstream_filters= NULL; - subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE; if(subtitle_codec_tag) @@ -4008,27 +4016,6 @@ static int opt_vstats(const char *opt, const char *arg) return opt_vstats_file(opt, filename); } -static int opt_bsf(const char *opt, const char *arg) -{ - AVBitStreamFilterContext *bsfc= av_bitstream_filter_init(arg); //FIXME split name and args for filter at '=' - AVBitStreamFilterContext **bsfp; - - if(!bsfc){ - fprintf(stderr, "Unknown bitstream filter %s\n", arg); - exit_program(1); - } - - bsfp= *opt == 'v' ? &video_bitstream_filters : - *opt == 'a' ? &audio_bitstream_filters : - &subtitle_bitstream_filters; - while(*bsfp) - bsfp= &(*bsfp)->next; - - *bsfp= bsfc; - - return 0; -} - static int opt_video_frames(OptionsContext *o, const char *opt, const char *arg) { return parse_option(o, "frames:v", arg, options); @@ -4146,9 +4133,7 @@ static const OptionDef options[] = { { "muxdelay", OPT_FLOAT | HAS_ARG | OPT_EXPERT, {(void*)&mux_max_delay}, "set the maximum demux-decode delay", "seconds" }, { "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT, {(void*)&mux_preload}, "set the initial demux-decode delay", "seconds" }, - { "absf", HAS_ARG | OPT_AUDIO | OPT_EXPERT, {(void*)opt_bsf}, "", "bitstream_filter" }, - { "vbsf", HAS_ARG | OPT_VIDEO | OPT_EXPERT, {(void*)opt_bsf}, "", "bitstream_filter" }, - { "sbsf", HAS_ARG | OPT_SUBTITLE | OPT_EXPERT, {(void*)opt_bsf}, "", "bitstream_filter" }, + { "bsf", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(bitstream_filters)}, "A comma-separated list of bitstream filters", "bitstream_filters" }, /* data codec support */ { "dcodec", HAS_ARG | OPT_DATA | OPT_FUNC2, {(void*)opt_data_codec}, "force data codec ('copy' to copy stream)", "codec" }, diff --git a/doc/avconv.texi b/doc/avconv.texi index 3ee606a16f..1b9a7929d6 100644 --- a/doc/avconv.texi +++ b/doc/avconv.texi @@ -567,11 +567,6 @@ Intra_dc_precision. Force video tag/fourcc. @item -qphist Show QP histogram. -@item -vbsf @var{bitstream_filter} -Bitstream filters available are "dump_extra", "remove_extra", "noise", "h264_mp4toannexb", "imxdump", "mjpegadump", "mjpeg2jpeg". -@example -avconv -i h264.mp4 -c:v copy -vbsf h264_mp4toannexb -an out.h264 -@end example @item -force_key_frames @var{time}[,@var{time}...] Force key frames at the specified timestamps, more precisely at the first frames after each specified time. @@ -632,8 +627,6 @@ Voice Over @item ka Karaoke @end table -@item -absf @var{bitstream_filter} -Bitstream filters available are "dump_extra", "remove_extra", "noise", "mp3comp", "mp3decomp". @end table @section Subtitle options: @@ -645,11 +638,6 @@ Set the subtitle codec. This is an alias for @code{-codec:s}. Set the ISO 639 language code (3 letters) of the current subtitle stream. @item -sn Disable subtitle recording. -@item -sbsf @var{bitstream_filter} -Bitstream filters available are "mov2textsub", "text2movsub". -@example -avconv -i file.mov -an -vn -sbsf mov2textsub -c:s copy -f rawvideo sub.txt -@end example @end table @section Audio/Video grab options @@ -812,6 +800,17 @@ an output mpegts file: @example avconv -i infile -streamid 0:33 -streamid 1:36 out.ts @end example + +@item -bsf[:@var{stream_specifier}] @var{bitstream_filters} +Set bitstream filters for matching streams. @var{bistream_filters} is +a comma-separated list of bitstream filters. Use the @code{-bsfs} option +to get the list of bitstream filters. +@example +avconv -i h264.mp4 -c:v copy -vbsf h264_mp4toannexb -an out.h264 +@end example +@example +avconv -i file.mov -an -vn -sbsf mov2textsub -c:s copy -f rawvideo sub.txt +@end example @end table @c man end OPTIONS From dc26318c2dd05893843147d8c5b169bd2f498c61 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 31 Aug 2011 08:51:15 +0200 Subject: [PATCH 09/17] avconv: move mux_preload and mux_max_delay to options context --- avconv.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/avconv.c b/avconv.c index 52b92f80c7..d941e695b1 100644 --- a/avconv.c +++ b/avconv.c @@ -140,9 +140,6 @@ static unsigned int subtitle_codec_tag = 0; static int data_disable = 0; static unsigned int data_codec_tag = 0; -static float mux_preload= 0.5; -static float mux_max_delay= 0.7; - static int file_overwrite = 0; static int do_benchmark = 0; static int do_hex_dump = 0; @@ -319,6 +316,8 @@ typedef struct OptionsContext { int64_t recording_time; uint64_t limit_filesize; + float mux_preload; + float mux_max_delay; SpecifierOpt *metadata; int nb_metadata; @@ -368,6 +367,8 @@ static void reset_options(OptionsContext *o) memset(o, 0, sizeof(*o)); + o->mux_preload = 0.5; + o->mux_max_delay = 0.7; o->recording_time = INT64_MAX; o->limit_filesize = UINT64_MAX; o->chapters_input_file = INT_MAX; @@ -3569,8 +3570,8 @@ static void opt_output_file(void *optctx, const char *filename) } } - oc->preload= (int)(mux_preload*AV_TIME_BASE); - oc->max_delay= (int)(mux_max_delay*AV_TIME_BASE); + oc->preload = (int)(o->mux_preload * AV_TIME_BASE); + oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE); oc->flags |= AVFMT_FLAG_NONBLOCK; /* copy chapters */ @@ -3935,7 +3936,7 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg) and the first pack from the other stream, respectively, may also have been written before. So the real data starts at SCR 36000+3*1200. */ - mux_preload= (36000+3*1200) / 90000.0; //0.44 + o->mux_preload = (36000+3*1200) / 90000.0; //0.44 } else if(!strcmp(arg, "svcd")) { opt_video_codec(o, "c:v", "mpeg2video"); @@ -4130,8 +4131,8 @@ static const OptionDef options[] = { { "isync", OPT_BOOL | OPT_EXPERT | OPT_GRAB, {(void*)&input_sync}, "sync read on input", "" }, /* muxer options */ - { "muxdelay", OPT_FLOAT | HAS_ARG | OPT_EXPERT, {(void*)&mux_max_delay}, "set the maximum demux-decode delay", "seconds" }, - { "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT, {(void*)&mux_preload}, "set the initial demux-decode delay", "seconds" }, + { "muxdelay", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET, {.off = OFFSET(mux_max_delay)}, "set the maximum demux-decode delay", "seconds" }, + { "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET, {.off = OFFSET(mux_preload)}, "set the initial demux-decode delay", "seconds" }, { "bsf", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(bitstream_filters)}, "A comma-separated list of bitstream filters", "bitstream_filters" }, From 9bc4e21a9b7900f95d056ae0d450c104a9e80108 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Fri, 2 Sep 2011 11:37:39 +0200 Subject: [PATCH 10/17] wavpack: use context reset in appropriate places This fixes improper flushing in the cases when the same frame is decoded in several iterations (for being too large to fit into output buffer) and flush is called mid-decoding and it also resets context in case of decoding errors. Signed-off-by: Anton Khirnov --- libavcodec/wavpack.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c index 62f68804b3..ea5dfbae16 100644 --- a/libavcodec/wavpack.c +++ b/libavcodec/wavpack.c @@ -470,6 +470,7 @@ static float wv_get_value_float(WavpackFrameContext *s, uint32_t *crc, int S) static void wv_reset_saved_context(WavpackFrameContext *s) { s->pos = 0; + s->samples_left = 0; s->sc.crc = s->extra_sc.crc = 0xFFFFFFFF; } @@ -582,6 +583,7 @@ static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb, vo s->samples_left -= count; if(!s->samples_left){ + wv_reset_saved_context(s); if(crc != s->CRC){ av_log(s->avctx, AV_LOG_ERROR, "CRC error\n"); return -1; @@ -590,7 +592,6 @@ static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb, vo av_log(s->avctx, AV_LOG_ERROR, "Extra bits CRC error\n"); return -1; } - wv_reset_saved_context(s); }else{ s->pos = pos; s->sc.crc = crc; @@ -660,6 +661,7 @@ static inline int wv_unpack_mono(WavpackFrameContext *s, GetBitContext *gb, void s->samples_left -= count; if(!s->samples_left){ + wv_reset_saved_context(s); if(crc != s->CRC){ av_log(s->avctx, AV_LOG_ERROR, "CRC error\n"); return -1; @@ -668,7 +670,6 @@ static inline int wv_unpack_mono(WavpackFrameContext *s, GetBitContext *gb, void av_log(s->avctx, AV_LOG_ERROR, "Extra bits CRC error\n"); return -1; } - wv_reset_saved_context(s); }else{ s->pos = pos; s->sc.crc = crc; @@ -1195,7 +1196,7 @@ static void wavpack_decode_flush(AVCodecContext *avctx) int i; for (i = 0; i < s->fdec_num; i++) - s->fdec[i]->samples_left = 0; + wv_reset_saved_context(s->fdec[i]); } AVCodec ff_wavpack_decoder = { From ff17fc6353c6513316b1132f27ac2a7a8d81b9ec Mon Sep 17 00:00:00 2001 From: Dustin Brody Date: Sat, 3 Sep 2011 15:38:17 -0400 Subject: [PATCH 11/17] mpeg12: propagate more real return values through chunk decode error return and fix some indentation Signed-off-by: Anton Khirnov --- libavcodec/mpeg12.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c index 4b20610cab..574f69a525 100644 --- a/libavcodec/mpeg12.c +++ b/libavcodec/mpeg12.c @@ -1912,7 +1912,7 @@ static int slice_decode_thread(AVCodecContext *c, void *arg){ //ret, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, s->start_mb_y, s->end_mb_y, s->error_count); if(ret < 0){ if (c->error_recognition >= FF_ER_EXPLODE) - return AVERROR_INVALIDDATA; + return ret; if(s->resync_mb_x>=0 && s->resync_mb_y>=0) ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, AC_ERROR|DC_ERROR|MV_ERROR); }else{ @@ -2267,10 +2267,11 @@ static int mpeg_decode_frame(AVCodecContext *avctx, s->slice_count= 0; - if(avctx->extradata && !avctx->frame_number && - decode_chunks(avctx, picture, data_size, avctx->extradata, avctx->extradata_size) < 0 && - avctx->error_recognition >= FF_ER_EXPLODE) - return AVERROR_INVALIDDATA; + if(avctx->extradata && !avctx->frame_number) { + int ret = decode_chunks(avctx, picture, data_size, avctx->extradata, avctx->extradata_size); + if (ret < 0 && avctx->error_recognition >= FF_ER_EXPLODE) + return ret; + } return decode_chunks(avctx, picture, data_size, buf, buf_size); } @@ -2344,17 +2345,17 @@ static int decode_chunks(AVCodecContext *avctx, s->slice_count = 0; } if(last_code == 0 || last_code == SLICE_MIN_START_CODE){ - if(mpeg_decode_postinit(avctx) < 0){ - av_log(avctx, AV_LOG_ERROR, "mpeg_decode_postinit() failure\n"); - return -1; - } + ret = mpeg_decode_postinit(avctx); + if(ret < 0){ + av_log(avctx, AV_LOG_ERROR, "mpeg_decode_postinit() failure\n"); + return ret; + } - /* we have a complete image: we try to decompress it */ - if(mpeg1_decode_picture(avctx, - buf_ptr, input_size) < 0) - s2->pict_type=0; + /* we have a complete image: we try to decompress it */ + if (mpeg1_decode_picture(avctx, buf_ptr, input_size) < 0) + s2->pict_type=0; s2->first_slice = 1; - last_code= PICTURE_START_CODE; + last_code= PICTURE_START_CODE; }else{ av_log(avctx, AV_LOG_ERROR, "ignoring pic after %X\n", last_code); if (avctx->error_recognition >= FF_ER_EXPLODE) @@ -2400,9 +2401,8 @@ static int decode_chunks(AVCodecContext *avctx, break; case GOP_START_CODE: if(last_code == 0){ - s2->first_field=0; - mpeg_decode_gop(avctx, - buf_ptr, input_size); + s2->first_field=0; + mpeg_decode_gop(avctx, buf_ptr, input_size); s->sync=1; }else{ av_log(avctx, AV_LOG_ERROR, "ignoring GOP_START_CODE after %X\n", last_code); @@ -2464,9 +2464,7 @@ static int decode_chunks(AVCodecContext *avctx, } if(!s2->current_picture_ptr){ av_log(avctx, AV_LOG_ERROR, "current_picture not initialized\n"); - if (avctx->error_recognition >= FF_ER_EXPLODE) - return AVERROR_INVALIDDATA; - return -1; + return AVERROR_INVALIDDATA; } if (avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU) { @@ -2495,7 +2493,7 @@ static int decode_chunks(AVCodecContext *avctx, if(ret < 0){ if (avctx->error_recognition >= FF_ER_EXPLODE) - return AVERROR_INVALIDDATA; + return ret; if(s2->resync_mb_x>=0 && s2->resync_mb_y>=0) ff_er_add_slice(s2, s2->resync_mb_x, s2->resync_mb_y, s2->mb_x, s2->mb_y, AC_ERROR|DC_ERROR|MV_ERROR); }else{ From bc5acfa7af01d7ac947159b3337d41692e29ee8a Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 4 Sep 2011 10:01:59 +0200 Subject: [PATCH 12/17] fate: use +frame+slice named constants instead of '3' --- tests/fate-run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fate-run.sh b/tests/fate-run.sh index f623eecae6..56514c8120 100755 --- a/tests/fate-run.sh +++ b/tests/fate-run.sh @@ -16,7 +16,7 @@ cmp=${6:-diff} ref=${7:-"${base}/ref/fate/${test}"} fuzz=$8 threads=${9:-1} -thread_type=${10:-3} +thread_type=${10:-frame+slice} outdir="tests/data/fate" outfile="${outdir}/${test}" From a2a38d9665802a2b53d6c864128ecb06db96e19c Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 5 Sep 2011 11:39:09 +0200 Subject: [PATCH 13/17] avconv: fix parsing metadata specifiers. After 039267f192f335144d9251e6f05a1513dd1e8ef1, metadata specifiers are passed without the leading ':'. Remove a ++ that didn't take this into account. --- avconv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avconv.c b/avconv.c index d941e695b1..09d4886b95 100644 --- a/avconv.c +++ b/avconv.c @@ -2730,7 +2730,7 @@ static int opt_map(OptionsContext *o, const char *opt, const char *arg) static void parse_meta_type(char *arg, char *type, int *index) { if (*arg) { - *type = *(++arg); + *type = *arg; switch (*arg) { case 'g': break; From bcd4aa8bec19a17bd633e3db13357784c05b6ca5 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Mon, 5 Sep 2011 12:37:50 +0200 Subject: [PATCH 14/17] wavpack: fix wrong return value in wavpack_decode_block() This function should return number of samples decoded, not number of bytes decoded. Spotted by Uoti Urpala. Signed-off-by: Luca Barbato --- libavcodec/wavpack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c index ea5dfbae16..22fab3804c 100644 --- a/libavcodec/wavpack.c +++ b/libavcodec/wavpack.c @@ -780,7 +780,7 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, s->samples = AV_RL32(buf); buf += 4; if(!s->samples){ *data_size = 0; - return buf_size; + return 0; } }else{ s->samples = wc->samples; From 3e5722a8cadd8b4a7f92110b9a0b2f48883f1243 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Fri, 26 Aug 2011 13:02:29 -0400 Subject: [PATCH 15/17] ac3enc: fix encoding of stereo ac3 files when rematrixing is disabled. The number of rematrixing bands still needs to be calculated. --- libavcodec/ac3enc_template.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libavcodec/ac3enc_template.c b/libavcodec/ac3enc_template.c index dd759a732b..3db49debbb 100644 --- a/libavcodec/ac3enc_template.c +++ b/libavcodec/ac3enc_template.c @@ -352,11 +352,6 @@ static void compute_rematrixing_strategy(AC3EncodeContext *s) block = &s->blocks[blk]; block->new_rematrixing_strategy = !blk; - if (!s->rematrixing_enabled) { - block0 = block; - continue; - } - block->num_rematrixing_bands = 4; if (block->cpl_in_use) { block->num_rematrixing_bands -= (s->start_freq[CPL_CH] <= 61); @@ -366,6 +361,11 @@ static void compute_rematrixing_strategy(AC3EncodeContext *s) } nb_coefs = FFMIN(block->end_freq[1], block->end_freq[2]); + if (!s->rematrixing_enabled) { + block0 = block; + continue; + } + for (bnd = 0; bnd < block->num_rematrixing_bands; bnd++) { /* calculate calculate sum of squared coeffs for one band in one block */ int start = ff_ac3_rematrix_band_tab[bnd]; From a0d17b6d45b8550bd8826baa9f8eb4e1a596525a Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Sun, 7 Aug 2011 17:51:13 -0400 Subject: [PATCH 16/17] ac3enc: scale floating-point coupling channel coefficients in scale_coefficients() rather than in apply_channel_coupling() --- libavcodec/ac3enc_float.c | 7 ++++--- libavcodec/ac3enc_template.c | 4 ---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/libavcodec/ac3enc_float.c b/libavcodec/ac3enc_float.c index 8e74aaf285..32ec558e70 100644 --- a/libavcodec/ac3enc_float.c +++ b/libavcodec/ac3enc_float.c @@ -104,9 +104,10 @@ static int normalize_samples(AC3EncodeContext *s) static void scale_coefficients(AC3EncodeContext *s) { int chan_size = AC3_MAX_COEFS * s->num_blocks; - s->ac3dsp.float_to_fixed24(s->fixed_coef_buffer + chan_size, - s->mdct_coef_buffer + chan_size, - chan_size * s->channels); + int cpl = s->cpl_on; + s->ac3dsp.float_to_fixed24(s->fixed_coef_buffer + (chan_size * !cpl), + s->mdct_coef_buffer + (chan_size * !cpl), + chan_size * (s->channels + cpl)); } diff --git a/libavcodec/ac3enc_template.c b/libavcodec/ac3enc_template.c index 3db49debbb..e7b8967edd 100644 --- a/libavcodec/ac3enc_template.c +++ b/libavcodec/ac3enc_template.c @@ -168,10 +168,6 @@ static void apply_channel_coupling(AC3EncodeContext *s) /* coefficients must be clipped in order to be encoded */ clip_coefficients(&s->dsp, cpl_coef, num_cpl_coefs); - - /* scale coupling coefficients from float to 24-bit fixed-point */ - s->ac3dsp.float_to_fixed24(&block->fixed_coef[CPL_CH][cpl_start], - cpl_coef, num_cpl_coefs); } /* calculate energy in each band in coupling channel and each fbw channel */ From ae264bb29be3506a489347c6e27a04cded0de621 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Sun, 7 Aug 2011 17:47:42 -0400 Subject: [PATCH 17/17] ac3enc: Add channel coupling support for the fixed-point AC-3 encoder. Update FATE references accordingly. --- libavcodec/ac3enc.c | 2 +- libavcodec/ac3enc.h | 2 ++ libavcodec/ac3enc_fixed.c | 17 +++++++++++++++ libavcodec/ac3enc_float.c | 12 +++++++++++ libavcodec/ac3enc_opts_template.c | 2 -- libavcodec/ac3enc_template.c | 32 +++++++++++++--------------- tests/ref/acodec/ac3_fixed | 2 +- tests/ref/seek/ac3_rm | 35 ++++++++++++++++++------------- 8 files changed, 67 insertions(+), 37 deletions(-) diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c index 3cfbbdf969..cf9c4d179f 100644 --- a/libavcodec/ac3enc.c +++ b/libavcodec/ac3enc.c @@ -2167,7 +2167,7 @@ static av_cold int validate_options(AC3EncodeContext *s) (s->channel_mode == AC3_CHMODE_STEREO); s->cpl_enabled = s->options.channel_coupling && - s->channel_mode >= AC3_CHMODE_STEREO && !s->fixed_point; + s->channel_mode >= AC3_CHMODE_STEREO; return 0; } diff --git a/libavcodec/ac3enc.h b/libavcodec/ac3enc.h index 65e88c9e01..bf5ccea19f 100644 --- a/libavcodec/ac3enc.h +++ b/libavcodec/ac3enc.h @@ -52,6 +52,7 @@ #define MAC_COEF(d,a,b) ((d)+=(a)*(b)) #define COEF_MIN (-16777215.0/16777216.0) #define COEF_MAX ( 16777215.0/16777216.0) +#define NEW_CPL_COORD_THRESHOLD 0.03 typedef float SampleType; typedef float CoefType; typedef float CoefSumType; @@ -60,6 +61,7 @@ typedef float CoefSumType; #define MAC_COEF(d,a,b) MAC64(d,a,b) #define COEF_MIN -16777215 #define COEF_MAX 16777215 +#define NEW_CPL_COORD_THRESHOLD 503317 typedef int16_t SampleType; typedef int32_t CoefType; typedef int64_t CoefSumType; diff --git a/libavcodec/ac3enc_fixed.c b/libavcodec/ac3enc_fixed.c index 951b73d69b..adb735279d 100644 --- a/libavcodec/ac3enc_fixed.c +++ b/libavcodec/ac3enc_fixed.c @@ -29,6 +29,7 @@ #define CONFIG_FFT_FLOAT 0 #undef CONFIG_AC3ENC_FLOAT #include "ac3enc.h" +#include "eac3enc.h" #define AC3ENC_TYPE AC3ENC_TYPE_AC3_FIXED #include "ac3enc_opts_template.c" @@ -112,6 +113,22 @@ static void clip_coefficients(DSPContext *dsp, int32_t *coef, unsigned int len) } +/** + * Calculate a single coupling coordinate. + */ +static CoefType calc_cpl_coord(CoefSumType energy_ch, CoefSumType energy_cpl) +{ + if (energy_cpl <= COEF_MAX) { + return 1048576; + } else { + uint64_t coord = energy_ch / (energy_cpl >> 24); + uint32_t coord32 = FFMIN(coord, 1073741824); + coord32 = ff_sqrt(coord32) << 9; + return FFMIN(coord32, COEF_MAX); + } +} + + static av_cold int ac3_fixed_encode_init(AVCodecContext *avctx) { AC3EncodeContext *s = avctx->priv_data; diff --git a/libavcodec/ac3enc_float.c b/libavcodec/ac3enc_float.c index 32ec558e70..598c69db1b 100644 --- a/libavcodec/ac3enc_float.c +++ b/libavcodec/ac3enc_float.c @@ -120,6 +120,18 @@ static void clip_coefficients(DSPContext *dsp, float *coef, unsigned int len) } +/** + * Calculate a single coupling coordinate. + */ +static CoefType calc_cpl_coord(CoefSumType energy_ch, CoefSumType energy_cpl) +{ + float coord = 0.125; + if (energy_cpl > 0) + coord *= sqrtf(energy_ch / energy_cpl); + return FFMIN(coord, COEF_MAX); +} + + #if CONFIG_AC3_ENCODER AVCodec ff_ac3_encoder = { .name = "ac3", diff --git a/libavcodec/ac3enc_opts_template.c b/libavcodec/ac3enc_opts_template.c index fdbbd5f743..a8bbedbf9e 100644 --- a/libavcodec/ac3enc_opts_template.c +++ b/libavcodec/ac3enc_opts_template.c @@ -72,11 +72,9 @@ static const AVOption eac3_options[] = { {"hdcd", "HDCD", 0, FF_OPT_TYPE_CONST, {.dbl = AC3ENC_OPT_ADCONV_HDCD }, INT_MIN, INT_MAX, AC3ENC_PARAM, "ad_conv_type"}, /* Other Encoding Options */ {"stereo_rematrixing", "Stereo Rematrixing", OFFSET(stereo_rematrixing), FF_OPT_TYPE_INT, {.dbl = AC3ENC_OPT_ON }, AC3ENC_OPT_OFF, AC3ENC_OPT_ON, AC3ENC_PARAM}, -#if AC3ENC_TYPE != AC3ENC_TYPE_AC3_FIXED {"channel_coupling", "Channel Coupling", OFFSET(channel_coupling), FF_OPT_TYPE_INT, {.dbl = AC3ENC_OPT_AUTO }, AC3ENC_OPT_AUTO, AC3ENC_OPT_ON, AC3ENC_PARAM, "channel_coupling"}, {"auto", "Selected by the Encoder", 0, FF_OPT_TYPE_CONST, {.dbl = AC3ENC_OPT_AUTO }, INT_MIN, INT_MAX, AC3ENC_PARAM, "channel_coupling"}, {"cpl_start_band", "Coupling Start Band", OFFSET(cpl_start), FF_OPT_TYPE_INT, {.dbl = AC3ENC_OPT_AUTO }, AC3ENC_OPT_AUTO, 15, AC3ENC_PARAM, "cpl_start_band"}, {"auto", "Selected by the Encoder", 0, FF_OPT_TYPE_CONST, {.dbl = AC3ENC_OPT_AUTO }, INT_MIN, INT_MAX, AC3ENC_PARAM, "cpl_start_band"}, -#endif {NULL} }; diff --git a/libavcodec/ac3enc_template.c b/libavcodec/ac3enc_template.c index e7b8967edd..7e2bf3a9ca 100644 --- a/libavcodec/ac3enc_template.c +++ b/libavcodec/ac3enc_template.c @@ -41,6 +41,8 @@ static int normalize_samples(AC3EncodeContext *s); static void clip_coefficients(DSPContext *dsp, CoefType *coef, unsigned int len); +static CoefType calc_cpl_coord(CoefSumType energy_ch, CoefSumType energy_cpl); + int AC3_NAME(allocate_sample_buffers)(AC3EncodeContext *s) { @@ -118,32 +120,25 @@ static void apply_mdct(AC3EncodeContext *s) } -/** - * Calculate a single coupling coordinate. - */ -static inline float calc_cpl_coord(float energy_ch, float energy_cpl) -{ - float coord = 0.125; - if (energy_cpl > 0) - coord *= sqrtf(energy_ch / energy_cpl); - return FFMIN(coord, COEF_MAX); -} - - /** * Calculate coupling channel and coupling coordinates. */ static void apply_channel_coupling(AC3EncodeContext *s) { + LOCAL_ALIGNED_16(CoefType, cpl_coords, [AC3_MAX_BLOCKS], [AC3_MAX_CHANNELS][16]); #if CONFIG_AC3ENC_FLOAT - LOCAL_ALIGNED_16(float, cpl_coords, [AC3_MAX_BLOCKS], [AC3_MAX_CHANNELS][16]); LOCAL_ALIGNED_16(int32_t, fixed_cpl_coords, [AC3_MAX_BLOCKS], [AC3_MAX_CHANNELS][16]); +#else + int32_t (*fixed_cpl_coords)[AC3_MAX_CHANNELS][16] = cpl_coords; +#endif int blk, ch, bnd, i, j; CoefSumType energy[AC3_MAX_BLOCKS][AC3_MAX_CHANNELS][16] = {{{0}}}; int cpl_start, num_cpl_coefs; memset(cpl_coords, 0, AC3_MAX_BLOCKS * sizeof(*cpl_coords)); - memset(fixed_cpl_coords, 0, AC3_MAX_BLOCKS * sizeof(*fixed_cpl_coords)); +#if CONFIG_AC3ENC_FLOAT + memset(fixed_cpl_coords, 0, AC3_MAX_BLOCKS * sizeof(*cpl_coords)); +#endif /* align start to 16-byte boundary. align length to multiple of 32. note: coupling start bin % 4 will always be 1 */ @@ -231,11 +226,11 @@ static void apply_channel_coupling(AC3EncodeContext *s) } else { CoefSumType coord_diff = 0; for (bnd = 0; bnd < s->num_cpl_bands; bnd++) { - coord_diff += fabs(cpl_coords[blk-1][ch][bnd] - - cpl_coords[blk ][ch][bnd]); + coord_diff += FFABS(cpl_coords[blk-1][ch][bnd] - + cpl_coords[blk ][ch][bnd]); } coord_diff /= s->num_cpl_bands; - if (coord_diff > 0.03) + if (coord_diff > NEW_CPL_COORD_THRESHOLD) block->new_cpl_coords[ch] = 1; } } @@ -282,9 +277,11 @@ static void apply_channel_coupling(AC3EncodeContext *s) if (!block->cpl_in_use) continue; +#if CONFIG_AC3ENC_FLOAT s->ac3dsp.float_to_fixed24(fixed_cpl_coords[blk][1], cpl_coords[blk][1], s->fbw_channels * 16); +#endif s->ac3dsp.extract_exponents(block->cpl_coord_exp[1], fixed_cpl_coords[blk][1], s->fbw_channels * 16); @@ -328,7 +325,6 @@ static void apply_channel_coupling(AC3EncodeContext *s) if (CONFIG_EAC3_ENCODER && s->eac3) ff_eac3_set_cpl_states(s); -#endif /* CONFIG_AC3ENC_FLOAT */ } diff --git a/tests/ref/acodec/ac3_fixed b/tests/ref/acodec/ac3_fixed index ca8a082c75..dba2dfc5e7 100644 --- a/tests/ref/acodec/ac3_fixed +++ b/tests/ref/acodec/ac3_fixed @@ -1,2 +1,2 @@ -0f14801e166819dd4a58981aea36e08b *./tests/data/acodec/ac3.rm +e7fa185030a56d9db8663ad9e38c6c94 *./tests/data/acodec/ac3.rm 98751 ./tests/data/acodec/ac3.rm diff --git a/tests/ref/seek/ac3_rm b/tests/ref/seek/ac3_rm index 05772fcf98..b38758bb2c 100644 --- a/tests/ref/seek/ac3_rm +++ b/tests/ref/seek/ac3_rm @@ -5,35 +5,40 @@ ret:-1 st:-1 flags:1 ts: 1.894167 ret:-1 st: 0 flags:0 ts: 0.788000 ret: 0 st: 0 flags:1 ts:-0.317000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 271 size: 556 -ret: 0 st:-1 flags:0 ts: 2.576668 -ret: 0 st: 0 flags:1 dts: 2.577000 pts: 2.577000 pos: 42397 size: 558 +ret:-1 st:-1 flags:0 ts: 2.576668 ret:-1 st:-1 flags:1 ts: 1.470835 ret:-1 st: 0 flags:0 ts: 0.365000 ret: 0 st: 0 flags:1 ts:-0.741000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 271 size: 556 -ret: 0 st:-1 flags:0 ts: 2.153336 -ret: 0 st: 0 flags:1 dts: 2.159000 pts: 2.159000 pos: 35567 size: 556 +ret:-1 st:-1 flags:0 ts: 2.153336 ret:-1 st:-1 flags:1 ts: 1.047503 ret: 0 st: 0 flags:0 ts:-0.058000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 271 size: 556 ret:-1 st: 0 flags:1 ts: 2.836000 -ret:-1 st:-1 flags:0 ts: 1.730004 -ret:-1 st:-1 flags:1 ts: 0.624171 +ret: 0 st:-1 flags:0 ts: 1.730004 +ret: 0 st: 0 flags:1 dts:8589.800000 pts:8589.800000 pos: 65950 size: 32801 +ret: 0 st:-1 flags:1 ts: 0.624171 +ret: 0 st: 0 flags:1 dts: 0.256000 pts: 0.256000 pos: 65337 size: 400 ret: 0 st: 0 flags:0 ts:-0.482000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 271 size: 556 -ret: 0 st: 0 flags:1 ts: 2.413000 -ret: 0 st: 0 flags:1 dts: 2.368000 pts: 2.368000 pos: 38981 size: 558 -ret:-1 st:-1 flags:0 ts: 1.306672 -ret:-1 st:-1 flags:1 ts: 0.200839 +ret:-1 st: 0 flags:1 ts: 2.413000 +ret: 0 st:-1 flags:0 ts: 1.306672 +ret: 0 st: 0 flags:1 dts:8589.800000 pts:8589.800000 pos: 65950 size: 32801 +ret: 0 st:-1 flags:1 ts: 0.200839 +ret: 0 st: 0 flags:1 dts: 0.034000 pts: 0.034000 pos: 839 size: 558 ret: 0 st: 0 flags:0 ts:-0.905000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 271 size: 556 -ret:-1 st: 0 flags:1 ts: 1.989000 -ret:-1 st:-1 flags:0 ts: 0.883340 +ret: 0 st: 0 flags:1 ts: 1.989000 +ret: 0 st: 0 flags:1 dts: 0.256000 pts: 0.256000 pos: 65337 size: 400 +ret: 0 st:-1 flags:0 ts: 0.883340 +ret: 0 st: 0 flags:1 dts: 3.378000 pts: 3.378000 pos: 55491 size: 558 ret: 0 st:-1 flags:1 ts:-0.222493 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 271 size: 556 ret: 0 st: 0 flags:0 ts: 2.672000 -ret: 0 st: 0 flags:1 dts: 2.821000 pts: 2.821000 pos: 46383 size: 556 -ret:-1 st: 0 flags:1 ts: 1.566000 -ret:-1 st:-1 flags:0 ts: 0.460008 +ret: 0 st: 0 flags:1 dts: 3.378000 pts: 3.378000 pos: 55491 size: 558 +ret: 0 st: 0 flags:1 ts: 1.566000 +ret: 0 st: 0 flags:1 dts: 0.256000 pts: 0.256000 pos: 65337 size: 400 +ret: 0 st:-1 flags:0 ts: 0.460008 +ret: 0 st: 0 flags:1 dts: 3.378000 pts: 3.378000 pos: 55491 size: 558 ret: 0 st:-1 flags:1 ts:-0.645825 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 271 size: 556