Newer
Older
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);
Michael Niedermayer
committed
const AVClass *fclass = avformat_get_class();
const AVOption *foption = av_opt_find(&fclass, e->key, NULL, 0,
AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
if (!option || foption)
Michael Niedermayer
committed
if (!(option->flags & AV_OPT_FLAG_DECODING_PARAM)) {
av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
"input file #%d (%s) is not a decoding option.\n", e->key,
option->help ? option->help : "", nb_input_files - 1,
filename);
}
av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
"input 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 decoder "
"which was not actually used for any stream.\n", e->key,
option->help ? option->help : "", nb_input_files - 1, filename);
}
av_dict_free(&unused_opts);
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);
input_stream_potentially_available = 1;
return 0;
}
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");
}
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 < 0; 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 < 0) {
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
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);
}
}
return ret;
}
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, int source_index)
{
OutputStream *ost;
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;
double qscale = -1;
int i;
if (!st) {
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];
GROW_ARRAY(output_streams, nb_output_streams);
if (!(ost = av_mallocz(sizeof(*ost))))
output_streams[nb_output_streams - 1] = ost;
ost->file_index = nb_output_files - 1;
ost->index = idx;
ost->st = st;
st->codec->codec_type = type;
choose_encoder(o, oc, ost);
ost->enc_ctx = avcodec_alloc_context3(ost->enc);
if (!ost->enc_ctx) {
av_log(NULL, AV_LOG_ERROR, "Error allocating the encoding context.\n");
exit_program(1);
}
ost->enc_ctx->codec_type = type;
AVIOContext *s = NULL;
char *buf = NULL, *arg = NULL, *preset = NULL;
ost->encoder_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");
av_dict_set(&ost->encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE);
av_free(buf);
} while (!s->eof_reached);
Michael Niedermayer
committed
avio_closep(&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->encoder_opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL);
}
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) {
char *arg = NULL;
if (next = strchr(bsf, ','))
*next++ = 0;
if (arg = strchr(bsf, '='))
*arg++ = 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;
av_dict_set(&ost->bsf_args, bsfc->filter->name, arg, 0);
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);
ost->enc_ctx->codec_tag = tag;
}
MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st);
ost->enc_ctx->flags |= AV_CODEC_FLAG_QSCALE;
ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale;
MATCH_PER_STREAM_OPT(disposition, str, ost->disposition, oc, st);
ost->disposition = av_strdup(ost->disposition);
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
ost->enc_ctx->flags |= AV_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 = input_streams[source_index]->user_set_discard;
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++;
}
}
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
/* 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);
video_enc = ost->enc_ctx;
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);
if (frame_rate && video_sync_method == VSYNC_PASSTHROUGH)
av_log(NULL, AV_LOG_ERROR, "Using -vsync 0 and -r can produce invalid output files\n");
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;
char *chroma_intra_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(chroma_intra_matrices, str, chroma_intra_matrix, oc, st);
if (chroma_intra_matrix) {
uint16_t *p = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64);
if (!p) {
av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for intra matrix.\n");
exit_program(1);
}
av_codec_set_chroma_intra_matrix(video_enc, p);
parse_matrix_coeffs(p, chroma_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");
}
video_enc->rc_override =
av_realloc_array(video_enc->rc_override,
i + 1, sizeof(RcOverride));
if (!video_enc->rc_override) {
av_log(NULL, AV_LOG_FATAL, "Could not (re)allocate memory for rc_override.\n");
exit_program(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->flags|= AV_CODEC_FLAG_PSNR;
MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
video_enc->flags |= AV_CODEC_FLAG_PASS1;
av_dict_set(&ost->encoder_opts, "flags", "+pass1", AV_DICT_APPEND);
}
if (do_pass & 2) {
video_enc->flags |= AV_CODEC_FLAG_PASS2;
av_dict_set(&ost->encoder_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)))
if (do_pass) {
char logfilename[1024];
FILE *f;
snprintf(logfilename, sizeof(logfilename), "%s-%d.log",
ost->logfile_prefix ? ost->logfile_prefix :
DEFAULT_PASS_LOGFILENAME_PREFIX,
i);
if (!strcmp(ost->enc->name, "libx264")) {
av_dict_set(&ost->encoder_opts, "stats", logfilename, AV_DICT_DONT_OVERWRITE);
} else {
if (video_enc->flags & AV_CODEC_FLAG_PASS2) {
char *logbuffer = read_file(logfilename);
if (!logbuffer) {
av_log(NULL, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n",
logfilename);
exit_program(1);
}
video_enc->stats_in = logbuffer;
}
if (video_enc->flags & AV_CODEC_FLAG_PASS1) {
f = av_fopen_utf8(logfilename, "wb");
if (!f) {
av_log(NULL, AV_LOG_FATAL,
"Cannot write log file '%s' for pass-1 encoding: %s\n",
logfilename, strerror(errno));
exit_program(1);
}
ost->logfile = f;
}
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);
audio_enc = ost->enc_ctx;
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];
Michael Niedermayer
committed
if ((map->ofile_idx == -1 || ost->file_index == map->ofile_idx) &&
(map->ostream_idx == -1 || ost->st->index == map->ostream_idx)) {
Michael Niedermayer
committed
InputStream *ist;
if (map->channel_idx == -1) {
ist = NULL;
} else if (ost->source_index < 0) {
av_log(NULL, AV_LOG_FATAL, "Cannot determine input stream for channel mapping %d.%d\n",
ost->file_index, ost->st->index);
Michael Niedermayer
committed
continue;
} else {
ist = input_streams[ost->source_index];
}
if (!ist || (ist->file_index == map->file_idx && ist->st->index == map->stream_idx)) {
if (av_reallocp_array(&ost->audio_channels_map,
ost->audio_channels_mapped + 1,
sizeof(*ost->audio_channels_map)
) < 0 )
exit_program(1);
ost->audio_channels_map[ost->audio_channels_mapped++] = map->channel_idx;
Michael Niedermayer
committed
}
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_unknown_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
{
OutputStream *ost;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_UNKNOWN, source_index);
if (!ost->stream_copy) {
av_log(NULL, AV_LOG_FATAL, "Unknown stream encoding not supported yet (only streamcopy)\n");
exit_program(1);
}
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);
subtitle_enc = ost->enc_ctx;
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,
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
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;
}
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;
const char *enc_config;
codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
if (!codec) {
av_log(s, AV_LOG_ERROR, "no encoder found for codec id %i\n", ic->streams[i]->codec->codec_id);
return AVERROR(EINVAL);
}
if (codec->type == AVMEDIA_TYPE_AUDIO)
opt_audio_codec(o, "c:a", codec->name);
else if (codec->type == AVMEDIA_TYPE_VIDEO)
opt_video_codec(o, "c:v", codec->name);
ost = new_output_stream(o, s, codec->type, -1);
st = ost->st;
avcodec_get_context_defaults3(st->codec, codec);
enc_config = av_stream_get_recommended_encoder_configuration(ic->streams[i]);
if (enc_config) {
AVDictionary *opts = NULL;
av_dict_parse_string(&opts, enc_config, "=", ",", 0);
av_opt_set_dict2(st->codec, &opts, AV_OPT_SEARCH_CHILDREN);
av_dict_free(&opts);
}
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)
Michael Niedermayer
committed
choose_pixel_fmt(st, st->codec, codec, st->codec->pix_fmt);
avcodec_copy_context(ost->enc_ctx, st->codec);
if (enc_config)
av_dict_parse_string(&ost->encoder_opts, enc_config, "=", ",", 0);
}
avformat_close_input(&ic);
static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
AVFormatContext *oc)
{
OutputStream *ost;
switch (ofilter->type) {
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
}
avfilter_inout_free(&ofilter->out_tmp);
}
static int init_complex_filters(void)
{
int i, ret = 0;
for (i = 0; i < nb_filtergraphs; i++) {
ret = init_complex_filtergraph(filtergraphs[i]);
if (ret < 0)
return ret;
}
return 0;
}
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 (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_ERROR, "-to value smaller than -ss; aborting.\n");
exit_program(1);
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;
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 (ofilter->type) {
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 = ist->user_set_discard;
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 && av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_VIDEO) != 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 + 100000000*!!ist->st->codec_info_nb_frames;
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 && av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_AUDIO) != 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;
}
}