Newer
Older
* This file is part of FFmpeg.
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include "cmdutils.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/avutil.h"
#include "libavutil/channel_layout.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/fifo.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#include "libavutil/pixdesc.h"
#include "libavutil/pixfmt.h"
#include "libavutil/time_internal.h"
#define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass"
#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
{\
int i, ret;\
for (i = 0; i < o->nb_ ## name; i++) {\
char *spec = o->name[i].specifier;\
if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0)\
outvar = o->name[i].u.type;\
else if (ret < 0)\
#define MATCH_PER_TYPE_OPT(name, type, outvar, fmtctx, mediatype)\
{\
for (i = 0; i < o->nb_ ## name; i++) {\
char *spec = o->name[i].specifier;\
if (!strcmp(spec, mediatype))\
outvar = o->name[i].u.type;\
}\
}
const HWAccel hwaccels[] = {
#if HAVE_VDPAU_X11
{ "vdpau", vdpau_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU },
{ "dxva2", dxva2_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD },
{ "vda", videotoolbox_init, HWACCEL_VDA, AV_PIX_FMT_VDA },
#endif
#if CONFIG_VIDEOTOOLBOX
{ "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX },
#endif
#if CONFIG_LIBMFX
{ "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV },
char *vstats_filename;
float audio_drift_threshold = 0.1;
float dts_delta_threshold = 10;
float dts_error_threshold = 3600*30;
int audio_volume = 256;
int audio_sync_method = 0;
int video_sync_method = VSYNC_AUTO;
float frame_drop_threshold = 0;
int do_deinterlace = 0;
int do_benchmark = 0;
int do_benchmark_all = 0;
int do_hex_dump = 0;
int do_pkt_dump = 0;
int copy_ts = 0;
int copy_tb = -1;
int debug_ts = 0;
int exit_on_error = 0;
int abort_on_flags = 0;
int stdin_interaction = 1;
int frame_bits_per_raw_sample = 0;
Michael Niedermayer
committed
float max_error_rate = 2.0/3;
static int intra_only = 0;
static int file_overwrite = 0;
static int no_file_overwrite = 0;
static int do_psnr = 0;
static int input_sync;
static int override_ffserver = 0;
static int input_stream_potentially_available = 0;
static int ignore_unknown_streams = 0;
static int copy_unknown_streams = 0;
Michael Niedermayer
committed
static void uninit_options(OptionsContext *o)
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
{
const OptionDef *po = options;
int i;
/* all OPT_SPEC and OPT_STRING can be freed in generic way */
while (po->name) {
void *dst = (uint8_t*)o + po->u.off;
if (po->flags & OPT_SPEC) {
SpecifierOpt **so = dst;
int i, *count = (int*)(so + 1);
for (i = 0; i < *count; i++) {
av_freep(&(*so)[i].specifier);
if (po->flags & OPT_STRING)
av_freep(&(*so)[i].u.str);
}
av_freep(so);
*count = 0;
} else if (po->flags & OPT_OFFSET && po->flags & OPT_STRING)
av_freep(dst);
po++;
}
for (i = 0; i < o->nb_stream_maps; i++)
av_freep(&o->stream_maps[i].linklabel);
av_freep(&o->stream_maps);
av_freep(&o->audio_channel_maps);
av_freep(&o->streamid_map);
Michael Niedermayer
committed
static void init_options(OptionsContext *o)
memset(o, 0, sizeof(*o));
o->mux_max_delay = 0.7;
o->start_time = AV_NOPTS_VALUE;
o->start_time_eof = AV_NOPTS_VALUE;
Michael Niedermayer
committed
o->recording_time = INT64_MAX;
o->limit_filesize = UINT64_MAX;
o->chapters_input_file = INT_MAX;
static int show_hwaccels(void *optctx, const char *opt, const char *arg)
{
int i;
printf("Hardware acceleration methods:\n");
for (i = 0; i < FF_ARRAY_ELEMS(hwaccels) - 1; i++) {
printf("%s\n", hwaccels[i].name);
}
printf("\n");
return 0;
}
/* return a copy of the input with the stream specifiers removed from the keys */
static AVDictionary *strip_specifiers(AVDictionary *dict)
{
AVDictionaryEntry *e = NULL;
AVDictionary *ret = NULL;
while ((e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))) {
char *p = strchr(e->key, ':');
if (p)
*p = 0;
av_dict_set(&ret, e->key, e->value, 0);
if (p)
*p = ':';
}
return ret;
static int opt_abort_on(void *optctx, const char *opt, const char *arg)
{
static const AVOption opts[] = {
{ "abort_on" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" },
{ "empty_output" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ABORT_ON_FLAG_EMPTY_OUTPUT }, .unit = "flags" },
{ NULL },
};
static const AVClass class = {
.class_name = "",
.item_name = av_default_item_name,
.option = opts,
.version = LIBAVUTIL_VERSION_INT,
};
const AVClass *pclass = &class;
return av_opt_eval_flags(&pclass, &opts[0], arg, &abort_on_flags);
}
static int opt_sameq(void *optctx, const char *opt, const char *arg)
{
Stefano Sabatini
committed
av_log(NULL, AV_LOG_ERROR, "Option '%s' was removed. "
"If you are looking for an option to preserve the quality (which is not "
"what -%s was for), use -qscale 0 or an equivalent quality factor option.\n",
opt, opt);
return AVERROR(EINVAL);
static int opt_video_channel(void *optctx, const char *opt, const char *arg)
{
av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -channel.\n");
return opt_default(optctx, "channel", arg);
static int opt_video_standard(void *optctx, const char *opt, const char *arg)
{
av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -standard.\n");
return opt_default(optctx, "standard", arg);
static int opt_audio_codec(void *optctx, const char *opt, const char *arg)
OptionsContext *o = optctx;
return parse_option(o, "codec:a", arg, options);
}
static int opt_video_codec(void *optctx, const char *opt, const char *arg)
OptionsContext *o = optctx;
return parse_option(o, "codec:v", arg, options);
}
static int opt_subtitle_codec(void *optctx, const char *opt, const char *arg)
OptionsContext *o = optctx;
return parse_option(o, "codec:s", arg, options);
}
static int opt_data_codec(void *optctx, const char *opt, const char *arg)
OptionsContext *o = optctx;
return parse_option(o, "codec:d", arg, options);
}
static int opt_map(void *optctx, const char *opt, const char *arg)
OptionsContext *o = optctx;
StreamMap *m = NULL;
int i, negative = 0, file_idx;
int sync_file_idx = -1, sync_stream_idx = 0;
char *p, *sync;
char *map;
char *allow_unused;
if (*arg == '-') {
negative = 1;
arg++;
}
map = av_strdup(arg);
if (!map)
return AVERROR(ENOMEM);
/* parse sync stream first, just pick first matching stream */
if (sync = strchr(map, ',')) {
*sync = 0;
sync_file_idx = strtol(sync + 1, &sync, 0);
if (sync_file_idx >= nb_input_files || sync_file_idx < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid sync file index: %d.\n", sync_file_idx);
}
if (*sync)
sync++;
for (i = 0; i < input_files[sync_file_idx]->nb_streams; i++)
if (check_stream_specifier(input_files[sync_file_idx]->ctx,
input_files[sync_file_idx]->ctx->streams[i], sync) == 1) {
sync_stream_idx = i;
break;
}
if (i == input_files[sync_file_idx]->nb_streams) {
av_log(NULL, AV_LOG_FATAL, "Sync stream specification in map %s does not "
"match any streams.\n", arg);
}
}
if (map[0] == '[') {
/* this mapping refers to lavfi output */
const char *c = map + 1;
GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
m = &o->stream_maps[o->nb_stream_maps - 1];
m->linklabel = av_get_token(&c, "]");
if (!m->linklabel) {
av_log(NULL, AV_LOG_ERROR, "Invalid output link label: %s.\n", map);
if (allow_unused = strchr(map, '?'))
*allow_unused = 0;
file_idx = strtol(map, &p, 0);
if (file_idx >= nb_input_files || file_idx < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid input file index: %d.\n", file_idx);
}
if (negative)
/* disable some already defined maps */
for (i = 0; i < o->nb_stream_maps; i++) {
m = &o->stream_maps[i];
if (file_idx == m->file_index &&
check_stream_specifier(input_files[m->file_index]->ctx,
input_files[m->file_index]->ctx->streams[m->stream_index],
*p == ':' ? p + 1 : p) > 0)
m->disabled = 1;
}
else
for (i = 0; i < input_files[file_idx]->nb_streams; i++) {
if (check_stream_specifier(input_files[file_idx]->ctx, input_files[file_idx]->ctx->streams[i],
*p == ':' ? p + 1 : p) <= 0)
continue;
GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
m = &o->stream_maps[o->nb_stream_maps - 1];
m->file_index = file_idx;
m->stream_index = i;
if (sync_file_idx >= 0) {
m->sync_file_index = sync_file_idx;
m->sync_stream_index = sync_stream_idx;
} else {
m->sync_file_index = file_idx;
m->sync_stream_index = i;
}
}
}
if (!m) {
if (allow_unused) {
av_log(NULL, AV_LOG_VERBOSE, "Stream map '%s' matches no streams; ignoring.\n", arg);
} else {
av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches no streams.\n"
"To ignore this, add a trailing '?' to the map.\n", arg);
exit_program(1);
}
}
av_freep(&map);
return 0;
}
static int opt_attach(void *optctx, const char *opt, const char *arg)
OptionsContext *o = optctx;
GROW_ARRAY(o->attachments, o->nb_attachments);
o->attachments[o->nb_attachments - 1] = arg;
return 0;
}
static int opt_map_channel(void *optctx, const char *opt, const char *arg)
OptionsContext *o = optctx;
int n;
AVStream *st;
AudioChannelMap *m;
GROW_ARRAY(o->audio_channel_maps, o->nb_audio_channel_maps);
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");
}
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);
}
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);
}
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);
}
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);
}
return 0;
}
static int opt_sdp_file(void *optctx, const char *opt, const char *arg)
{
av_free(sdp_filename);
sdp_filename = av_strdup(arg);
return 0;
}
* Parse a metadata specifier passed as 'arg' parameter.
* @param arg metadata string to parse
* @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram)
* @param index for type c/p, chapter/program index is written here
* @param stream_spec for type s, the stream specifier is written here
*/
static void parse_meta_type(char *arg, char *type, int *index, const char **stream_spec)
{
if (*arg) {
*type = *arg;
switch (*arg) {
case 'g':
break;
case 's':
if (*(++arg) && *arg != ':') {
av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg);
}
*stream_spec = *arg == ':' ? arg + 1 : "";
break;
case 'c':
case 'p':
if (*(++arg) == ':')
*index = strtol(++arg, NULL, 0);
break;
default:
av_log(NULL, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
}
} else
*type = 'g';
}
static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
{
AVDictionary **meta_in = NULL;
AVDictionary **meta_out = NULL;
int i, ret = 0;
char type_in, type_out;
const char *istream_spec = NULL, *ostream_spec = NULL;
int idx_in = 0, idx_out = 0;
parse_meta_type(inspec, &type_in, &idx_in, &istream_spec);
parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);
if (!ic) {
if (type_out == 'g' || !*outspec)
o->metadata_global_manual = 1;
if (type_out == 's' || !*outspec)
o->metadata_streams_manual = 1;
if (type_out == 'c' || !*outspec)
o->metadata_chapters_manual = 1;
return 0;
}
if (type_in == 'g' || type_out == 'g')
o->metadata_global_manual = 1;
if (type_in == 's' || type_out == 's')
o->metadata_streams_manual = 1;
if (type_in == 'c' || type_out == 'c')
o->metadata_chapters_manual = 1;
/* ic is NULL when just disabling automatic mappings */
if (!ic)
return 0;
#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
if ((index) < 0 || (index) >= (nb_elems)) {\
av_log(NULL, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\
(desc), (index));\
}
#define SET_DICT(type, meta, context, index)\
switch (type) {\
case 'g':\
meta = &context->metadata;\
break;\
case 'c':\
METADATA_CHECK_INDEX(index, context->nb_chapters, "chapter")\
meta = &context->chapters[index]->metadata;\
break;\
case 'p':\
METADATA_CHECK_INDEX(index, context->nb_programs, "program")\
meta = &context->programs[index]->metadata;\
break;\
break; /* handled separately below */ \
default: av_assert0(0);\
}\
SET_DICT(type_in, meta_in, ic, idx_in);
SET_DICT(type_out, meta_out, oc, idx_out);
/* for input streams choose first matching stream */
if (type_in == 's') {
for (i = 0; i < ic->nb_streams; i++) {
if ((ret = check_stream_specifier(ic, ic->streams[i], istream_spec)) > 0) {
meta_in = &ic->streams[i]->metadata;
break;
} else if (ret < 0)
}
if (!meta_in) {
av_log(NULL, AV_LOG_FATAL, "Stream specifier %s does not match any streams.\n", istream_spec);
}
}
if (type_out == 's') {
for (i = 0; i < oc->nb_streams; i++) {
if ((ret = check_stream_specifier(oc, oc->streams[i], ostream_spec)) > 0) {
meta_out = &oc->streams[i]->metadata;
av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
} else if (ret < 0)
}
} else
av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
return 0;
}
static int opt_recording_timestamp(void *optctx, const char *opt, const char *arg)
OptionsContext *o = optctx;
char buf[128];
int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;
struct tm time = *gmtime((time_t*)&recording_timestamp);
if (!strftime(buf, sizeof(buf), "creation_time=%Y-%m-%dT%H:%M:%S%z", &time))
parse_option(o, "metadata", buf, options);
av_log(NULL, AV_LOG_WARNING, "%s is deprecated, set the 'creation_time' metadata "
"tag instead.\n", opt);
return 0;
}
static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
{
const AVCodecDescriptor *desc;
const char *codec_string = encoder ? "encoder" : "decoder";
AVCodec *codec;
codec = encoder ?
avcodec_find_encoder_by_name(name) :
avcodec_find_decoder_by_name(name);
if (!codec && (desc = avcodec_descriptor_get_by_name(name))) {
codec = encoder ? avcodec_find_encoder(desc->id) :
avcodec_find_decoder(desc->id);
if (codec)
av_log(NULL, AV_LOG_VERBOSE, "Matched %s '%s' for codec '%s'.\n",
codec_string, codec->name, desc->name);
}
if (!codec) {
av_log(NULL, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name);
}
if (codec->type != type) {
av_log(NULL, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name);
}
return codec;
}
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) {
AVCodec *codec = find_codec_or_die(codec_name, st->codec->codec_type, 0);
st->codec->codec_id = codec->id;
return codec;
} else
return avcodec_find_decoder(st->codec->codec_id);
}
/* Add all the streams from the given input file to the global
* list of input streams. */
static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
{
for (i = 0; i < ic->nb_streams; i++) {
AVStream *st = ic->streams[i];
AVCodecContext *dec = st->codec;
InputStream *ist = av_mallocz(sizeof(*ist));
char *framerate = NULL, *hwaccel = NULL, *hwaccel_device = NULL;
char *codec_tag = NULL;
char *next;
char *discard_str = NULL;
const AVOption *discard_opt = av_opt_find(dec, "skip_frame", NULL, 0, 0);
GROW_ARRAY(input_streams, nb_input_streams);
input_streams[nb_input_streams - 1] = ist;
ist->st = st;
ist->file_index = nb_input_files;
ist->discard = 1;
st->discard = AVDISCARD_ALL;
ist->nb_samples = 0;
ist->min_pts = INT64_MAX;
ist->max_pts = INT64_MIN;
ist->ts_scale = 1.0;
MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
Martin Storsjö
committed
ist->autorotate = 1;
MATCH_PER_STREAM_OPT(autorotate, i, ist->autorotate, ic, st);
MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
if (codec_tag) {
uint32_t tag = strtol(codec_tag, &next, 0);
if (*next)
tag = AV_RL32(codec_tag);
st->codec->codec_tag = tag;
}
ist->dec = choose_decoder(o, ic, st);
ist->decoder_opts = filter_codec_opts(o->g->codec_opts, ist->st->codec->codec_id, ic, st, ist->dec);
ist->reinit_filters = -1;
MATCH_PER_STREAM_OPT(reinit_filters, i, ist->reinit_filters, ic, st);
MATCH_PER_STREAM_OPT(discard, str, discard_str, ic, st);
ist->user_set_discard = AVDISCARD_NONE;
if (discard_str && av_opt_eval_int(dec, discard_opt, discard_str, &ist->user_set_discard) < 0) {
av_log(NULL, AV_LOG_ERROR, "Error parsing discard %s.\n",
discard_str);
exit_program(1);
}
ist->filter_in_rescale_delta_last = AV_NOPTS_VALUE;
ist->dec_ctx = avcodec_alloc_context3(ist->dec);
if (!ist->dec_ctx) {
av_log(NULL, AV_LOG_ERROR, "Error allocating the decoder context.\n");
exit_program(1);
}
ret = avcodec_copy_context(ist->dec_ctx, dec);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error initializing the decoder context.\n");
exit_program(1);
}
switch (dec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
if(!ist->dec)
ist->dec = avcodec_find_decoder(dec->codec_id);
#if FF_API_EMU_EDGE
if (av_codec_get_lowres(dec)) {
dec->flags |= CODEC_FLAG_EMU_EDGE;
}
#endif
ist->resample_height = ist->dec_ctx->height;
ist->resample_width = ist->dec_ctx->width;
ist->resample_pix_fmt = ist->dec_ctx->pix_fmt;
MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
if (framerate && av_parse_video_rate(&ist->framerate,
framerate) < 0) {
av_log(NULL, AV_LOG_ERROR, "Error parsing framerate %s.\n",
framerate);
ist->top_field_first = -1;
MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st);
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st);
if (hwaccel) {
if (!strcmp(hwaccel, "none"))
ist->hwaccel_id = HWACCEL_NONE;
else if (!strcmp(hwaccel, "auto"))
ist->hwaccel_id = HWACCEL_AUTO;
else {
int i;
for (i = 0; hwaccels[i].name; i++) {
if (!strcmp(hwaccels[i].name, hwaccel)) {
ist->hwaccel_id = hwaccels[i].id;
break;
}
}
if (!ist->hwaccel_id) {
av_log(NULL, AV_LOG_FATAL, "Unrecognized hwaccel: %s.\n",
hwaccel);
av_log(NULL, AV_LOG_FATAL, "Supported hwaccels: ");
for (i = 0; hwaccels[i].name; i++)
av_log(NULL, AV_LOG_FATAL, "%s ", hwaccels[i].name);
av_log(NULL, AV_LOG_FATAL, "\n");
exit_program(1);
}
}
}
MATCH_PER_STREAM_OPT(hwaccel_devices, str, hwaccel_device, ic, st);
if (hwaccel_device) {
ist->hwaccel_device = av_strdup(hwaccel_device);
if (!ist->hwaccel_device)
exit_program(1);
}
ist->hwaccel_pix_fmt = AV_PIX_FMT_NONE;
break;
case AVMEDIA_TYPE_AUDIO:
ist->guess_layout_max = INT_MAX;
MATCH_PER_STREAM_OPT(guess_layout_max, i, ist->guess_layout_max, ic, st);
guess_input_channel_layout(ist);
ist->resample_sample_fmt = ist->dec_ctx->sample_fmt;
ist->resample_sample_rate = ist->dec_ctx->sample_rate;
ist->resample_channels = ist->dec_ctx->channels;
ist->resample_channel_layout = ist->dec_ctx->channel_layout;
break;
case AVMEDIA_TYPE_DATA:
case AVMEDIA_TYPE_SUBTITLE: {
char *canvas_size = NULL;
if(!ist->dec)
ist->dec = avcodec_find_decoder(dec->codec_id);
MATCH_PER_STREAM_OPT(fix_sub_duration, i, ist->fix_sub_duration, ic, st);
MATCH_PER_STREAM_OPT(canvas_sizes, str, canvas_size, ic, st);
if (canvas_size &&
av_parse_video_size(&ist->dec_ctx->width, &ist->dec_ctx->height, canvas_size) < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid canvas size: %s.\n", canvas_size);
case AVMEDIA_TYPE_ATTACHMENT:
case AVMEDIA_TYPE_UNKNOWN:
break;
default:
abort();
}
}
}
static void assert_file_overwrite(const char *filename)
{
if (file_overwrite && no_file_overwrite) {
Vittorio Giovara
committed
fprintf(stderr, "Error, both -y and -n supplied. Exiting.\n");
exit_program(1);
}
if (!file_overwrite) {
const char *proto_name = avio_find_protocol_name(filename);
if (proto_name && !strcmp(proto_name, "file") && avio_check(filename, 0) == 0) {
if (stdin_interaction && !no_file_overwrite) {
fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
fflush(stderr);
term_exit();
signal(SIGINT, SIG_DFL);
av_log(NULL, AV_LOG_FATAL, "Not overwriting - exiting\n");
av_log(NULL, AV_LOG_FATAL, "File '%s' already exists. Exiting.\n", filename);
}
}
}
}
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);
}
assert_file_overwrite(filename);
if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) {
av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n",
filename);
}
avio_write(out, st->codec->extradata, st->codec->extradata_size);
avio_flush(out);
avio_close(out);
}
static int open_input_file(OptionsContext *o, const char *filename)
InputFile *f;
AVFormatContext *ic;
AVInputFormat *file_iformat = NULL;
int err, i, ret;
int64_t timestamp;
AVDictionary **opts;
AVDictionary *unused_opts = NULL;
AVDictionaryEntry *e = NULL;
int orig_nb_streams; // number of streams before avformat_find_stream_info
char * video_codec_name = NULL;
char * audio_codec_name = NULL;
char *subtitle_codec_name = NULL;
int scan_all_pmts_set = 0;
if (o->format) {
if (!(file_iformat = av_find_input_format(o->format))) {
av_log(NULL, AV_LOG_FATAL, "Unknown input format: '%s'\n", o->format);
}
}
if (!strcmp(filename, "-"))
filename = "pipe:";
stdin_interaction &= strncmp(filename, "pipe:", 5) &&
strcmp(filename, "/dev/stdin");
/* get default parameters from command line */
ic = avformat_alloc_context();
if (!ic) {
print_error(filename, AVERROR(ENOMEM));
}
if (o->nb_audio_sample_rate) {
av_dict_set_int(&o->g->format_opts, "sample_rate", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i, 0);
}
if (o->nb_audio_channels) {
/* because we set audio_channels based on both the "ac" and
* "channel_layout" options, we need to check that the specified
* demuxer actually has the "channels" option before setting it */
if (file_iformat && file_iformat->priv_class &&
av_opt_find(&file_iformat->priv_class, "channels", NULL, 0,
AV_OPT_SEARCH_FAKE_OBJ)) {
av_dict_set_int(&o->g->format_opts, "channels", o->audio_channels[o->nb_audio_channels - 1].u.i, 0);
}
}
if (o->nb_frame_rates) {
/* set the format-level framerate option;
* this is important for video grabbers, e.g. x11 */
if (file_iformat && file_iformat->priv_class &&
av_opt_find(&file_iformat->priv_class, "framerate", NULL, 0,
AV_OPT_SEARCH_FAKE_OBJ)) {
av_dict_set(&o->g->format_opts, "framerate",
o->frame_rates[o->nb_frame_rates - 1].u.str, 0);
}
}
if (o->nb_frame_sizes) {
av_dict_set(&o->g->format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0);
}
if (o->nb_frame_pix_fmts)
av_dict_set(&o->g->format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0);
MATCH_PER_TYPE_OPT(codec_names, str, video_codec_name, ic, "v");
MATCH_PER_TYPE_OPT(codec_names, str, audio_codec_name, ic, "a");
MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, ic, "s");
MATCH_PER_TYPE_OPT(codec_names, str, data_codec_name, ic, "d");
ic->video_codec_id = video_codec_name ?
find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0)->id : AV_CODEC_ID_NONE;
ic->audio_codec_id = audio_codec_name ?
find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)->id : AV_CODEC_ID_NONE;
ic->subtitle_codec_id= subtitle_codec_name ?
find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)->id : AV_CODEC_ID_NONE;
ic->data_codec_id = data_codec_name ?
find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0)->id : AV_CODEC_ID_NONE;
if (video_codec_name)
av_format_set_video_codec (ic, find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0));
if (audio_codec_name)
av_format_set_audio_codec (ic, find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0));
if (subtitle_codec_name)
av_format_set_subtitle_codec(ic, find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0));
if (data_codec_name)
av_format_set_data_codec(ic, find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0));
ic->flags |= AVFMT_FLAG_NONBLOCK;
ic->interrupt_callback = int_cb;
if (!av_dict_get(o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
av_dict_set(&o->g->format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
scan_all_pmts_set = 1;
}
/* open the input file with generic avformat function */
err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts);
if (err < 0) {
print_error(filename, err);
if (scan_all_pmts_set)
av_dict_set(&o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
Michael Niedermayer
committed
remove_avoptions(&o->g->format_opts, o->g->codec_opts);
/* apply forced codec ids */
for (i = 0; i < ic->nb_streams; i++)
choose_decoder(o, ic, ic->streams[i]);
/* Set AVCodecContext options for avformat_find_stream_info */
opts = setup_find_stream_info_opts(ic, o->g->codec_opts);
orig_nb_streams = ic->nb_streams;
/* If not enough info to get the stream parameters, we decode the
first frames to get it. (used in mpeg case for example) */
ret = avformat_find_stream_info(ic, opts);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "%s: could not find codec parameters\n", filename);
Michael Niedermayer
committed
if (ic->nb_streams == 0) {
avformat_close_input(&ic);
exit_program(1);
}
if (o->start_time_eof != AV_NOPTS_VALUE) {
if (ic->duration>0) {
o->start_time = o->start_time_eof + ic->duration;
} else
av_log(NULL, AV_LOG_WARNING, "Cannot use -sseof, duration of %s not known\n", filename);
}
timestamp = (o->start_time == AV_NOPTS_VALUE) ? 0 : o->start_time;
/* add the stream start time */
if (!o->seek_timestamp && ic->start_time != AV_NOPTS_VALUE)
timestamp += ic->start_time;
/* if seeking requested, we execute it */
if (o->start_time != AV_NOPTS_VALUE) {
Michael Niedermayer
committed
int64_t seek_timestamp = timestamp;
if (!(ic->iformat->flags & AVFMT_SEEK_TO_PTS)) {
int dts_heuristic = 0;
for (i=0; i<ic->nb_streams; i++) {
AVCodecContext *avctx = ic->streams[i]->codec;
if (avctx->has_b_frames)
dts_heuristic = 1;
}
if (dts_heuristic) {
seek_timestamp -= 3*AV_TIME_BASE / 23;
}
}
ret = avformat_seek_file(ic, -1, INT64_MIN, seek_timestamp, seek_timestamp, 0);
if (ret < 0) {
av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
filename, (double)timestamp / AV_TIME_BASE);
}
}
/* update the current parameters so that they match the one of the input stream */
add_input_streams(o, ic);
/* dump the file content */
av_dump_format(ic, nb_input_files, filename, 0);
GROW_ARRAY(input_files, nb_input_files);
f = av_mallocz(sizeof(*f));
if (!f)
input_files[nb_input_files - 1] = f;
f->ctx = ic;
f->ist_index = nb_input_streams - ic->nb_streams;
f->start_time = o->start_time;
f->recording_time = o->recording_time;
Michael Niedermayer
committed
f->input_ts_offset = o->input_ts_offset;
f->ts_offset = o->input_ts_offset - (copy_ts ? (start_at_zero && ic->start_time != AV_NOPTS_VALUE ? ic->start_time : 0) : timestamp);
f->nb_streams = ic->nb_streams;
f->rate_emu = o->rate_emu;
f->accurate_seek = o->accurate_seek;
f->loop = o->loop;
f->duration = 0;
f->time_base = (AVRational){ 1, 1 };
#if HAVE_PTHREADS
f->thread_queue_size = o->thread_queue_size > 0 ? o->thread_queue_size : 8;
#endif
/* check if all codec options have been used */
unused_opts = strip_specifiers(o->g->codec_opts);
for (i = f->ist_index; i < nb_input_streams; i++) {
e = NULL;
while ((e = av_dict_get(input_streams[i]->decoder_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);
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) {
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
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;
if (arg)
if (!(bsfc->args = av_strdup(arg))) {
av_log(NULL, AV_LOG_FATAL, "Bitstream filter memory allocation failed\n");
exit_program(1);
}
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;
Michael Niedermayer
committed
av_dict_copy(&ost->sws_dict, o->g->sws_dict, 0);
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++;
}
}
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
/* 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,
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
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 best_score = 0, idx = -1;
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
score = ist->st->codec->channels + 100000000*!!ist->st->codec_info_nb_frames;
if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
score > best_score) {
best_score = score;
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
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
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;
}
/* Data only if codec id match */
if (!o->data_disable ) {
enum AVCodecID codec_id = av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_DATA);
for (i = 0; codec_id != AV_CODEC_ID_NONE && i < nb_input_streams; i++) {
if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_DATA
&& input_streams[i]->st->codec->codec_id == codec_id )
new_data_stream(o, oc, i);
}
}
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
} 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;
case AVMEDIA_TYPE_UNKNOWN:
if (copy_unknown_streams) {
ost = new_unknown_stream (o, oc, src_idx);
break;
}
Michael Niedermayer
committed
av_log(NULL, ignore_unknown_streams ? AV_LOG_WARNING : AV_LOG_FATAL,
"Cannot map stream #%d:%d - unsupported type.\n",
map->file_index, map->stream_index);
if (!ignore_unknown_streams) {
av_log(NULL, AV_LOG_FATAL,
"If you want unsupported types ignored instead "
"of failing, please use the -ignore_unknown option\n"
"If you want them copied, please use -copy_unknown\n");
}
if (ost)
ost->sync_ist = input_streams[ input_files[map->sync_file_index]->ist_index
+ map->sync_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 = 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);
Michael Niedermayer
committed
avio_closep(&pb);
Loading
Loading full blame...