Newer
Older
AVIOContext *s = NULL;
char *buf = NULL, *arg = NULL, *preset = NULL;
ost->opts = filter_codec_opts(o->g->codec_opts, ost->enc->id, oc, st, ost->enc);
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");
}
*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);
} else {
ost->opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL);
}
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->max_frames = INT64_MAX;
MATCH_PER_STREAM_OPT(max_frames, i64, ost->max_frames, oc, st);
for (i = 0; i<o->nb_max_frames; i++) {
char *p = o->max_frames[i].specifier;
if (!*p && type != AVMEDIA_TYPE_VIDEO) {
av_log(NULL, AV_LOG_WARNING, "Applying unspecific -frames to non video streams, maybe you meant -vframes ?\n");
break;
}
}
ost->copy_prior_start = -1;
MATCH_PER_STREAM_OPT(copy_prior_start, i, ost->copy_prior_start, 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);
}
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);
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(o->g->sws_opts, "sws_flags", 0, &ost->sws_flags);
Michael Niedermayer
committed
av_dict_copy(&ost->swr_opts, o->g->swr_opts, 0);
if (ost->enc && av_get_exact_bits_per_sample(ost->enc->id) == 24)
Michael Niedermayer
committed
av_dict_set(&ost->swr_opts, "output_sample_bits", "24", 0);
av_dict_copy(&ost->resample_opts, o->g->resample_opts, 0);
ost->source_index = source_index;
if (source_index >= 0) {
ost->sync_ist = input_streams[source_index];
input_streams[source_index]->discard = 0;
input_streams[source_index]->st->discard = AVDISCARD_NONE;
}
ost->last_mux_dts = AV_NOPTS_VALUE;
return ost;
}
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);
}
p++;
}
}
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
/* read file contents into a string */
static uint8_t *read_file(const char *filename)
{
AVIOContext *pb = NULL;
AVIOContext *dyn_buf = NULL;
int ret = avio_open(&pb, filename, AVIO_FLAG_READ);
uint8_t buf[1024], *str;
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error opening file %s.\n", filename);
return NULL;
}
ret = avio_open_dyn_buf(&dyn_buf);
if (ret < 0) {
avio_closep(&pb);
return NULL;
}
while ((ret = avio_read(pb, buf, sizeof(buf))) > 0)
avio_write(dyn_buf, buf, ret);
avio_w8(dyn_buf, 0);
avio_closep(&pb);
ret = avio_close_dyn_buf(dyn_buf, &str);
if (ret < 0)
return NULL;
return str;
}
static char *get_ost_filters(OptionsContext *o, AVFormatContext *oc,
OutputStream *ost)
{
AVStream *st = ost->st;
Stefano Sabatini
committed
if (ost->filters_script && ost->filters) {
av_log(NULL, AV_LOG_ERROR, "Both -filter and -filter_script set for "
"output stream #%d:%d.\n", nb_output_files, st->index);
Stefano Sabatini
committed
if (ost->filters_script)
return read_file(ost->filters_script);
else if (ost->filters)
return av_strdup(ost->filters);
return av_strdup(st->codec->codec_type == AVMEDIA_TYPE_VIDEO ?
"null" : "anull");
}
Stefano Sabatini
committed
static void check_streamcopy_filters(OptionsContext *o, AVFormatContext *oc,
const OutputStream *ost, enum AVMediaType type)
{
Stefano Sabatini
committed
if (ost->filters_script || ost->filters) {
Stefano Sabatini
committed
av_log(NULL, AV_LOG_ERROR,
Stefano Sabatini
committed
"%s '%s' was defined for %s output stream %d:%d but codec copy was selected.\n"
Stefano Sabatini
committed
"Filtering and streamcopy cannot be used together.\n",
Stefano Sabatini
committed
ost->filters ? "Filtergraph" : "Filtergraph script",
ost->filters ? ost->filters : ost->filters_script,
av_get_media_type_string(type), ost->file_index, ost->index);
Stefano Sabatini
committed
exit_program(1);
}
}
static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
{
AVStream *st;
OutputStream *ost;
AVCodecContext *video_enc;
char *frame_rate = NULL, *frame_aspect_ratio = NULL;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO, source_index);
st = ost->st;
video_enc = st->codec;
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);
MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);
if (frame_aspect_ratio) {
AVRational q;
if (av_parse_ratio(&q, frame_aspect_ratio, 255, 0, NULL) < 0 ||
q.num <= 0 || q.den <= 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid aspect ratio: %s\n", frame_aspect_ratio);
}
ost->frame_aspect_ratio = q;
}
Stefano Sabatini
committed
MATCH_PER_STREAM_OPT(filter_scripts, str, ost->filters_script, oc, st);
MATCH_PER_STREAM_OPT(filters, str, ost->filters, oc, st);
if (!ost->stream_copy) {
const char *p = NULL;
char *frame_size = NULL;
char *frame_pix_fmt = NULL;
char *intra_matrix = NULL, *inter_matrix = NULL;
int i;
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);
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 && *frame_pix_fmt == '+') {
ost->keep_pix_fmt = 1;
if (!*++frame_pix_fmt)
frame_pix_fmt = NULL;
}
if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == AV_PIX_FMT_NONE) {
av_log(NULL, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", frame_pix_fmt);
}
st->sample_aspect_ratio = video_enc->sample_aspect_ratio;
if (intra_only)
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");
}
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");
}
parse_matrix_coeffs(video_enc->inter_matrix, inter_matrix);
}
MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st);
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");
/* FIXME realloc failure */
video_enc->rc_override =
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;
}
p = strchr(p, '/');
if (p) p++;
}
video_enc->rc_override_count = i;
video_enc->intra_dc_precision = intra_dc_precision - 8;
if (do_psnr)
video_enc->flags|= CODEC_FLAG_PSNR;
MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
video_enc->flags |= CODEC_FLAG_PASS1;
av_dict_set(&ost->opts, "flags", "+pass1", AV_DICT_APPEND);
}
if (do_pass & 2) {
video_enc->flags |= CODEC_FLAG_PASS2;
av_dict_set(&ost->opts, "flags", "+pass2", AV_DICT_APPEND);
MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st);
if (ost->logfile_prefix &&
!(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
MATCH_PER_STREAM_OPT(forced_key_frames, str, ost->forced_keyframes, oc, st);
if (ost->forced_keyframes)
ost->forced_keyframes = av_strdup(ost->forced_keyframes);
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);
ost->avfilter = get_ost_filters(o, oc, ost);
if (!ost->avfilter)
} else {
MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st);
}
Stefano Sabatini
committed
if (ost->stream_copy)
check_streamcopy_filters(o, oc, ost, AVMEDIA_TYPE_VIDEO);
return ost;
}
static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
AVStream *st;
OutputStream *ost;
AVCodecContext *audio_enc;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO, source_index);
st = ost->st;
audio_enc = st->codec;
audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
Stefano Sabatini
committed
MATCH_PER_STREAM_OPT(filter_scripts, str, ost->filters_script, oc, st);
MATCH_PER_STREAM_OPT(filters, str, ost->filters, oc, st);
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);
Michael Niedermayer
committed
MATCH_PER_STREAM_OPT(apad, str, ost->apad, oc, st);
ost->apad = av_strdup(ost->apad);
ost->avfilter = get_ost_filters(o, oc, ost);
if (!ost->avfilter)
/* 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);
}
}
Stefano Sabatini
committed
if (ost->stream_copy)
check_streamcopy_filters(o, oc, ost, AVMEDIA_TYPE_AUDIO);
return ost;
}
static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
{
OutputStream *ost;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA, source_index);
if (!ost->stream_copy) {
av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
}
return ost;
}
static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT, source_index);
ost->stream_copy = 1;
ost->finished = 1;
return ost;
}
static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
{
AVStream *st;
OutputStream *ost;
AVCodecContext *subtitle_enc;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE, source_index);
st = ost->st;
subtitle_enc = st->codec;
subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc, st);
if (!ost->stream_copy) {
char *frame_size = NULL;
MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
if (frame_size && av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size) < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
return ost;
}
/* arg format is "output-stream-index:streamid-value". */
static int opt_streamid(void *optctx, const char *opt, const char *arg)
OptionsContext *o = optctx;
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);
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);
return 0;
}
static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata)
{
AVFormatContext *is = ifile->ctx;
AVFormatContext *os = ofile->ctx;
tmp = av_realloc_f(os->chapters, is->nb_chapters + os->nb_chapters, sizeof(*os->chapters));
if (!tmp)
return AVERROR(ENOMEM);
os->chapters = tmp;
for (i = 0; i < is->nb_chapters; i++) {
AVChapter *in_ch = is->chapters[i], *out_ch;
int64_t start_time = (ofile->start_time == AV_NOPTS_VALUE) ? 0 : ofile->start_time;
int64_t ts_off = av_rescale_q(start_time - ifile->ts_offset,
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
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);
if (copy_metadata)
av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
os->chapters[os->nb_chapters++] = out_ch;
}
return 0;
}
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
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, -1);
st = ost->st;
avctx = st->codec;
ost->enc = codec;
// FIXME: a more elegant solution is needed
memcpy(st, ic->streams[i], sizeof(AVStream));
st->cur_dts = 0;
st->info = av_malloc(sizeof(*st->info));
memcpy(st->info, ic->streams[i]->info, sizeof(*st->info));
st->codec= avctx;
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, st->codec->pix_fmt);
}
avformat_close_input(&ic);
static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
AVFormatContext *oc)
{
OutputStream *ost;
switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
ofilter->out_tmp->pad_idx)) {
case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc, -1); break;
case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc, -1); break;
default:
av_log(NULL, AV_LOG_FATAL, "Only video and audio filters are supported "
"currently.\n");
}
ost->source_index = -1;
ost->filter = ofilter;
ofilter->ost = ost;
if (ost->stream_copy) {
av_log(NULL, AV_LOG_ERROR, "Streamcopy requested for output stream %d:%d, "
"which is fed from a complex filtergraph. Filtering and streamcopy "
"cannot be used together.\n", ost->file_index, ost->index);
Stefano Sabatini
committed
if (ost->avfilter && (ost->filters || ost->filters_script)) {
Stefano Sabatini
committed
const char *opt = ost->filters ? "-vf/-af/-filter" : "-filter_script";
av_log(NULL, AV_LOG_ERROR,
"%s '%s' was specified through the %s option "
"for output stream %d:%d, which is fed from a complex filtergraph.\n"
"%s and -filter_complex cannot be used together for the same stream.\n",
ost->filters ? "Filtergraph" : "Filtergraph script",
ost->filters ? ost->filters : ost->filters_script,
opt, ost->file_index, ost->index, opt);
exit_program(1);
Stefano Sabatini
committed
}
if (configure_output_filter(ofilter->graph, ofilter, ofilter->out_tmp) < 0) {
av_log(NULL, AV_LOG_FATAL, "Error configuring filter.\n");
}
avfilter_inout_free(&ofilter->out_tmp);
}
static int configure_complex_filters(void)
{
int i, ret = 0;
for (i = 0; i < nb_filtergraphs; i++)
if (!filtergraphs[i]->graph &&
(ret = configure_filtergraph(filtergraphs[i])) < 0)
return ret;
return 0;
}
static int open_output_file(OptionsContext *o, const char *filename)
{
AVFormatContext *oc;
int i, j, err;
AVOutputFormat *file_oformat;
OutputFile *of;
OutputStream *ost;
InputStream *ist;
AVDictionary *unused_opts = NULL;
AVDictionaryEntry *e = NULL;
if (configure_complex_filters() < 0) {
av_log(NULL, AV_LOG_FATAL, "Error configuring filters.\n");
if (o->stop_time != INT64_MAX && o->recording_time != INT64_MAX) {
o->stop_time = INT64_MAX;
av_log(NULL, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n");
}
if (o->stop_time != INT64_MAX && o->recording_time == INT64_MAX) {
int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time;
if (o->stop_time <= start_time) {
av_log(NULL, AV_LOG_WARNING, "-to value smaller than -ss; ignoring -to.\n");
o->stop_time = INT64_MAX;
} else {
o->recording_time = o->stop_time - start_time;
}
}
GROW_ARRAY(output_files, nb_output_files);
of = av_mallocz(sizeof(*of));
if (!of)
output_files[nb_output_files - 1] = of;
of->ost_index = nb_output_streams;
of->recording_time = o->recording_time;
of->start_time = o->start_time;
of->limit_filesize = o->limit_filesize;
of->shortest = o->shortest;
av_dict_copy(&of->opts, o->g->format_opts, 0);
if (!strcmp(filename, "-"))
filename = "pipe:";
err = avformat_alloc_output_context2(&oc, NULL, o->format, filename);
print_error(filename, err);
of->ctx = oc;
if (o->recording_time != INT64_MAX)
oc->duration = o->recording_time;
file_oformat= oc->oformat;
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
oc->interrupt_callback = int_cb;
/* create streams for all unlabeled output pads */
for (i = 0; i < nb_filtergraphs; i++) {
FilterGraph *fg = filtergraphs[i];
for (j = 0; j < fg->nb_outputs; j++) {
OutputFilter *ofilter = fg->outputs[j];
if (!ofilter->out_tmp || ofilter->out_tmp->name)
continue;
switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
ofilter->out_tmp->pad_idx)) {
case AVMEDIA_TYPE_VIDEO: o->video_disable = 1; break;
case AVMEDIA_TYPE_AUDIO: o->audio_disable = 1; break;
case AVMEDIA_TYPE_SUBTITLE: o->subtitle_disable = 1; break;
}
init_output_filter(ofilter, o, oc);
}
}
/* ffserver seeking with date=... needs a date reference */
if (!strcmp(file_oformat->name, "ffm") &&
av_strstart(filename, "http:", NULL)) {
int err = parse_option(o, "metadata", "creation_time=now", options);
if (err < 0) {
print_error(filename, err);
exit_program(1);
}
}
if (!strcmp(file_oformat->name, "ffm") && !override_ffserver &&
av_strstart(filename, "http:", NULL)) {
int j;
/* special case for files sent to ffserver: we get the stream
parameters from ffserver */
int err = read_ffserver_streams(o, oc, filename);
if (err < 0) {
print_error(filename, err);
}
for(j = nb_output_streams - oc->nb_streams; j < nb_output_streams; j++) {
ost = output_streams[j];
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
if(ist->st->codec->codec_type == ost->st->codec->codec_type){
ost->sync_ist= ist;
ost->source_index= i;
if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) ost->avfilter = av_strdup("anull");
if(ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) ost->avfilter = av_strdup("null");
ist->discard = 0;
ist->st->discard = AVDISCARD_NONE;
break;
}
}
if(!ost->sync_ist){
av_log(NULL, AV_LOG_FATAL, "Missing %s stream which is required by this ffm\n", av_get_media_type_string(ost->st->codec->codec_type));
} else if (!o->nb_stream_maps) {
char *subtitle_codec_name = NULL;
/* pick the "best" stream of each type */
/* video: highest resolution */
if (!o->video_disable && oc->oformat->video_codec != AV_CODEC_ID_NONE) {
int area = 0, idx = -1;
int qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0);
for (i = 0; i < nb_input_streams; i++) {
int new_area;
ist = input_streams[i];
new_area = ist->st->codec->width * ist->st->codec->height;
if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
new_area = 1;
if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
new_area > area) {
if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
continue;
area = new_area;
idx = i;
}
}
if (idx >= 0)
new_video_stream(o, oc, idx);
}
/* audio: most channels */
if (!o->audio_disable && oc->oformat->audio_codec != AV_CODEC_ID_NONE) {
int channels = 0, idx = -1;
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
ist->st->codec->channels > channels) {
channels = ist->st->codec->channels;
idx = i;
}
}
if (idx >= 0)
new_audio_stream(o, oc, idx);
}
/* subtitles: pick first */
MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, oc, "s");
if (!o->subtitle_disable && (oc->oformat->subtitle_codec != AV_CODEC_ID_NONE || subtitle_codec_name)) {
for (i = 0; i < nb_input_streams; i++)
if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
new_subtitle_stream(o, oc, i);
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
break;
}
}
/* do something with data? */
} else {
for (i = 0; i < o->nb_stream_maps; i++) {
StreamMap *map = &o->stream_maps[i];
if (map->disabled)
continue;
if (map->linklabel) {
FilterGraph *fg;
OutputFilter *ofilter = NULL;
int j, k;
for (j = 0; j < nb_filtergraphs; j++) {
fg = filtergraphs[j];
for (k = 0; k < fg->nb_outputs; k++) {
AVFilterInOut *out = fg->outputs[k]->out_tmp;
if (out && !strcmp(out->name, map->linklabel)) {
ofilter = fg->outputs[k];
goto loop_end;
}
}
}
loop_end:
if (!ofilter) {
av_log(NULL, AV_LOG_FATAL, "Output with label '%s' does not exist "
"in any defined filter graph, or was already used elsewhere.\n", map->linklabel);
}
init_output_filter(ofilter, o, oc);
} else {
int src_idx = input_files[map->file_index]->ist_index + map->stream_index;
ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index];
if(o->subtitle_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
continue;
if(o-> audio_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
continue;
if(o-> video_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
continue;
if(o-> data_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_DATA)
continue;
switch (ist->st->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO: ost = new_video_stream (o, oc, src_idx); break;
case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream (o, oc, src_idx); break;
case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream (o, oc, src_idx); break;
case AVMEDIA_TYPE_DATA: ost = new_data_stream (o, oc, src_idx); break;
case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc, src_idx); break;
default:
av_log(NULL, AV_LOG_FATAL, "Cannot map stream #%d:%d - unsupported type.\n",
map->file_index, map->stream_index);
}
}
}
}
/* handle attached files */
for (i = 0; i < o->nb_attachments; i++) {
AVIOContext *pb;
uint8_t *attachment;
const char *p;
int64_t len;
if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) {
av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n",
o->attachments[i]);
}
if ((len = avio_size(pb)) <= 0) {
av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
o->attachments[i]);
}
if (!(attachment = av_malloc(len))) {
av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n",
o->attachments[i]);
}
avio_read(pb, attachment, len);
ost = new_attachment_stream(o, oc, -1);
ost->stream_copy = 0;
ost->attachment_filename = o->attachments[i];
ost->st->codec->extradata = attachment;
ost->st->codec->extradata_size = len;
p = strrchr(o->attachments[i], '/');
av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE);
avio_close(pb);
}
for (i = nb_output_streams - oc->nb_streams; i < nb_output_streams; i++) { //for all streams of this output file
AVDictionaryEntry *e;
ost = output_streams[i];
if ((ost->stream_copy || ost->attachment_filename)
&& (e = av_dict_get(o->g->codec_opts, "flags", NULL, AV_DICT_IGNORE_SUFFIX))
&& (!e->key[5] || check_stream_specifier(oc, ost->st, e->key+6)))
if (av_opt_set(ost->st->codec, "flags", e->value, 0) < 0)
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
/* check if all codec options have been used */
unused_opts = strip_specifiers(o->g->codec_opts);
for (i = of->ost_index; i < nb_output_streams; i++) {
e = NULL;
while ((e = av_dict_get(output_streams[i]->opts, "", e,
AV_DICT_IGNORE_SUFFIX)))
av_dict_set(&unused_opts, e->key, NULL, 0);
}
e = NULL;
while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
const AVClass *class = avcodec_get_class();
const AVOption *option = av_opt_find(&class, e->key, NULL, 0,
AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
if (!option)
continue;
if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) {
av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
"output file #%d (%s) is not an encoding option.\n", e->key,
option->help ? option->help : "", nb_output_files - 1,
filename);
// gop_timecode is injected by generic code but not always used
if (!strcmp(e->key, "gop_timecode"))
continue;
av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
"output file #%d (%s) has not been used for any stream. The most "
"likely reason is either wrong type (e.g. a video option with "
"no video streams) or that it is a private option of some encoder "
"which was not actually used for any stream.\n", e->key,
option->help ? option->help : "", nb_output_files - 1, filename);
}
av_dict_free(&unused_opts);
/* check filename in case of an image number is expected */
if (oc->oformat->flags & AVFMT_NEEDNUMBER) {
if (!av_filename_number_test(oc->filename)) {
print_error(oc->filename, AVERROR(EINVAL));
}
}
if (!(oc->oformat->flags & AVFMT_NOFILE)) {
/* test if it already exists to avoid losing precious files */
assert_file_overwrite(filename);
/* open the file */
if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,
&oc->interrupt_callback,
&of->opts)) < 0) {
print_error(filename, err);
} else if (strcmp(oc->oformat->name, "image2")==0 && !av_filename_number_test(filename))
assert_file_overwrite(filename);
if (o->mux_preload) {
uint8_t buf[64];
snprintf(buf, sizeof(buf), "%d", (int)(o->mux_preload*AV_TIME_BASE));
av_dict_set(&of->opts, "preload", buf, 0);
}
oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
/* copy metadata */
for (i = 0; i < o->nb_metadata_map; i++) {
char *p;
int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
if (in_file_index >= nb_input_files) {
av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc,
in_file_index >= 0 ?
input_files[in_file_index]->ctx : NULL, o);
}
/* copy chapters */
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*/
o->chapters_input_file = -1;
for (i = 0; i < nb_input_files; i++)
if (input_files[i]->ctx->nb_chapters) {
o->chapters_input_file = i;
break;
}
} else {
av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n",
o->chapters_input_file);
}
}
if (o->chapters_input_file >= 0)
copy_chapters(input_files[o->chapters_input_file], of,
!o->metadata_chapters_manual);
/* copy global metadata by default */
if (!o->metadata_global_manual && nb_input_files){
av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata,
AV_DICT_DONT_OVERWRITE);
if(o->recording_time != INT64_MAX)
av_dict_set(&oc->metadata, "duration", NULL, 0);
av_dict_set(&oc->metadata, "creation_time", NULL, 0);
}
if (!o->metadata_streams_manual)
for (i = of->ost_index; i < nb_output_streams; i++) {
InputStream *ist;
if (output_streams[i]->source_index < 0) /* this is true e.g. for attached files */
continue;
ist = input_streams[output_streams[i]->source_index];
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;
const char *stream_spec;
int index = 0, j, ret = 0;
val = strchr(o->metadata[i].u.str, '=');