Newer
Older
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) {
output_packet(ist, NULL);
flush_encoders();
term_exit();
/* write the trailer if needed and close file */
os = output_files[i]->ctx;
av_write_trailer(os);
}
/* dump report by using the first video and audio streams */
print_report(1, timer_start);
/* close each encoder */
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
if (ost->encoding_needed) {
av_freep(&ost->st->codec->stats_in);
avcodec_close(ost->st->codec);
}
}
/* close each decoder */
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
if (ist->decoding_needed) {
avcodec_close(ist->st->codec);
}
}
/* finished ! */
ret = 0;
fail:
av_freep(&no_packet);
if (output_streams) {
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
av_freep(&ost->st->codec->extradata);
if (ost->logfile) {
fclose(ost->logfile);
ost->logfile = NULL;
}
av_freep(&ost->st->codec->subtitle_header);
av_free(ost->forced_kf_pts);
av_dict_free(&ost->opts);
}
}
}
return ret;
}
static double parse_frame_aspect_ratio(const char *arg)
{
int x = 0, y = 0;
double ar = 0;
const char *p;
char *end;
p = strchr(arg, ':');
if (p) {
x = strtol(arg, &end, 10);
if (end == p)
if (x > 0 && y > 0)
ar = (double)x / (double)y;
} else
ar = strtod(arg, NULL);
if (!ar) {
av_log(NULL, AV_LOG_FATAL, "Incorrect aspect ratio specification.\n");
exit_program(1);
static int opt_audio_codec(OptionsContext *o, const char *opt, const char *arg)
return parse_option(o, "codec:a", arg, options);
static int opt_video_codec(OptionsContext *o, const char *opt, const char *arg)
return parse_option(o, "codec:v", arg, options);
static int opt_subtitle_codec(OptionsContext *o, const char *opt, const char *arg)
return parse_option(o, "codec:s", arg, options);
static int opt_data_codec(OptionsContext *o, const char *opt, const char *arg)
return parse_option(o, "codec:d", arg, options);
static int opt_map(OptionsContext *o, const char *opt, const char *arg)
StreamMap *m = NULL;
int i, negative = 0, file_idx;
int sync_file_idx = -1, sync_stream_idx;
char *p, *sync;
char *map;
if (*arg == '-') {
negative = 1;
arg++;
}
map = av_strdup(arg);
/* parse sync stream first, just pick first matching stream */
if (sync = strchr(map, ',')) {
*sync = 0;
sync_file_idx = strtol(sync + 1, &sync, 0);
if (sync_file_idx >= nb_input_files || sync_file_idx < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid sync file index: %d.\n", sync_file_idx);
exit_program(1);
}
if (*sync)
sync++;
for (i = 0; i < input_files[sync_file_idx]->nb_streams; i++)
if (check_stream_specifier(input_files[sync_file_idx]->ctx,
input_files[sync_file_idx]->ctx->streams[i], sync) == 1) {
sync_stream_idx = i;
break;
}
if (i == input_files[sync_file_idx]->nb_streams) {
av_log(NULL, AV_LOG_FATAL, "Sync stream specification in map %s does not "
"match any streams.\n", arg);
exit_program(1);
}
}
if (map[0] == '[') {
/* this mapping refers to lavfi output */
const char *c = map + 1;
o->stream_maps = grow_array(o->stream_maps, sizeof(*o->stream_maps),
&o->nb_stream_maps, o->nb_stream_maps + 1);
m = &o->stream_maps[o->nb_stream_maps - 1];
m->linklabel = av_get_token(&c, "]");
if (!m->linklabel) {
av_log(NULL, AV_LOG_ERROR, "Invalid output link label: %s.\n", map);
exit_program(1);
}
} else {
file_idx = strtol(map, &p, 0);
if (file_idx >= nb_input_files || file_idx < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid input file index: %d.\n", file_idx);
exit_program(1);
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
if (negative)
/* disable some already defined maps */
for (i = 0; i < o->nb_stream_maps; i++) {
m = &o->stream_maps[i];
if (file_idx == m->file_index &&
check_stream_specifier(input_files[m->file_index]->ctx,
input_files[m->file_index]->ctx->streams[m->stream_index],
*p == ':' ? p + 1 : p) > 0)
m->disabled = 1;
}
else
for (i = 0; i < input_files[file_idx]->nb_streams; i++) {
if (check_stream_specifier(input_files[file_idx]->ctx, input_files[file_idx]->ctx->streams[i],
*p == ':' ? p + 1 : p) <= 0)
continue;
o->stream_maps = grow_array(o->stream_maps, sizeof(*o->stream_maps),
&o->nb_stream_maps, o->nb_stream_maps + 1);
m = &o->stream_maps[o->nb_stream_maps - 1];
m->file_index = file_idx;
m->stream_index = i;
if (sync_file_idx >= 0) {
m->sync_file_index = sync_file_idx;
m->sync_stream_index = sync_stream_idx;
} else {
m->sync_file_index = file_idx;
m->sync_stream_index = i;
}
av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches no streams.\n", arg);
exit_program(1);
}
av_freep(&map);
return 0;
}
static int opt_attach(OptionsContext *o, const char *opt, const char *arg)
{
o->attachments = grow_array(o->attachments, sizeof(*o->attachments),
&o->nb_attachments, o->nb_attachments + 1);
o->attachments[o->nb_attachments - 1] = arg;
return 0;
}
/**
* Parse a metadata specifier in arg.
* @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram)
* @param index for type c/p, chapter/program index is written here
* @param stream_spec for type s, the stream specifier is written here
*/
static void parse_meta_type(char *arg, char *type, int *index, const char **stream_spec)
switch (*arg) {
case 'g':
break;
case 's':
if (*(++arg) && *arg != ':') {
av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg);
exit_program(1);
}
*stream_spec = *arg == ':' ? arg + 1 : "";
break;
case 'c':
case 'p':
if (*(++arg) == ':')
*index = strtol(++arg, NULL, 0);
av_log(NULL, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
exit_program(1);
}
} else
*type = 'g';
}
static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
AVDictionary **meta_in = NULL;
AVDictionary **meta_out;
int i, ret = 0;
char type_in, type_out;
const char *istream_spec = NULL, *ostream_spec = NULL;
int idx_in = 0, idx_out = 0;
parse_meta_type(inspec, &type_in, &idx_in, &istream_spec);
parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);
if (type_in == 'g' || type_out == 'g')
o->metadata_global_manual = 1;
if (type_in == 's' || type_out == 's')
o->metadata_streams_manual = 1;
if (type_in == 'c' || type_out == 'c')
o->metadata_chapters_manual = 1;
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
if ((index) < 0 || (index) >= (nb_elems)) {\
av_log(NULL, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\
(desc), (index));\
exit_program(1);\
}
#define SET_DICT(type, meta, context, index)\
switch (type) {\
case 'g':\
meta = &context->metadata;\
break;\
case 'c':\
METADATA_CHECK_INDEX(index, context->nb_chapters, "chapter")\
meta = &context->chapters[index]->metadata;\
break;\
case 'p':\
METADATA_CHECK_INDEX(index, context->nb_programs, "program")\
meta = &context->programs[index]->metadata;\
break;\
}\
SET_DICT(type_in, meta_in, ic, idx_in);
SET_DICT(type_out, meta_out, oc, idx_out);
/* for input streams choose first matching stream */
if (type_in == 's') {
for (i = 0; i < ic->nb_streams; i++) {
if ((ret = check_stream_specifier(ic, ic->streams[i], istream_spec)) > 0) {
meta_in = &ic->streams[i]->metadata;
break;
} else if (ret < 0)
exit_program(1);
}
if (!meta_in) {
av_log(NULL, AV_LOG_FATAL, "Stream specifier %s does not match any streams.\n", istream_spec);
exit_program(1);
}
}
if (type_out == 's') {
for (i = 0; i < oc->nb_streams; i++) {
if ((ret = check_stream_specifier(oc, oc->streams[i], ostream_spec)) > 0) {
meta_out = &oc->streams[i]->metadata;
av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
} else if (ret < 0)
exit_program(1);
}
} else
av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
return 0;
}
static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
{
const char *codec_string = encoder ? "encoder" : "decoder";
AVCodec *codec;
codec = encoder ?
avcodec_find_encoder_by_name(name) :
avcodec_find_decoder_by_name(name);
av_log(NULL, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name);
av_log(NULL, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name);
return codec;
static AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st)
MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
if (codec_name) {
AVCodec *codec = find_codec_or_die(codec_name, st->codec->codec_type, 0);
st->codec->codec_id = codec->id;
return codec;
} else
return avcodec_find_decoder(st->codec->codec_id);
/**
* Add all the streams from the given input file to the global
* list of input streams.
*/
static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
int i;
for (i = 0; i < ic->nb_streams; i++) {
AVStream *st = ic->streams[i];
AVCodecContext *dec = st->codec;
InputStream *ist = av_mallocz(sizeof(*ist));
if (!ist)
exit_program(1);
input_streams = grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, nb_input_streams + 1);
input_streams[nb_input_streams - 1] = ist;
ist->st = st;
ist->file_index = nb_input_files;
ist->discard = 1;
st->discard = AVDISCARD_ALL;
ist->opts = filter_codec_opts(codec_opts, ist->st->codec->codec_id, ic, st);
ist->ts_scale = 1.0;
MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
ist->dec = choose_decoder(o, ic, st);
switch (dec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
ist->resample_height = dec->height;
ist->resample_width = dec->width;
ist->resample_pix_fmt = dec->pix_fmt;
case AVMEDIA_TYPE_AUDIO:
guess_input_channel_layout(ist);
ist->resample_sample_fmt = dec->sample_fmt;
ist->resample_sample_rate = dec->sample_rate;
ist->resample_channels = dec->channels;
ist->resample_channel_layout = dec->channel_layout;
break;
case AVMEDIA_TYPE_DATA:
case AVMEDIA_TYPE_SUBTITLE:
case AVMEDIA_TYPE_ATTACHMENT:
case AVMEDIA_TYPE_UNKNOWN:
break;
default:
abort();
}
}
}
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
static void assert_file_overwrite(const char *filename)
{
if (!file_overwrite &&
(strchr(filename, ':') == NULL || filename[1] == ':' ||
av_strstart(filename, "file:", NULL))) {
if (avio_check(filename, 0) == 0) {
if (!using_stdin) {
fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
fflush(stderr);
if (!read_yesno()) {
fprintf(stderr, "Not overwriting - exiting\n");
exit_program(1);
}
}
else {
fprintf(stderr,"File '%s' already exists. Exiting.\n", filename);
exit_program(1);
}
}
}
}
static void dump_attachment(AVStream *st, const char *filename)
{
int ret;
AVIOContext *out = NULL;
AVDictionaryEntry *e;
if (!st->codec->extradata_size) {
av_log(NULL, AV_LOG_WARNING, "No extradata to dump in stream #%d:%d.\n",
nb_input_files - 1, st->index);
return;
}
if (!*filename && (e = av_dict_get(st->metadata, "filename", NULL, 0)))
filename = e->value;
if (!*filename) {
av_log(NULL, AV_LOG_FATAL, "No filename specified and no 'filename' tag"
"in stream #%d:%d.\n", nb_input_files - 1, st->index);
exit_program(1);
}
assert_file_overwrite(filename);
Martin Storsjö
committed
if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) {
av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n",
filename);
exit_program(1);
}
avio_write(out, st->codec->extradata, st->codec->extradata_size);
avio_flush(out);
avio_close(out);
}
static int opt_input_file(OptionsContext *o, const char *opt, const char *filename)
{
AVFormatContext *ic;
AVInputFormat *file_iformat = NULL;
int64_t timestamp;
uint8_t buf[128];
AVDictionary **opts;
int orig_nb_streams; // number of streams before avformat_find_stream_info
if (o->format) {
if (!(file_iformat = av_find_input_format(o->format))) {
av_log(NULL, AV_LOG_FATAL, "Unknown input format: '%s'\n", o->format);
exit_program(1);
}
}
if (!strcmp(filename, "-"))
filename = "pipe:";
using_stdin |= !strncmp(filename, "pipe:", 5) ||
!strcmp(filename, "/dev/stdin");
/* get default parameters from command line */
ic = avformat_alloc_context();
if (!ic) {
print_error(filename, AVERROR(ENOMEM));
exit_program(1);
}
if (o->nb_audio_sample_rate) {
snprintf(buf, sizeof(buf), "%d", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i);
av_dict_set(&format_opts, "sample_rate", buf, 0);
}
if (o->nb_audio_channels) {
Justin Ruggles
committed
/* because we set audio_channels based on both the "ac" and
* "channel_layout" options, we need to check that the specified
* demuxer actually has the "channels" option before setting it */
if (file_iformat && file_iformat->priv_class &&
av_opt_find(&file_iformat->priv_class, "channels", NULL, 0,
AV_OPT_SEARCH_FAKE_OBJ)) {
snprintf(buf, sizeof(buf), "%d",
o->audio_channels[o->nb_audio_channels - 1].u.i);
av_dict_set(&format_opts, "channels", buf, 0);
}
if (o->nb_frame_rates) {
av_dict_set(&format_opts, "framerate", o->frame_rates[o->nb_frame_rates - 1].u.str, 0);
if (o->nb_frame_sizes) {
av_dict_set(&format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0);
if (o->nb_frame_pix_fmts)
av_dict_set(&format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0);
ic->flags |= AVFMT_FLAG_NONBLOCK;
Martin Storsjö
committed
ic->interrupt_callback = int_cb;
/* open the input file with generic libav function */
err = avformat_open_input(&ic, filename, file_iformat, &format_opts);
if (err < 0) {
print_error(filename, err);
exit_program(1);
}
assert_avoptions(format_opts);
/* apply forced codec ids */
for (i = 0; i < ic->nb_streams; i++)
choose_decoder(o, ic, ic->streams[i]);
/* Set AVCodecContext options for avformat_find_stream_info */
opts = setup_find_stream_info_opts(ic, codec_opts);
orig_nb_streams = ic->nb_streams;
/* If not enough info to get the stream parameters, we decode the
first frames to get it. (used in mpeg case for example) */
ret = avformat_find_stream_info(ic, opts);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "%s: could not find codec parameters\n", filename);
avformat_close_input(&ic);
exit_program(1);
}
Anton Khirnov
committed
timestamp = o->start_time;
/* add the stream start time */
if (ic->start_time != AV_NOPTS_VALUE)
timestamp += ic->start_time;
/* if seeking requested, we execute it */
Anton Khirnov
committed
if (o->start_time != 0) {
ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
if (ret < 0) {
av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
filename, (double)timestamp / AV_TIME_BASE);
}
}
/* update the current parameters so that they match the one of the input stream */
/* dump the file content */
av_dump_format(ic, nb_input_files, filename, 0);
input_files = grow_array(input_files, sizeof(*input_files), &nb_input_files, nb_input_files + 1);
if (!(input_files[nb_input_files - 1] = av_mallocz(sizeof(*input_files[0]))))
exit_program(1);
input_files[nb_input_files - 1]->ctx = ic;
input_files[nb_input_files - 1]->ist_index = nb_input_streams - ic->nb_streams;
input_files[nb_input_files - 1]->ts_offset = o->input_ts_offset - (copy_ts ? 0 : timestamp);
input_files[nb_input_files - 1]->nb_streams = ic->nb_streams;
input_files[nb_input_files - 1]->rate_emu = o->rate_emu;
for (i = 0; i < o->nb_dump_attachment; i++) {
int j;
for (j = 0; j < ic->nb_streams; j++) {
AVStream *st = ic->streams[j];
if (check_stream_specifier(ic, st, o->dump_attachment[i].specifier) == 1)
dump_attachment(st, o->dump_attachment[i].u.str);
}
}
for (i = 0; i < orig_nb_streams; i++)
av_dict_free(&opts[i]);
av_freep(&opts);
return 0;
}
static void parse_forced_key_frames(char *kf, OutputStream *ost,
AVCodecContext *avctx)
{
char *p;
int n = 1, i;
int64_t t;
for (p = kf; *p; p++)
if (*p == ',')
n++;
ost->forced_kf_count = n;
ost->forced_kf_pts = av_malloc(sizeof(*ost->forced_kf_pts) * n);
if (!ost->forced_kf_pts) {
av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n");
exit_program(1);
}
for (i = 0; i < n; i++) {
p = i ? strchr(p, ',') + 1 : kf;
t = parse_time_or_die("force_key_frames", p, 1);
ost->forced_kf_pts[i] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base);
}
}
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
static uint8_t *get_line(AVIOContext *s)
{
AVIOContext *line;
uint8_t *buf;
char c;
if (avio_open_dyn_buf(&line) < 0) {
av_log(NULL, AV_LOG_FATAL, "Could not alloc buffer for reading preset.\n");
exit_program(1);
}
while ((c = avio_r8(s)) && c != '\n')
avio_w8(line, c);
avio_w8(line, 0);
avio_close_dyn_buf(line, &buf);
return buf;
}
static int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s)
{
int i, ret = 1;
char filename[1000];
const char *base[3] = { getenv("AVCONV_DATADIR"),
getenv("HOME"),
AVCONV_DATADIR,
};
for (i = 0; i < FF_ARRAY_ELEMS(base) && ret; i++) {
if (!base[i])
continue;
if (codec_name) {
snprintf(filename, sizeof(filename), "%s%s/%s-%s.avpreset", base[i],
i != 1 ? "" : "/.avconv", codec_name, preset_name);
Martin Storsjö
committed
ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
}
if (ret) {
snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i],
i != 1 ? "" : "/.avconv", preset_name);
Martin Storsjö
committed
ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
static void choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *ost)
{
char *codec_name = NULL;
MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st);
if (!codec_name) {
ost->st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename,
NULL, ost->st->codec->codec_type);
ost->enc = avcodec_find_encoder(ost->st->codec->codec_id);
} else if (!strcmp(codec_name, "copy"))
else {
ost->enc = find_codec_or_die(codec_name, ost->st->codec->codec_type, 1);
ost->st->codec->codec_id = ost->enc->id;
}
}
static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type)
AVStream *st = avformat_new_stream(oc, NULL);
char *bsf = NULL, *next, *codec_tag = NULL;
AVBitStreamFilterContext *bsfc, *bsfc_prev = NULL;
char *buf = NULL, *arg = NULL, *preset = NULL;
AVIOContext *s = NULL;
av_log(NULL, AV_LOG_FATAL, "Could not alloc stream.\n");
if (oc->nb_streams - 1 < o->nb_streamid_map)
st->id = o->streamid_map[oc->nb_streams - 1];
output_streams = grow_array(output_streams, sizeof(*output_streams), &nb_output_streams,
nb_output_streams + 1);
if (!(ost = av_mallocz(sizeof(*ost))))
exit_program(1);
output_streams[nb_output_streams - 1] = ost;
ost->file_index = nb_output_files;
choose_encoder(o, oc, ost);
if (ost->enc) {
ost->opts = filter_codec_opts(codec_opts, ost->enc->id, oc, st);
}
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
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
MATCH_PER_STREAM_OPT(presets, str, preset, oc, st);
if (preset && (!(ret = get_preset_file_2(preset, ost->enc->name, &s)))) {
do {
buf = get_line(s);
if (!buf[0] || buf[0] == '#') {
av_free(buf);
continue;
}
if (!(arg = strchr(buf, '='))) {
av_log(NULL, AV_LOG_FATAL, "Invalid line found in the preset file.\n");
exit_program(1);
}
*arg++ = 0;
av_dict_set(&ost->opts, buf, arg, AV_DICT_DONT_OVERWRITE);
av_free(buf);
} while (!s->eof_reached);
avio_close(s);
}
if (ret) {
av_log(NULL, AV_LOG_FATAL,
"Preset %s specified for stream %d:%d, but could not be opened.\n",
preset, ost->file_index, ost->index);
exit_program(1);
}
ost->max_frames = INT64_MAX;
MATCH_PER_STREAM_OPT(max_frames, i64, ost->max_frames, oc, st);
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_FATAL, "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;
}
MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st);
if (codec_tag) {
uint32_t tag = strtol(codec_tag, &next, 0);
if (*next)
tag = AV_RL32(codec_tag);
st->codec->codec_tag = tag;
}
MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st);
if (qscale >= 0 || same_quant) {
st->codec->flags |= CODEC_FLAG_QSCALE;
st->codec->global_quality = FF_QP2LAMBDA * qscale;
}
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
av_opt_get_int(sws_opts, "sws_flags", 0, &ost->sws_flags);
ost->pix_fmts[0] = ost->pix_fmts[1] = PIX_FMT_NONE;
static void parse_matrix_coeffs(uint16_t *dest, const char *str)
{
int i;
const char *p = str;
break;
p = strchr(p, ',');
av_log(NULL, AV_LOG_FATAL, "Syntax error in matrix \"%s\" at coeff %d\n", str, i);
exit_program(1);
}
p++;
}
}
static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
{
AVStream *st;
OutputStream *ost;
AVCodecContext *video_enc;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO);
st = ost->st;
video_enc = st->codec;
const char *p = NULL;
char *forced_key_frames = NULL, *frame_rate = NULL, *frame_size = NULL;
char *frame_aspect_ratio = NULL, *frame_pix_fmt = NULL;
char *intra_matrix = NULL, *inter_matrix = NULL;
const char *filters = "null";
MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);
if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate);
exit_program(1);
}
MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
if (frame_size && av_parse_video_size(&video_enc->width, &video_enc->height, frame_size) < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
exit_program(1);
}
MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);
if (frame_aspect_ratio)
ost->frame_aspect_ratio = parse_frame_aspect_ratio(frame_aspect_ratio);
MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st);
if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == PIX_FMT_NONE) {
av_log(NULL, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", frame_pix_fmt);
exit_program(1);
}
st->sample_aspect_ratio = video_enc->sample_aspect_ratio;
MATCH_PER_STREAM_OPT(intra_matrices, str, intra_matrix, oc, st);
if (intra_matrix) {
if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64))) {
av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for intra matrix.\n");
exit_program(1);
}
parse_matrix_coeffs(video_enc->intra_matrix, intra_matrix);
}
MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st);
if (inter_matrix) {
if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64))) {
av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for inter matrix.\n");
exit_program(1);
}
parse_matrix_coeffs(video_enc->inter_matrix, inter_matrix);
}
MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st);
int e = sscanf(p, "%d,%d,%d", &start, &end, &q);
if (e != 3) {
av_log(NULL, AV_LOG_FATAL, "error parsing rc_override\n");
exit_program(1);
}
av_realloc(video_enc->rc_override,
sizeof(RcOverride) * (i + 1));
video_enc->rc_override[i].start_frame = start;
video_enc->rc_override[i].end_frame = end;
if (q > 0) {
video_enc->rc_override[i].qscale = q;
video_enc->rc_override[i].quality_factor = 1.0;
else {
video_enc->rc_override[i].qscale = 0;
video_enc->rc_override[i].quality_factor = -q/100.0;
if (!video_enc->rc_initial_buffer_occupancy)
video_enc->rc_initial_buffer_occupancy = video_enc->rc_buffer_size * 3 / 4;
video_enc->intra_dc_precision = intra_dc_precision - 8;
/* two pass mode */
if (do_pass) {
if (do_pass == 1) {
video_enc->flags |= CODEC_FLAG_PASS1;
} else {
video_enc->flags |= CODEC_FLAG_PASS2;
}
}
MATCH_PER_STREAM_OPT(forced_key_frames, str, forced_key_frames, oc, st);
if (forced_key_frames)
parse_forced_key_frames(forced_key_frames, ost, video_enc);
MATCH_PER_STREAM_OPT(force_fps, i, ost->force_fps, oc, st);
ost->top_field_first = -1;
MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
MATCH_PER_STREAM_OPT(filters, str, filters, oc, st);
ost->avfilter = av_strdup(filters);
} else {
MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st);
static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
{
AVStream *st;
OutputStream *ost;
AVCodecContext *audio_enc;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO);
st = ost->st;
audio_enc = st->codec;
audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
char *sample_fmt = NULL;
const char *filters = "anull";
MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st);
MATCH_PER_STREAM_OPT(sample_fmts, str, sample_fmt, oc, st);
if (sample_fmt &&
(audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) {
av_log(NULL, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt);
exit_program(1);
}
MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
MATCH_PER_STREAM_OPT(filters, str, filters, oc, st);
ost->avfilter = av_strdup(filters);
static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc)
{
OutputStream *ost;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA);
av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
exit_program(1);
}
static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc)
{
OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT);
static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc)
{
AVStream *st;
OutputStream *ost;
AVCodecContext *subtitle_enc;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE);
st = ost->st;
subtitle_enc = st->codec;
subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
}
/* arg format is "output-stream-index:streamid-value". */
static int opt_streamid(OptionsContext *o, const char *opt, const char *arg)
{
int idx;
char *p;
char idx_str[16];
av_strlcpy(idx_str, arg, sizeof(idx_str));
p = strchr(idx_str, ':');
if (!p) {
av_log(NULL, AV_LOG_FATAL,
"Invalid value '%s' for option '%s', required syntax is 'index:value'\n",
arg, opt);
exit_program(1);
}
*p++ = '\0';
idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, INT_MAX);
o->streamid_map = grow_array(o->streamid_map, sizeof(*o->streamid_map), &o->nb_streamid_map, idx+1);
o->streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX);