Newer
Older
if (file_idx >= nb_input_files || file_idx < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid input file index: %d.\n", file_idx);
}
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;
}
}
if (!m) {
av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches no streams.\n", arg);
exit_program(1);
}
av_freep(&map);
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;
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
static int opt_map_channel(OptionsContext *o, const char *opt, const char *arg)
{
int n;
AVStream *st;
AudioChannelMap *m;
o->audio_channel_maps =
grow_array(o->audio_channel_maps, sizeof(*o->audio_channel_maps),
&o->nb_audio_channel_maps, o->nb_audio_channel_maps + 1);
m = &o->audio_channel_maps[o->nb_audio_channel_maps - 1];
/* muted channel syntax */
n = sscanf(arg, "%d:%d.%d", &m->channel_idx, &m->ofile_idx, &m->ostream_idx);
if ((n == 1 || n == 3) && m->channel_idx == -1) {
m->file_idx = m->stream_idx = -1;
if (n == 1)
m->ofile_idx = m->ostream_idx = -1;
return 0;
}
/* normal syntax */
n = sscanf(arg, "%d.%d.%d:%d.%d",
&m->file_idx, &m->stream_idx, &m->channel_idx,
&m->ofile_idx, &m->ostream_idx);
if (n != 3 && n != 5) {
av_log(NULL, AV_LOG_FATAL, "Syntax error, mapchan usage: "
"[file.stream.channel|-1][:syncfile:syncstream]\n");
exit_program(1);
}
if (n != 5) // only file.stream.channel specified
m->ofile_idx = m->ostream_idx = -1;
/* check input */
if (m->file_idx < 0 || m->file_idx >= nb_input_files) {
av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file index: %d\n",
m->file_idx);
exit_program(1);
}
if (m->stream_idx < 0 ||
m->stream_idx >= input_files[m->file_idx].nb_streams) {
av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file stream index #%d.%d\n",
m->file_idx, m->stream_idx);
exit_program(1);
}
st = input_files[m->file_idx].ctx->streams[m->stream_idx];
if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
av_log(NULL, AV_LOG_FATAL, "mapchan: stream #%d.%d is not an audio stream.\n",
m->file_idx, m->stream_idx);
exit_program(1);
}
if (m->channel_idx < 0 || m->channel_idx >= st->codec->channels) {
av_log(NULL, AV_LOG_FATAL, "mapchan: invalid audio channel #%d.%d.%d\n",
m->file_idx, m->stream_idx, m->channel_idx);
exit_program(1);
}
return 0;
}
static void parse_meta_type(char *arg, char *type, int *index)
if (*arg) {
*type = *arg;
switch (*arg) {
case 'g':
break;
case 's':
case 'c':
case 'p':
if (*(++arg) == ':')
*index = strtol(++arg, NULL, 0);
break;
default:
av_log(NULL, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
}
} else
*type = 'g';
}
static int opt_map_metadata(OptionsContext *o, const char *opt, const char *arg)
Patrice Bensoussan
committed
{
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);
Patrice Bensoussan
committed
m = &o->meta_data_maps[o->nb_meta_data_maps - 1][1];
m->file = strtol(arg, &p, 0);
parse_meta_type(*p ? p + 1 : p, &m->type, &m->index);
Patrice Bensoussan
committed
m1 = &o->meta_data_maps[o->nb_meta_data_maps - 1][0];
if (p = strchr(opt, ':'))
parse_meta_type(p + 1, &m1->type, &m1->index);
else
m1->type = 'g';
Anton Khirnov
committed
if (m->type == 'g' || m1->type == 'g')
o->metadata_global_manual = 1;
Anton Khirnov
committed
if (m->type == 's' || m1->type == 's')
o->metadata_streams_manual = 1;
Anton Khirnov
committed
if (m->type == 'c' || m1->type == 'c')
o->metadata_chapters_manual = 1;
Patrice Bensoussan
committed
}
static int opt_map_meta_data(OptionsContext *o, const char *opt, const char *arg)
av_log(NULL, AV_LOG_WARNING, "-map_meta_data is deprecated and will be removed soon. "
"Use -map_metadata instead.\n");
return opt_map_metadata(o, opt, arg);
static int opt_recording_timestamp(OptionsContext *o, const char *opt, const char *arg)
{
char buf[128];
int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;
struct tm time = *gmtime((time_t*)&recording_timestamp);
strftime(buf, sizeof(buf), "creation_time=%FT%T%z", &time);
parse_option(o, "metadata", buf, options);
av_log(NULL, AV_LOG_WARNING, "%s is deprecated, set the 'creation_time' metadata "
"tag instead.\n", opt);
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);
if(!codec) {
av_log(NULL, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name);
exit_program(1);
}
if(codec->type != type) {
av_log(NULL, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name);
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, rfps, rfps_base;
char *next, *codec_tag = NULL;
for (i = 0; i < ic->nb_streams; i++) {
AVStream *st = ic->streams[i];
AVCodecContext *dec = st->codec;
InputStream *ist;
input_streams = grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, nb_input_streams + 1);
ist = &input_streams[nb_input_streams - 1];
ist->st = st;
ist->file_index = nb_input_files;
ist->discard = 1;
ist->opts = filter_codec_opts(codec_opts, choose_decoder(o, ic, st), ic, st);
ist->ts_scale = 1.0;
MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
if (codec_tag) {
uint32_t tag = strtol(codec_tag, &next, 0);
if (*next)
tag = AV_RL32(codec_tag);
st->codec->codec_tag = tag;
}
ist->dec = choose_decoder(o, ic, st);
switch (dec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
if(!ist->dec)
ist->dec = avcodec_find_decoder(dec->codec_id);
st->discard= AVDISCARD_ALL;
break;
case AVMEDIA_TYPE_VIDEO:
if(!ist->dec)
ist->dec = avcodec_find_decoder(dec->codec_id);
rfps = ic->streams[i]->r_frame_rate.num;
rfps_base = ic->streams[i]->r_frame_rate.den;
if (dec->lowres) {
dec->flags |= CODEC_FLAG_EMU_EDGE;
}
if (dec->time_base.den != rfps*dec->ticks_per_frame || dec->time_base.num != rfps_base) {
av_log(NULL, AV_LOG_INFO,"\nSeems stream %d codec frame rate differs from container frame rate: %2.2f (%d/%d) -> %2.2f (%d/%d)\n",
i, (float)dec->time_base.den / dec->time_base.num, dec->time_base.den, dec->time_base.num,
(float)rfps / rfps_base, rfps, rfps_base);
if (o->video_disable)
st->discard= AVDISCARD_ALL;
else if(video_discard)
st->discard= video_discard;
break;
case AVMEDIA_TYPE_DATA:
if (o->data_disable)
st->discard= AVDISCARD_ALL;
break;
case AVMEDIA_TYPE_SUBTITLE:
if(!ist->dec)
ist->dec = avcodec_find_decoder(dec->codec_id);
if(o->subtitle_disable)
st->discard = AVDISCARD_ALL;
break;
case AVMEDIA_TYPE_ATTACHMENT:
case AVMEDIA_TYPE_UNKNOWN:
break;
default:
abort();
}
}
}
static void assert_file_overwrite(const char *filename)
if ((!file_overwrite || no_file_overwrite) &&
(strchr(filename, ':') == NULL || filename[1] == ':' ||
av_strstart(filename, "file:", NULL))) {
if (avio_check(filename, 0) == 0) {
if (!using_stdin && (!no_file_overwrite || file_overwrite)) {
fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
fflush(stderr);
term_exit();
signal(SIGINT, SIG_DFL);
if (!read_yesno()) {
av_log(0, AV_LOG_FATAL, "Not overwriting - exiting\n");
exit_program(1);
}
term_init();
}
else {
av_log(0, AV_LOG_FATAL, "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);
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)
AVInputFormat *file_iformat = NULL;
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);
if (!strcmp(filename, "-"))
filename = "pipe:";
using_stdin |= !strncmp(filename, "pipe:", 5) ||
!strcmp(filename, "/dev/stdin");
ic = avformat_alloc_context();
if (!ic) {
print_error(filename, AVERROR(ENOMEM));
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) {
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->video_codec_id = video_codec_name ?
find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0)->id : CODEC_ID_NONE;
ic->audio_codec_id = audio_codec_name ?
find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)->id : CODEC_ID_NONE;
ic->subtitle_codec_id= subtitle_codec_name ?
find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)->id : CODEC_ID_NONE;
ic->interrupt_callback = int_cb;
av_log(NULL, AV_LOG_WARNING,
"-loop_input is deprecated, use -loop 1\n"
"Note, both loop options only work with -f image2\n"
);
/* open the input file with generic avformat function */
err = avformat_open_input(&ic, filename, file_iformat, &format_opts);
print_error(filename, err);
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);
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 */
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 */
add_input_streams(o, ic);
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);
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;
Max Krasnyansky
committed
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);
reset_options(o, 1);
static void parse_forced_key_frames(char *kf, OutputStream *ost)
{
char *p;
int n = 1, i;
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;
ost->forced_kf_pts[i] = parse_time_or_die("force_key_frames", p, 1);
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
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);
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);
ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
Fabrice Bellard
committed
}
}
Fabrice Bellard
committed
}
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"))
ost->stream_copy = 1;
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);
int idx = oc->nb_streams - 1, ret = 0;
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);
ost = &output_streams[nb_output_streams - 1];
ost->file_index = nb_output_files;
ost->index = idx;
ost->st = st;
st->codec->codec_type = type;
choose_encoder(o, oc, ost);
ost->opts = filter_codec_opts(codec_opts, ost->enc, 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
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
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);
Fabrice Bellard
committed
}
if (bsfc_prev)
bsfc_prev->next = bsfc;
else
ost->bitstream_filters = bsfc;
bsfc_prev = bsfc;
bsf = next;
Fabrice Bellard
committed
}
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;
Fabrice Bellard
committed
}
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;
}
Michael Niedermayer
committed
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
Michael Niedermayer
committed
av_opt_get_int(sws_opts, "sws_flags", 0, &ost->sws_flags);
static void parse_matrix_coeffs(uint16_t *dest, const char *str)
{
int i;
const char *p = str;
for(i = 0;; i++) {
dest[i] = atoi(p);
if(i == 63)
break;
p = strchr(p, ',');
if(!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)
Fabrice Bellard
committed
AVCodecContext *video_enc;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO);
st = ost->st;
Michael Niedermayer
committed
video_enc = st->codec;
if (!ost->stream_copy) {
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, *filters = NULL;
Fabrice Bellard
committed
int i;
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);
video_enc->bits_per_raw_sample = frame_bits_per_raw_sample;
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;
Fabrice Bellard
committed
if (intra_only)
Fabrice Bellard
committed
video_enc->gop_size = 0;
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);
Fabrice Bellard
committed
}
MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st);
Fabrice Bellard
committed
for(i=0; p; i++){
int start, end, q;
int e=sscanf(p, "%d,%d,%d", &start, &end, &q);
if(e!=3){
av_log(NULL, AV_LOG_FATAL, "error parsing rc_override\n");
Fabrice Bellard
committed
}
/* FIXME realloc failure */
video_enc->rc_override=
av_realloc(video_enc->rc_override,
Fabrice Bellard
committed
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;
}
p= strchr(p, '/');
if(p) p++;
}
video_enc->rc_override_count=i;
if (!video_enc->rc_initial_buffer_occupancy)
video_enc->rc_initial_buffer_occupancy = video_enc->rc_buffer_size*3/4;
Fabrice Bellard
committed
video_enc->intra_dc_precision= intra_dc_precision - 8;
if (do_psnr)
video_enc->flags|= CODEC_FLAG_PSNR;
Fabrice Bellard
committed
/* two pass mode */
if (do_pass) {
Fabrice Bellard
committed
video_enc->flags |= CODEC_FLAG_PASS1;
Fabrice Bellard
committed
video_enc->flags |= CODEC_FLAG_PASS2;
}
}
MATCH_PER_STREAM_OPT(forced_key_frames, str, forced_key_frames, oc, st);
parse_forced_key_frames(forced_key_frames, ost);
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(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st);
#if CONFIG_AVFILTER
MATCH_PER_STREAM_OPT(filters, str, filters, oc, st);
if (filters)
ost->avfilter = av_strdup(filters);
#endif
Fabrice Bellard
committed
}
Fabrice Bellard
committed
}
static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
Fabrice Bellard
committed
{
Fabrice Bellard
committed
AVStream *st;
Fabrice Bellard
committed
AVCodecContext *audio_enc;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO);
st = ost->st;
Michael Niedermayer
committed
Michael Niedermayer
committed
audio_enc = st->codec;
audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
if (!ost->stream_copy) {
char *sample_fmt = NULL;
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);
MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
ost->rematrix_volume=1.0;
MATCH_PER_STREAM_OPT(rematrix_volume, f, ost->rematrix_volume, oc, st);
Fabrice Bellard
committed
}
/* check for channel mapping for this audio stream */
for (n = 0; n < o->nb_audio_channel_maps; n++) {
AudioChannelMap *map = &o->audio_channel_maps[n];
InputStream *ist = &input_streams[ost->source_index];
if ((map->channel_idx == -1 || (ist->file_index == map->file_idx && ist->st->index == map->stream_idx)) &&
(map->ofile_idx == -1 || ost->file_index == map->ofile_idx) &&
(map->ostream_idx == -1 || ost->st->index == map->ostream_idx)) {
if (ost->audio_channels_mapped < FF_ARRAY_ELEMS(ost->audio_channels_map))
ost->audio_channels_map[ost->audio_channels_mapped++] = map->channel_idx;
else
av_log(NULL, AV_LOG_FATAL, "Max channel mapping for output %d.%d reached\n",
ost->file_index, ost->st->index);
}
}
Fabrice Bellard
committed
}
static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc)
OutputStream *ost;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA);
if (!ost->stream_copy) {
av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc)
{
OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT);
ost->stream_copy = 1;
static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc)
Fabrice Bellard
committed
{
AVStream *st;
Fabrice Bellard
committed
AVCodecContext *subtitle_enc;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE);
st = ost->st;
subtitle_enc = st->codec;
Fabrice Bellard
committed
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);
}
*p++ = '\0';
idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, MAX_STREAMS-1);
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);
Aurelien Jacobs
committed
return 0;
static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata)
AVFormatContext *is = ifile->ctx;
AVFormatContext *os = ofile->ctx;
int i;
for (i = 0; i < is->nb_chapters; i++) {
AVChapter *in_ch = is->chapters[i], *out_ch;
int64_t ts_off = av_rescale_q(ofile->start_time - ifile->ts_offset,
AV_TIME_BASE_Q, in_ch->time_base);
int64_t rt = (ofile->recording_time == INT64_MAX) ? INT64_MAX :
av_rescale_q(ofile->recording_time, AV_TIME_BASE_Q, in_ch->time_base);
if (in_ch->end < ts_off)
continue;
if (rt != INT64_MAX && in_ch->start > rt + ts_off)
break;
out_ch = av_mallocz(sizeof(AVChapter));
if (!out_ch)
return AVERROR(ENOMEM);
out_ch->id = in_ch->id;
out_ch->time_base = in_ch->time_base;
out_ch->start = FFMAX(0, in_ch->start - ts_off);
out_ch->end = FFMIN(rt, in_ch->end - ts_off);
av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
os->nb_chapters++;
os->chapters = av_realloc_f(os->chapters, os->nb_chapters, sizeof(AVChapter));
if (!os->chapters)
return AVERROR(ENOMEM);
os->chapters[os->nb_chapters - 1] = out_ch;
}
return 0;
}
static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename)
{
int i, err;
AVFormatContext *ic = avformat_alloc_context();
ic->interrupt_callback = int_cb;
err = avformat_open_input(&ic, filename, NULL, NULL);
if (err < 0)
return err;
/* copy stream format */
for(i=0;i<ic->nb_streams;i++) {
AVStream *st;
OutputStream *ost;
AVCodec *codec;
AVCodecContext *avctx;
codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
ost = new_output_stream(o, s, codec->type);
st = ost->st;
ost->enc = codec;
// FIXME: a more elegant solution is needed
memcpy(st, ic->streams[i], sizeof(AVStream));
st->info = av_malloc(sizeof(*st->info));
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 && !ost->stream_copy)
choose_sample_fmt(st, codec);
else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !ost->stream_copy)
choose_pixel_fmt(st, codec);
}
av_close_input_file(ic);
return 0;
}
static void opt_output_file(void *optctx, const char *filename)
Fabrice Bellard
committed
{
OptionsContext *o = optctx;
Fabrice Bellard
committed
AVFormatContext *oc;
AVOutputFormat *file_oformat;