Newer
Older
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) {
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
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 |= CODEC_FLAG_QSCALE;
ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale;
}
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
ost->enc_ctx->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 = 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++;
}
}
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
/* 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)
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;
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->encoder_opts, "flags", "+pass1", AV_DICT_APPEND);
}
if (do_pass & 2) {
video_enc->flags |= 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)))
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_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,
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
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 (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_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;
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
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 = 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;
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;
}
}
if (idx >= 0)
new_audio_stream(o, oc, idx);
}
/* subtitles: pick first */
MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, oc, "s");
Michael Niedermayer
committed
if (!o->subtitle_disable && (avcodec_find_encoder(oc->oformat->subtitle_codec) || subtitle_codec_name)) {
for (i = 0; i < nb_input_streams; i++)
if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
Carl Eugen Hoyos
committed
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
AVCodecDescriptor const *input_descriptor =
avcodec_descriptor_get(input_streams[i]->st->codec->codec_id);
AVCodecDescriptor const *output_descriptor = NULL;
AVCodec const *output_codec =
avcodec_find_encoder(oc->oformat->subtitle_codec);
int input_props = 0, output_props = 0;
if (output_codec)
output_descriptor = avcodec_descriptor_get(output_codec->id);
if (input_descriptor)
input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
if (output_descriptor)
output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
if (subtitle_codec_name ||
input_props & output_props ||
// Map dvb teletext which has neither property to any output subtitle encoder
input_descriptor && output_descriptor &&
(!input_descriptor->props ||
!output_descriptor->props)) {
new_subtitle_stream(o, oc, i);
break;
}
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
}
}
/* 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",