aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2011-08-30 04:10:54 +0200
committerMichael Niedermayer <michaelni@gmx.at>2011-08-30 17:57:59 +0200
commite3bf4e292cf999c9b8442a4e23677cab0b4781a9 (patch)
treef10095d0105e3e41321bb8358c6de860da8e0b74
parenta0147957e70aecd9d3e06f69a53d26456f061fc9 (diff)
downloadffmpeg-e3bf4e292cf999c9b8442a4e23677cab0b4781a9.tar.gz
ffmpeg: replace -vcodec/-acodec/-scodec with a better system.
The new option doesn't depend on its placement wrt -new* options (which don't exist anymore) and works in a similar way as per-stream AVOptions. -[vas]codec remain as aliases to -codec:[vas]
-rw-r--r--ffmpeg.c246
1 files changed, 97 insertions, 149 deletions
diff --git a/ffmpeg.c b/ffmpeg.c
index 1e45cd10b3..9cd6371fda 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -122,6 +122,8 @@ static int nb_output_files = 0;
static StreamMap *stream_maps = NULL;
static int nb_stream_maps;
+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;
@@ -149,7 +151,6 @@ static uint16_t *inter_matrix = NULL;
static const char *video_rc_override_string=NULL;
static int video_disable = 0;
static int video_discard = 0;
-static char *video_codec_name = NULL;
static unsigned int video_codec_tag = 0;
static char *video_language = NULL;
static int same_quant = 0;
@@ -170,17 +171,14 @@ static int audio_sample_rate = 0;
static float audio_qscale = QSCALE_NONE;
static int audio_disable = 0;
static int audio_channels = 0;
-static char *audio_codec_name = NULL;
static unsigned int audio_codec_tag = 0;
static char *audio_language = NULL;
static int subtitle_disable = 0;
-static char *subtitle_codec_name = NULL;
static char *subtitle_language = NULL;
static unsigned int subtitle_codec_tag = 0;
static int data_disable = 0;
-static char *data_codec_name = NULL;
static unsigned int data_codec_tag = 0;
static float mux_preload= 0.5;
@@ -197,10 +195,6 @@ static int do_pkt_dump = 0;
static int do_psnr = 0;
static int do_pass = 0;
static const char *pass_logfilename_prefix;
-static int audio_stream_copy = 0;
-static int video_stream_copy = 0;
-static int subtitle_stream_copy = 0;
-static int data_stream_copy = 0;
static int video_sync_method= -1;
static int audio_sync_method= 0;
static float audio_drift_threshold= 0.1;
@@ -550,11 +544,6 @@ static int exit_program(int ret)
av_freep(&input_streams);
av_freep(&input_files);
- av_free(video_codec_name);
- av_free(audio_codec_name);
- av_free(subtitle_codec_name);
- av_free(data_codec_name);
-
uninit_opts();
av_free(audio_buf);
av_free(audio_out);
@@ -691,7 +680,59 @@ static void choose_pixel_fmt(AVStream *st, AVCodec *codec)
}
}
-static OutputStream *new_output_stream(AVFormatContext *oc, int file_idx, AVCodec *codec)
+static enum CodecID find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
+{
+ const char *codec_string = encoder ? "encoder" : "decoder";
+ AVCodec *codec;
+
+ if(!name)
+ return CODEC_ID_NONE;
+ codec = encoder ?
+ avcodec_find_encoder_by_name(name) :
+ avcodec_find_decoder_by_name(name);
+ if(!codec) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown %s '%s'\n", codec_string, name);
+ exit_program(1);
+ }
+ if(codec->type != type) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid %s type '%s'\n", codec_string, name);
+ exit_program(1);
+ }
+ return codec->id;
+}
+
+static AVCodec *choose_codec(AVFormatContext *s, AVStream *st, enum AVMediaType type, AVDictionary *codec_names)
+{
+ 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);
+ }
+
+ if (!codec_name) {
+ if (s->oformat) {
+ st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename, NULL, type);
+ return avcodec_find_encoder(st->codec->codec_id);
+ }
+ } else if (!strcmp(codec_name, "copy"))
+ st->stream_copy = 1;
+ else {
+ st->codec->codec_id = find_codec_or_die(codec_name, type, s->iformat == NULL);
+ return s->oformat ? avcodec_find_encoder_by_name(codec_name) :
+ avcodec_find_decoder_by_name(codec_name);
+ }
+
+ return NULL;
+}
+
+static OutputStream *new_output_stream(AVFormatContext *oc, int file_idx, enum AVMediaType type)
{
OutputStream *ost;
AVStream *st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0);
@@ -716,13 +757,14 @@ static OutputStream *new_output_stream(AVFormatContext *oc, int file_idx, AVCode
ost->file_index = file_idx;
ost->index = idx;
ost->st = st;
- ost->enc = codec;
- if (codec) {
- st->codec->codec_type = codec->type;
- ost->opts = filter_codec_opts(codec_opts, codec->id, oc, st);
+ st->codec->codec_type = type;
+ ost->enc = choose_codec(oc, st, type, codec_names);
+ if (ost->enc) {
+ ost->opts = filter_codec_opts(codec_opts, ost->enc->id, oc, st);
}
- avcodec_get_context_defaults3(st->codec, codec);
+ 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
ost->sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
return ost;
@@ -743,7 +785,7 @@ static int read_ffserver_streams(AVFormatContext *s, const char *filename)
AVCodec *codec;
codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
- ost = new_output_stream(s, nb_output_files, codec);
+ ost = new_output_stream(s, nb_output_files, codec->type);
st = ost->st;
// FIXME: a more elegant solution is needed
@@ -752,17 +794,10 @@ static int read_ffserver_streams(AVFormatContext *s, const char *filename)
memcpy(st->info, ic->streams[i]->info, sizeof(*st->info));
avcodec_copy_context(st->codec, ic->streams[i]->codec);
- if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
- if (audio_stream_copy) {
- st->stream_copy = 1;
- } else
- choose_sample_fmt(st, codec);
- } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
- if (video_stream_copy) {
- st->stream_copy = 1;
- } else
- choose_pixel_fmt(st, codec);
- }
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && !st->stream_copy)
+ choose_sample_fmt(st, codec);
+ else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !st->stream_copy)
+ choose_pixel_fmt(st, codec);
}
av_close_input_file(ic);
@@ -2916,36 +2951,29 @@ static int opt_video_standard(const char *opt, const char *arg)
return opt_default("standard", arg);
}
-static int opt_codec(int *pstream_copy, char **pcodec_name,
- int codec_type, const char *arg)
+static int opt_codec(const char *opt, const char *arg)
{
- av_freep(pcodec_name);
- if (!strcmp(arg, "copy")) {
- *pstream_copy = 1;
- } else {
- *pcodec_name = av_strdup(arg);
- }
- return 0;
+ return av_dict_set(&codec_names, opt, arg, 0);
}
static int opt_audio_codec(const char *opt, const char *arg)
{
- return opt_codec(&audio_stream_copy, &audio_codec_name, AVMEDIA_TYPE_AUDIO, arg);
+ return opt_codec("codec:a", arg);
}
static int opt_video_codec(const char *opt, const char *arg)
{
- return opt_codec(&video_stream_copy, &video_codec_name, AVMEDIA_TYPE_VIDEO, arg);
+ return opt_codec("codec:v", arg);
}
static int opt_subtitle_codec(const char *opt, const char *arg)
{
- return opt_codec(&subtitle_stream_copy, &subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, arg);
+ return opt_codec("codec:s", arg);
}
static int opt_data_codec(const char *opt, const char *arg)
{
- return opt_codec(&data_stream_copy, &data_codec_name, AVMEDIA_TYPE_DATA, arg);
+ return opt_codec("codec:d", arg);
}
static int opt_codec_tag(const char *opt, const char *arg)
@@ -3153,26 +3181,6 @@ static int opt_input_ts_offset(const char *opt, const char *arg)
return 0;
}
-static enum CodecID find_codec_or_die(const char *name, int type, int encoder)
-{
- const char *codec_string = encoder ? "encoder" : "decoder";
- AVCodec *codec;
-
- if(!name)
- return CODEC_ID_NONE;
- codec = encoder ?
- avcodec_find_encoder_by_name(name) :
- avcodec_find_decoder_by_name(name);
- if(!codec) {
- fprintf(stderr, "Unknown %s '%s'\n", codec_string, name);
- exit_program(1);
- }
- if(codec->type != type) {
- fprintf(stderr, "Invalid %s type '%s'\n", codec_string, name);
- exit_program(1);
- }
- return codec->id;
-}
static int opt_input_file(const char *opt, const char *filename)
{
@@ -3223,12 +3231,6 @@ static int opt_input_file(const char *opt, const char *filename)
if (frame_pix_fmt != PIX_FMT_NONE)
av_dict_set(&format_opts, "pixel_format", av_get_pix_fmt_name(frame_pix_fmt), 0);
- ic->video_codec_id =
- find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0);
- ic->audio_codec_id =
- find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0);
- ic->subtitle_codec_id=
- find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0);
ic->flags |= AVFMT_FLAG_NONBLOCK;
if (loop_input) {
@@ -3268,6 +3270,10 @@ static int opt_input_file(const char *opt, const char *filename)
opt_programid=0;
}
+ /* 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);
+
/* Set AVCodecContext options for avformat_find_stream_info */
opts = setup_find_stream_info_opts(ic, codec_opts);
orig_nb_streams = ic->nb_streams;
@@ -3315,16 +3321,16 @@ static int opt_input_file(const char *opt, const char *filename)
if (i < nb_ts_scale)
ist->ts_scale = ts_scale[i];
+ ist->dec = choose_codec(ic, st, dec->codec_type, codec_names);
+
switch (dec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
- ist->dec = avcodec_find_decoder_by_name(audio_codec_name);
if(!ist->dec)
ist->dec = avcodec_find_decoder(dec->codec_id);
if(audio_disable)
st->discard= AVDISCARD_ALL;
break;
case AVMEDIA_TYPE_VIDEO:
- ist->dec= avcodec_find_decoder_by_name(video_codec_name);
if(!ist->dec)
ist->dec = avcodec_find_decoder(dec->codec_id);
rfps = ic->streams[i]->r_frame_rate.num;
@@ -3352,7 +3358,6 @@ static int opt_input_file(const char *opt, const char *filename)
case AVMEDIA_TYPE_DATA:
break;
case AVMEDIA_TYPE_SUBTITLE:
- ist->dec = avcodec_find_decoder_by_name(subtitle_codec_name);
if(!ist->dec)
ist->dec = avcodec_find_decoder(dec->codec_id);
if(subtitle_disable)
@@ -3390,9 +3395,7 @@ static int opt_input_file(const char *opt, const char *filename)
for (i = 0; i < orig_nb_streams; i++)
av_dict_free(&opts[i]);
av_freep(&opts);
- av_freep(&video_codec_name);
- av_freep(&audio_codec_name);
- av_freep(&subtitle_codec_name);
+ av_dict_free(&codec_names);
uninit_opts();
init_opts();
return 0;
@@ -3403,22 +3406,10 @@ static OutputStream *new_video_stream(AVFormatContext *oc, int file_idx)
AVStream *st;
OutputStream *ost;
AVCodecContext *video_enc;
- enum CodecID codec_id = CODEC_ID_NONE;
- AVCodec *codec= NULL;
-
- if(!video_stream_copy){
- if (video_codec_name) {
- codec_id = find_codec_or_die(video_codec_name, AVMEDIA_TYPE_VIDEO, 1);
- codec = avcodec_find_encoder_by_name(video_codec_name);
- } else {
- codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_VIDEO);
- codec = avcodec_find_encoder(codec_id);
- }
- }
- ost = new_output_stream(oc, file_idx, codec);
+ ost = new_output_stream(oc, file_idx, AVMEDIA_TYPE_VIDEO);
st = ost->st;
- if (!video_stream_copy) {
+ if (!st->stream_copy) {
ost->frame_aspect_ratio = frame_aspect_ratio;
frame_aspect_ratio = 0;
#if CONFIG_AVFILTER
@@ -3441,9 +3432,7 @@ static OutputStream *new_video_stream(AVFormatContext *oc, int file_idx)
video_enc->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
- video_enc->codec_type = AVMEDIA_TYPE_VIDEO;
- if (video_stream_copy) {
- st->stream_copy = 1;
+ if (st->stream_copy) {
video_enc->sample_aspect_ratio =
st->sample_aspect_ratio = av_d2q(frame_aspect_ratio*frame_height/frame_width, 255);
} else {
@@ -3452,7 +3441,6 @@ static OutputStream *new_video_stream(AVFormatContext *oc, int file_idx)
if (frame_rate.num)
ost->frame_rate = frame_rate;
- video_enc->codec_id = codec_id;
video_enc->width = frame_width;
video_enc->height = frame_height;
@@ -3524,9 +3512,7 @@ static OutputStream *new_video_stream(AVFormatContext *oc, int file_idx)
/* reset some key parameters */
video_disable = 0;
- av_freep(&video_codec_name);
av_freep(&forced_key_frames);
- video_stream_copy = 0;
frame_pix_fmt = PIX_FMT_NONE;
return ost;
}
@@ -3535,20 +3521,9 @@ static OutputStream *new_audio_stream(AVFormatContext *oc, int file_idx)
{
AVStream *st;
OutputStream *ost;
- AVCodec *codec= NULL;
AVCodecContext *audio_enc;
- enum CodecID codec_id = CODEC_ID_NONE;
- if(!audio_stream_copy){
- if (audio_codec_name) {
- codec_id = find_codec_or_die(audio_codec_name, AVMEDIA_TYPE_AUDIO, 1);
- codec = avcodec_find_encoder_by_name(audio_codec_name);
- } else {
- codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_AUDIO);
- codec = avcodec_find_encoder(codec_id);
- }
- }
- ost = new_output_stream(oc, file_idx, codec);
+ ost = new_output_stream(oc, file_idx, AVMEDIA_TYPE_AUDIO);
st = ost->st;
ost->bitstream_filters = audio_bitstream_filters;
@@ -3565,11 +3540,7 @@ static OutputStream *new_audio_stream(AVFormatContext *oc, int file_idx)
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
audio_enc->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
- if (audio_stream_copy) {
- st->stream_copy = 1;
- } else {
- audio_enc->codec_id = codec_id;
-
+ if (!st->stream_copy) {
if (audio_qscale > QSCALE_NONE) {
audio_enc->flags |= CODEC_FLAG_QSCALE;
audio_enc->global_quality = FF_QP2LAMBDA * audio_qscale;
@@ -3588,8 +3559,6 @@ static OutputStream *new_audio_stream(AVFormatContext *oc, int file_idx)
/* reset some key parameters */
audio_disable = 0;
- av_freep(&audio_codec_name);
- audio_stream_copy = 0;
return ost;
}
@@ -3600,29 +3569,22 @@ static OutputStream *new_data_stream(AVFormatContext *oc, int file_idx)
OutputStream *ost;
AVCodecContext *data_enc;
- ost = new_output_stream(oc, file_idx, NULL);
+ ost = new_output_stream(oc, file_idx, AVMEDIA_TYPE_DATA);
st = ost->st;
data_enc = st->codec;
- if (!data_stream_copy) {
+ if (!st->stream_copy) {
fprintf(stderr, "Data stream encoding not supported yet (only streamcopy)\n");
exit_program(1);
}
- data_enc->codec_type = AVMEDIA_TYPE_DATA;
-
if (data_codec_tag)
data_enc->codec_tag= data_codec_tag;
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
data_enc->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
- if (data_stream_copy) {
- st->stream_copy = 1;
- }
data_disable = 0;
- av_freep(&data_codec_name);
- data_stream_copy = 0;
return ost;
}
@@ -3630,20 +3592,9 @@ static OutputStream *new_subtitle_stream(AVFormatContext *oc, int file_idx)
{
AVStream *st;
OutputStream *ost;
- AVCodec *codec=NULL;
AVCodecContext *subtitle_enc;
- enum CodecID codec_id = CODEC_ID_NONE;
- if(!subtitle_stream_copy){
- if (subtitle_codec_name) {
- codec_id = find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 1);
- codec = avcodec_find_encoder_by_name(subtitle_codec_name);
- } else {
- codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_SUBTITLE);
- codec = avcodec_find_encoder(codec_id);
- }
- }
- ost = new_output_stream(oc, file_idx, codec);
+ ost = new_output_stream(oc, file_idx, AVMEDIA_TYPE_SUBTITLE);
st = ost->st;
subtitle_enc = st->codec;
@@ -3658,11 +3609,6 @@ static OutputStream *new_subtitle_stream(AVFormatContext *oc, int file_idx)
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
subtitle_enc->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
- if (subtitle_stream_copy) {
- st->stream_copy = 1;
- } else {
- subtitle_enc->codec_id = codec_id;
- }
if (subtitle_language) {
av_dict_set(&st->metadata, "language", subtitle_language, 0);
@@ -3670,8 +3616,6 @@ static OutputStream *new_subtitle_stream(AVFormatContext *oc, int file_idx)
}
subtitle_disable = 0;
- av_freep(&subtitle_codec_name);
- subtitle_stream_copy = 0;
return ost;
}
@@ -3945,6 +3889,8 @@ static int opt_output_file(const char *opt, const char *filename)
av_freep(&stream_maps);
nb_stream_maps = 0;
+ av_dict_free(&codec_names);
+
av_freep(&forced_key_frames);
uninit_opts();
init_opts();
@@ -4156,8 +4102,8 @@ static int opt_target(const char *opt, const char *arg)
}
if(!strcmp(arg, "vcd")) {
- opt_video_codec("vcodec", "mpeg1video");
- opt_audio_codec("vcodec", "mp2");
+ opt_codec("c:v", "mpeg1video");
+ opt_codec("c:a", "mp2");
opt_format("f", "vcd");
opt_frame_size("s", norm == PAL ? "352x288" : "352x240");
@@ -4184,8 +4130,8 @@ static int opt_target(const char *opt, const char *arg)
mux_preload= (36000+3*1200) / 90000.0; //0.44
} else if(!strcmp(arg, "svcd")) {
- opt_video_codec("vcodec", "mpeg2video");
- opt_audio_codec("acodec", "mp2");
+ opt_codec("c:v", "mpeg2video");
+ opt_codec("c:a", "mp2");
opt_format("f", "svcd");
opt_frame_size("s", norm == PAL ? "480x576" : "480x480");
@@ -4207,8 +4153,8 @@ static int opt_target(const char *opt, const char *arg)
} else if(!strcmp(arg, "dvd")) {
- opt_video_codec("vcodec", "mpeg2video");
- opt_audio_codec("vcodec", "ac3");
+ opt_codec("c:v", "mpeg2video");
+ opt_codec("c:a", "ac3");
opt_format("f", "dvd");
opt_frame_size("vcodec", norm == PAL ? "720x576" : "720x480");
@@ -4305,6 +4251,8 @@ static const OptionDef options[] = {
{ "f", HAS_ARG, {(void*)opt_format}, "force format", "fmt" },
{ "i", HAS_ARG, {(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" },
{ "map", HAS_ARG | OPT_EXPERT, {(void*)opt_map}, "set input stream mapping", "file.stream[:syncfile.syncstream]" },
{ "map_meta_data", HAS_ARG | OPT_EXPERT, {(void*)opt_map_meta_data}, "DEPRECATED set meta data information of outfile from infile",
"outfile[,metadata]:infile[,metadata]" },