int sync_stream_index;
} StreamMap;
+typedef struct {
+ int file_idx, stream_idx, channel_idx; // input
+ int ofile_idx, ostream_idx; // output
+} AudioChannelMap;
+
/**
* select an input file for an output file
*/
/* audio only */
int audio_resample;
+ int audio_channels_map[SWR_CH_MAX]; ///< list of the channels id to pick from the source stream
+ int audio_channels_mapped; ///< number of channels in audio_channels_map
int resample_sample_fmt;
int resample_channels;
int resample_sample_rate;
+ float rematrix_volume;
AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */
FILE *logfile;
int64_t sws_flags;
AVDictionary *opts;
int is_past_recording_time;
+ int stream_copy;
+ const char *attachment_filename;
} OutputStream;
int nb_audio_channels;
SpecifierOpt *audio_sample_rate;
int nb_audio_sample_rate;
+ SpecifierOpt *rematrix_volume;
+ int nb_rematrix_volume;
SpecifierOpt *frame_rates;
int nb_frame_rates;
SpecifierOpt *frame_sizes;
SpecifierOpt *ts_scale;
int nb_ts_scale;
+ SpecifierOpt *dump_attachment;
+ int nb_dump_attachment;
/* output options */
StreamMap *stream_maps;
int nb_stream_maps;
+ AudioChannelMap *audio_channel_maps; ///< one info entry per -map_channel
+ int nb_audio_channel_maps; ///< number of (valid) -map_channel settings
/* first item specifies output metadata, second is input */
MetadataMap (*meta_data_maps)[2];
int nb_meta_data_maps;
int metadata_global_manual;
int metadata_streams_manual;
int metadata_chapters_manual;
+ const char **attachments;
+ int nb_attachments;
int chapters_input_file;
int nb_inter_matrices;
SpecifierOpt *top_field_first;
int nb_top_field_first;
+ SpecifierOpt *presets;
+ int nb_presets;
#if CONFIG_AVFILTER
SpecifierOpt *filters;
int nb_filters;
}
av_freep(&o->stream_maps);
+ av_freep(&o->audio_channel_maps);
av_freep(&o->meta_data_maps);
av_freep(&o->streamid_map);
if(is_input) o->recording_time = bak.recording_time;
else o->recording_time = INT64_MAX;
- o->mux_preload = 0.5;
o->mux_max_delay = 0.7;
o->limit_filesize = UINT64_MAX;
o->chapters_input_file = INT_MAX;
}
if (*p == -1) {
if((codec->capabilities & CODEC_CAP_LOSSLESS) && av_get_sample_fmt_name(st->codec->sample_fmt) > av_get_sample_fmt_name(codec->sample_fmts[0]))
- av_log(NULL, AV_LOG_ERROR, "Convertion will not be lossless'\n");
+ av_log(NULL, AV_LOG_ERROR, "Conversion will not be lossless.\n");
if(av_get_sample_fmt_name(st->codec->sample_fmt))
av_log(NULL, AV_LOG_WARNING,
"Incompatible sample format '%s' for codec '%s', auto-selecting format '%s'\n",
ost->resample_channels != dec->channels ||
ost->resample_sample_rate != dec->sample_rate;
- if ((ost->audio_resample && !ost->swr) || resample_changed) {
+ if ((ost->audio_resample && !ost->swr) || resample_changed || ost->audio_channels_mapped) {
if (resample_changed) {
av_log(NULL, AV_LOG_INFO, "Input stream #%d.%d frame changed from rate:%d fmt:%s ch:%d to rate:%d fmt:%s ch:%d\n",
ist->file_index, ist->st->index,
swr_free(&ost->swr);
}
/* if audio_sync_method is >1 the resampler is needed for audio drift compensation */
- if (audio_sync_method <= 1 &&
+ if (audio_sync_method <= 1 && !ost->audio_channels_mapped &&
ost->resample_sample_fmt == enc->sample_fmt &&
ost->resample_channels == enc->channels &&
ost->resample_sample_rate == enc->sample_rate) {
ost->swr = swr_alloc2(ost->swr,
enc->channel_layout, enc->sample_fmt, enc->sample_rate,
dec->channel_layout, dec->sample_fmt, dec->sample_rate,
+ ost->audio_channels_mapped ? ost->audio_channels_map : NULL,
0, NULL);
+ av_set_double(ost->swr, "rmvol", ost->rematrix_volume);
+ if (ost->audio_channels_mapped) {
+ av_set_int(ost->swr, "icl", av_get_default_channel_layout(ost->audio_channels_mapped));
+ av_set_int(ost->swr, "uch", ost->audio_channels_mapped);
+ }
av_set_int(ost->swr, "ich", dec->channels);
av_set_int(ost->swr, "och", enc->channels);
if(audio_sync_method>1) av_set_int(ost->swr, "flags", SWR_FLAG_RESAMPLE);
float q = -1;
ost = &ost_table[i];
enc = ost->st->codec;
- if (!ost->st->stream_copy && enc->coded_frame)
+ if (!ost->stream_copy && enc->coded_frame)
q = enc->coded_frame->quality/(float)FF_QP2LAMBDA;
if (vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "q=%2.1f ", q);
#if CONFIG_AVFILTER
int frame_available;
#endif
- float quality;
+ float quality = 0;
AVPacket avpkt;
int bps = av_get_bytes_per_sample(ist->st->codec->sample_fmt);
os = output_files[ost->file_index].ctx;
ist = &input_streams[ost->source_index];
+ if (ost->attachment_filename)
+ continue;
+
codec = ost->st->codec;
icodec = ist->st->codec;
codec->bits_per_raw_sample= icodec->bits_per_raw_sample;
codec->chroma_sample_location = icodec->chroma_sample_location;
- if (ost->st->stream_copy) {
+ if (ost->stream_copy) {
uint64_t extra_size = (uint64_t)icodec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE;
if (extra_size > INT_MAX) {
ist->st->codec->sample_aspect_ratio.num ?
ist->st->codec->sample_aspect_ratio : (AVRational){0, 1};
}
+ ost->st->avg_frame_rate = ist->st->avg_frame_rate;
break;
case AVMEDIA_TYPE_SUBTITLE:
codec->width = icodec->width;
if (!ost->fifo) {
return AVERROR(ENOMEM);
}
- if (!codec->sample_rate) {
+ if (!codec->sample_rate)
codec->sample_rate = icodec->sample_rate;
- }
choose_sample_rate(ost->st, ost->enc);
codec->time_base = (AVRational){1, codec->sample_rate};
if (codec->sample_fmt == AV_SAMPLE_FMT_NONE)
codec->sample_fmt = icodec->sample_fmt;
choose_sample_fmt(ost->st, ost->enc);
- if (!codec->channels) {
+ if (ost->audio_channels_mapped) {
+ /* the requested output channel is set to the number of
+ * -map_channel only if no -ac are specified */
+ if (!codec->channels) {
+ codec->channels = ost->audio_channels_mapped;
+ codec->channel_layout = av_get_default_channel_layout(codec->channels);
+ if (!codec->channel_layout) {
+ av_log(NULL, AV_LOG_FATAL, "Unable to find an appropriate channel layout for requested number of channel\n");
+ exit_program(1);
+ }
+ }
+ /* fill unused channel mapping with -1 (which means a muted
+ * channel in case the number of output channels is bigger
+ * than the number of mapped channel) */
+ for (j = ost->audio_channels_mapped; j < FF_ARRAY_ELEMS(ost->audio_channels_map); j++)
+ ost->audio_channels_map[j] = -1;
+ } else if (!codec->channels) {
codec->channels = icodec->channels;
codec->channel_layout = icodec->channel_layout;
}
snprintf(logfilename, sizeof(logfilename), "%s-%d.log",
pass_logfilename_prefix ? pass_logfilename_prefix : DEFAULT_PASS_LOGFILENAME_PREFIX,
i);
+ if (codec->flags & CODEC_FLAG_PASS2) {
+ char *logbuffer;
+ size_t logbuffer_size;
+ if (cmdutils_read_file(logfilename, &logbuffer, &logbuffer_size) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n",
+ logfilename);
+ exit_program(1);
+ }
+ codec->stats_in = logbuffer;
+ }
if (codec->flags & CODEC_FLAG_PASS1) {
f = fopen(logfilename, "wb");
if (!f) {
exit_program(1);
}
ost->logfile = f;
- } else {
- char *logbuffer;
- size_t logbuffer_size;
- if (read_file(logfilename, &logbuffer, &logbuffer_size) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n",
- logfilename);
- exit_program(1);
- }
- codec->stats_in = logbuffer;
}
}
}
av_log(NULL, AV_LOG_INFO, "Stream mapping:\n");
for (i = 0; i < nb_output_streams; i++) {
ost = &output_streams[i];
+
+ if (ost->attachment_filename) {
+ /* an attached file */
+ av_log(NULL, AV_LOG_INFO, " File %s -> Stream #%d:%d\n",
+ ost->attachment_filename, ost->file_index, ost->index);
+ continue;
+ }
av_log(NULL, AV_LOG_INFO, " Stream #%d.%d -> #%d.%d",
input_streams[ost->source_index].file_index,
input_streams[ost->source_index].st->index,
ost->file_index,
ost->index);
+ if (ost->audio_channels_mapped) {
+ av_log(NULL, AV_LOG_INFO, " [ch:");
+ for (j = 0; j < ost->audio_channels_mapped; j++)
+ if (ost->audio_channels_map[j] == -1)
+ av_log(NULL, AV_LOG_INFO, " M");
+ else
+ av_log(NULL, AV_LOG_INFO, " %d", ost->audio_channels_map[j]);
+ av_log(NULL, AV_LOG_INFO, "]");
+ }
if (ost->sync_ist != &input_streams[ost->source_index])
av_log(NULL, AV_LOG_INFO, " [sync #%d.%d]",
ost->sync_ist->file_index,
ost->sync_ist->st->index);
- if (ost->st->stream_copy)
+ if (ost->stream_copy)
av_log(NULL, AV_LOG_INFO, " (copy)");
else
av_log(NULL, AV_LOG_INFO, " (%s -> %s)", input_streams[ost->source_index].dec ?
for (i = 0; i < nb_output_streams; i++) {
ost = &output_streams[i];
if (ost) {
- if (ost->st->stream_copy)
+ if (ost->stream_copy)
av_freep(&ost->st->codec->extradata);
if (ost->logfile) {
fclose(ost->logfile);
/* disable some already defined maps */
for (i = 0; i < o->nb_stream_maps; i++) {
m = &o->stream_maps[i];
- if (check_stream_specifier(input_files[m->file_index].ctx,
+ 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;
return 0;
}
+static int opt_attach(OptionsContext *o, const char *opt, const char *arg)
+{
+ o->attachments = grow_array(o->attachments, sizeof(*o->attachments),
+ &o->nb_attachments, o->nb_attachments + 1);
+ o->attachments[o->nb_attachments - 1] = arg;
+ return 0;
+}
+
+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) {
return 0;
}
-static enum CodecID find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
+static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
{
const char *codec_string = encoder ? "encoder" : "decoder";
AVCodec *codec;
- if(!name)
- return CODEC_ID_NONE;
codec = encoder ?
avcodec_find_encoder_by_name(name) :
avcodec_find_decoder_by_name(name);
av_log(NULL, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name);
exit_program(1);
}
- return codec->id;
+ return codec;
}
-static AVCodec *choose_codec(OptionsContext *o, AVFormatContext *s, AVStream *st, enum AVMediaType type)
+static AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st)
{
char *codec_name = NULL;
MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
-
- if (!codec_name) {
- if (s->oformat) {
- st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename, NULL, type);
- return avcodec_find_encoder(st->codec->codec_id);
- }
- } else if (!strcmp(codec_name, "copy"))
- st->stream_copy = 1;
- else {
- st->codec->codec_id = find_codec_or_die(codec_name, type, s->iformat == NULL);
- return s->oformat ? avcodec_find_encoder_by_name(codec_name) :
- avcodec_find_decoder_by_name(codec_name);
- }
-
- return NULL;
+ 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);
}
/**
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];
MATCH_PER_STREAM_OPT(ts_scale, dbl, scale, ic, st);
ist->ts_scale = scale;
- ist->dec = choose_codec(o, ic, st, dec->codec_type);
- if (!ist->dec)
- ist->dec = avcodec_find_decoder(dec->codec_id);
+ 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:
}
}
+static void assert_file_overwrite(const char *filename)
+{
+ if (!file_overwrite &&
+ (strchr(filename, ':') == NULL || filename[1] == ':' ||
+ av_strstart(filename, "file:", NULL))) {
+ if (avio_check(filename, 0) == 0) {
+ if (!using_stdin) {
+ fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
+ fflush(stderr);
+ term_exit();
+ 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_open (&out, filename, AVIO_FLAG_WRITE)) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n",
+ filename);
+ exit_program(1);
+ }
+
+ avio_write(out, st->codec->extradata, st->codec->extradata_size);
+ avio_flush(out);
+ avio_close(out);
+}
+
static int opt_input_file(OptionsContext *o, const char *opt, const char *filename)
{
AVFormatContext *ic;
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 =
- find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0);
- ic->audio_codec_id =
- find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0);
- ic->subtitle_codec_id=
- find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 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->flags |= AVFMT_FLAG_NONBLOCK;
if (loop_input) {
/* apply forced codec ids */
for (i = 0; i < ic->nb_streams; i++)
- choose_codec(o, ic, ic->streams[i], ic->streams[i]->codec->codec_type);
+ choose_decoder(o, ic, ic->streams[i]);
/* Set AVCodecContext options for avformat_find_stream_info */
opts = setup_find_stream_info_opts(ic, codec_opts);
input_files[nb_input_files - 1].nb_streams = ic->nb_streams;
input_files[nb_input_files - 1].rate_emu = o->rate_emu;
+ for (i = 0; i < o->nb_dump_attachment; i++) {
+ int j;
+
+ for (j = 0; j < ic->nb_streams; j++) {
+ AVStream *st = ic->streams[j];
+
+ if (check_stream_specifier(ic, st, o->dump_attachment[i].specifier) == 1)
+ dump_attachment(st, o->dump_attachment[i].u.str);
+ }
+ }
+
for (i = 0; i < orig_nb_streams; i++)
av_dict_free(&opts[i]);
av_freep(&opts);
}
}
+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_open(s, filename, AVIO_FLAG_READ);
+ }
+ if (ret) {
+ snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i],
+ i != 1 ? "" : "/.avconv", preset_name);
+ ret = avio_open(s, filename, AVIO_FLAG_READ);
+ }
+ }
+ 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)
{
OutputStream *ost;
- AVStream *st = av_new_stream(oc, oc->nb_streams < o->nb_streamid_map ? o->streamid_map[oc->nb_streams] : 0);
- int idx = oc->nb_streams - 1;
+ AVStream *st = avformat_new_stream(oc, NULL);
+ int idx = oc->nb_streams - 1, ret = 0;
int64_t max_frames = INT64_MAX;
char *bsf = NULL, *next, *codec_tag = NULL;
AVBitStreamFilterContext *bsfc, *bsfc_prev = NULL;
double qscale = -1;
+ char *buf = NULL, *arg = NULL, *preset = NULL;
+ AVIOContext *s = NULL;
if (!st) {
av_log(NULL, AV_LOG_FATAL, "Could not alloc stream.\n");
exit_program(1);
}
+ 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->index = idx;
ost->st = st;
st->codec->codec_type = type;
- ost->enc = choose_codec(o, oc, st, type);
+ choose_encoder(o, oc, ost);
if (ost->enc) {
ost->opts = filter_codec_opts(codec_opts, ost->enc->id, oc, st);
}
avcodec_get_context_defaults3(st->codec, ost->enc);
st->codec->codec_type = type; // XXX hack, avcodec_get_context_defaults2() sets type to unknown for stream copy
+ 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);
+ }
+
MATCH_PER_STREAM_OPT(max_frames, i64, max_frames, oc, st);
ost->max_frames = max_frames;
st = ost->st;
video_enc = st->codec;
- if (!st->stream_copy) {
+ 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;
/* two pass mode */
if (do_pass) {
- if (do_pass == 1) {
+ if (do_pass & 1) {
video_enc->flags |= CODEC_FLAG_PASS1;
- } else {
+ }
+ if (do_pass & 2) {
video_enc->flags |= CODEC_FLAG_PASS2;
}
}
static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
{
+ int n;
AVStream *st;
OutputStream *ost;
AVCodecContext *audio_enc;
audio_enc = st->codec;
audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
- if (!st->stream_copy) {
+ if (!ost->stream_copy) {
char *sample_fmt = NULL;
MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st);
}
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);
+ }
+
+ /* 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);
+ }
}
return ost;
static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc)
{
- AVStream *st;
OutputStream *ost;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA);
- st = ost->st;
- if (!st->stream_copy) {
+ if (!ost->stream_copy) {
av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
exit_program(1);
}
static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc)
{
OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT);
- ost->st->stream_copy = 1;
+ ost->stream_copy = 1;
return ost;
}
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;
+ avctx = st->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));
+ st->codec= avctx;
avcodec_copy_context(st->codec, ic->streams[i]->codec);
- if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && !st->stream_copy)
+ 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 && !st->stream_copy)
+ else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !ost->stream_copy)
choose_pixel_fmt(st, codec);
}
if (!strcmp(file_oformat->name, "ffm") &&
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);
print_error(filename, err);
exit_program(1);
}
+ 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;
+ ist->discard = 0;
+ break;
+ }
+ }
+ }
} else if (!o->nb_stream_maps) {
/* pick the "best" stream of each type */
#define NEW_STREAM(type, 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_open(&pb, o->attachments[i], AVIO_FLAG_READ)) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n",
+ o->attachments[i]);
+ exit_program(1);
+ }
+ if ((len = avio_size(pb)) <= 0) {
+ av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
+ o->attachments[i]);
+ exit_program(1);
+ }
+ if (!(attachment = av_malloc(len))) {
+ av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n",
+ o->attachments[i]);
+ exit_program(1);
+ }
+ avio_read(pb, attachment, len);
+
+ ost = new_attachment_stream(o, oc);
+ ost->stream_copy = 0;
+ ost->source_index = -1;
+ 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);
+ }
+
output_files = grow_array(output_files, sizeof(*output_files), &nb_output_files, nb_output_files + 1);
output_files[nb_output_files - 1].ctx = oc;
output_files[nb_output_files - 1].ost_index = nb_output_streams - oc->nb_streams;
if (!(oc->oformat->flags & AVFMT_NOFILE)) {
/* test if it already exists to avoid loosing precious files */
- if (!file_overwrite &&
- (strchr(filename, ':') == NULL ||
- filename[1] == ':' ||
- av_strstart(filename, "file:", NULL))) {
- if (avio_check(filename, 0) == 0) {
- if (!using_stdin) {
- fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
- fflush(stderr);
- term_exit();
- 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);
- }
- }
- }
+ assert_file_overwrite(filename);
/* open the file */
if ((err = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE)) < 0) {
}
}
- oc->preload = (int)(o->mux_preload * AV_TIME_BASE);
+ if (o->mux_preload) {
+ uint8_t buf[64];
+ snprintf(buf, sizeof(buf), "%d", (int)(o->mux_preload*AV_TIME_BASE));
+ av_dict_set(&output_files[nb_output_files - 1].opts, "preload", buf, 0);
+ }
oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
if (loop_output >= 0) {
METADATA_CHECK_INDEX(map->index, files[j]->nb_programs, "program")
meta[j] = &files[j]->programs[map->index]->metadata;
break;
+ default:
+ abort();
}
}
}
if (!o->metadata_streams_manual)
for (i = output_files[nb_output_files - 1].ost_index; i < nb_output_streams; i++) {
- InputStream *ist = &input_streams[output_streams[i].source_index];
+ 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);
}
/* same option as mencoder */
static int opt_pass(const char *opt, const char *arg)
{
- do_pass = parse_number_or_die(opt, arg, OPT_INT, 1, 2);
+ do_pass = parse_number_or_die(opt, arg, OPT_INT, 1, 3);
return 0;
}
{ "y", OPT_BOOL, {(void*)&file_overwrite}, "overwrite output files" },
{ "c", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" },
{ "codec", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" },
+ { "pre", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(presets)}, "preset name", "preset" },
{ "map", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map}, "set input stream mapping", "file.stream[:syncfile.syncstream]" },
+ { "map_channel", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_channel}, "map an audio channel from one stream to another", "file.stream.channel[:syncfile.syncstream]" },
{ "map_meta_data", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_meta_data}, "DEPRECATED set meta data information of outfile from infile",
"outfile[,metadata]:infile[,metadata]" },
{ "map_metadata", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_metadata}, "set metadata information of outfile from infile",
{ "filter", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(filters)}, "set stream filterchain", "filter_list" },
#endif
{ "stats", OPT_BOOL, {&print_stats}, "print progress report during encoding", },
+ { "attach", HAS_ARG | OPT_FUNC2, {(void*)opt_attach}, "add an attachment to the output file", "filename" },
+ { "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(dump_attachment)}, "extract an attachment into a file", "filename" },
/* video options */
{ "vframes", HAS_ARG | OPT_VIDEO | OPT_FUNC2, {(void*)opt_video_frames}, "set the number of video frames to record", "number" },
{ "atag", HAS_ARG | OPT_EXPERT | OPT_AUDIO | OPT_FUNC2, {(void*)opt_old2new}, "force audio tag/fourcc", "fourcc/tag" },
{ "vol", OPT_INT | HAS_ARG | OPT_AUDIO, {(void*)&audio_volume}, "change audio volume (256=normal)" , "volume" }, //
{ "sample_fmt", HAS_ARG | OPT_EXPERT | OPT_AUDIO | OPT_SPEC | OPT_STRING, {.off = OFFSET(sample_fmts)}, "set sample format", "format" },
+ { "rmvol", HAS_ARG | OPT_AUDIO | OPT_FLOAT | OPT_SPEC, {.off = OFFSET(rematrix_volume)}, "rematrix volume (as factor)", "volume" },
/* subtitle options */
{ "sn", OPT_BOOL | OPT_SUBTITLE | OPT_OFFSET, {.off = OFFSET(subtitle_disable)}, "disable subtitle" },