|
@@ -117,8 +117,8 @@ static const OptionDef options[];
|
|
|
#define MAX_STREAMS 1024 /* arbitrary sanity check value */
|
|
|
|
|
|
static const char *last_asked_format = NULL;
|
|
|
-static double *input_files_ts_scale[MAX_FILES] = {NULL};
|
|
|
-static int nb_input_files_ts_scale[MAX_FILES] = {0};
|
|
|
+static double *ts_scale;
|
|
|
+static int nb_ts_scale;
|
|
|
|
|
|
static AVFormatContext *output_files[MAX_FILES];
|
|
|
static int nb_output_files = 0;
|
|
@@ -171,7 +171,6 @@ static char *vfilters = NULL;
|
|
|
|
|
|
static int intra_only = 0;
|
|
|
static int audio_sample_rate = 0;
|
|
|
-static int64_t channel_layout = 0;
|
|
|
#define QSCALE_NONE -99999
|
|
|
static float audio_qscale = QSCALE_NONE;
|
|
|
static int audio_disable = 0;
|
|
@@ -194,7 +193,6 @@ static float mux_max_delay= 0.7;
|
|
|
|
|
|
static int64_t recording_time = INT64_MAX;
|
|
|
static int64_t start_time = 0;
|
|
|
-static int64_t recording_timestamp = 0;
|
|
|
static int64_t input_ts_offset = 0;
|
|
|
static int file_overwrite = 0;
|
|
|
static AVDictionary *metadata;
|
|
@@ -327,6 +325,7 @@ typedef struct InputStream {
|
|
|
int64_t next_pts; /* synthetic pts for cases where pkt.pts
|
|
|
is not defined */
|
|
|
int64_t pts; /* current pts */
|
|
|
+ double ts_scale;
|
|
|
int is_start; /* is 1 at the start and after a discontinuity */
|
|
|
int showed_multi_packet_warning;
|
|
|
int is_past_recording_time;
|
|
@@ -538,7 +537,6 @@ static int ffmpeg_exit(int ret)
|
|
|
}
|
|
|
for(i=0;i<nb_input_files;i++) {
|
|
|
av_close_input_file(input_files[i].ctx);
|
|
|
- av_free(input_files_ts_scale[i]);
|
|
|
}
|
|
|
|
|
|
av_free(intra_matrix);
|
|
@@ -671,10 +669,16 @@ static void choose_pixel_fmt(AVStream *st, AVCodec *codec)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static OutputStream *new_output_stream(AVFormatContext *oc, int file_idx)
|
|
|
+static OutputStream *new_output_stream(AVFormatContext *oc, int file_idx, AVCodec *codec)
|
|
|
{
|
|
|
- int idx = oc->nb_streams - 1;
|
|
|
OutputStream *ost;
|
|
|
+ AVStream *st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0);
|
|
|
+ int idx = oc->nb_streams - 1;
|
|
|
+
|
|
|
+ if (!st) {
|
|
|
+ av_log(NULL, AV_LOG_ERROR, "Could not alloc stream.\n");
|
|
|
+ ffmpeg_exit(1);
|
|
|
+ }
|
|
|
|
|
|
output_streams_for_file[file_idx] =
|
|
|
grow_array(output_streams_for_file[file_idx],
|
|
@@ -689,6 +693,10 @@ static OutputStream *new_output_stream(AVFormatContext *oc, int file_idx)
|
|
|
}
|
|
|
ost->file_index = file_idx;
|
|
|
ost->index = idx;
|
|
|
+ ost->st = st;
|
|
|
+ ost->enc = codec;
|
|
|
+
|
|
|
+ avcodec_get_context_defaults3(st->codec, codec);
|
|
|
|
|
|
ost->sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
|
|
|
return ost;
|
|
@@ -704,28 +712,21 @@ static int read_ffserver_streams(AVFormatContext *s, const char *filename)
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
/* copy stream format */
|
|
|
- s->nb_streams = 0;
|
|
|
- s->streams = av_mallocz(sizeof(AVStream *) * ic->nb_streams);
|
|
|
for(i=0;i<ic->nb_streams;i++) {
|
|
|
AVStream *st;
|
|
|
+ OutputStream *ost;
|
|
|
AVCodec *codec;
|
|
|
|
|
|
- s->nb_streams++;
|
|
|
+ codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
|
|
|
+ ost = new_output_stream(s, nb_output_files, codec);
|
|
|
+ st = ost->st;
|
|
|
|
|
|
// FIXME: a more elegant solution is needed
|
|
|
- st = av_mallocz(sizeof(AVStream));
|
|
|
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 = avcodec_alloc_context();
|
|
|
- if (!st->codec) {
|
|
|
- print_error(filename, AVERROR(ENOMEM));
|
|
|
- ffmpeg_exit(1);
|
|
|
- }
|
|
|
avcodec_copy_context(st->codec, ic->streams[i]->codec);
|
|
|
- s->streams[i] = st;
|
|
|
|
|
|
- codec = avcodec_find_encoder(st->codec->codec_id);
|
|
|
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
|
|
|
if (audio_stream_copy) {
|
|
|
st->stream_copy = 1;
|
|
@@ -740,13 +741,8 @@ static int read_ffserver_streams(AVFormatContext *s, const char *filename)
|
|
|
|
|
|
if(st->codec->flags & CODEC_FLAG_BITEXACT)
|
|
|
nopts = 1;
|
|
|
-
|
|
|
- new_output_stream(s, nb_output_files);
|
|
|
}
|
|
|
|
|
|
- if (!nopts)
|
|
|
- s->timestamp = av_gettime();
|
|
|
-
|
|
|
av_close_input_file(ic);
|
|
|
return 0;
|
|
|
}
|
|
@@ -2102,7 +2098,6 @@ static int transcode(AVFormatContext **output_files,
|
|
|
for(i=0;i<os->nb_streams;i++,n++) {
|
|
|
int found;
|
|
|
ost = ost_table[n] = output_streams_for_file[k][i];
|
|
|
- ost->st = os->streams[i];
|
|
|
if (nb_stream_maps > 0) {
|
|
|
ost->source_index = input_files[stream_maps[n].file_index].ist_index +
|
|
|
stream_maps[n].stream_index;
|
|
@@ -2278,6 +2273,9 @@ static int transcode(AVFormatContext **output_files,
|
|
|
}
|
|
|
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) {
|
|
|
codec->channels = icodec->channels;
|
|
|
codec->channel_layout = icodec->channel_layout;
|
|
@@ -2738,12 +2736,11 @@ static int transcode(AVFormatContext **output_files,
|
|
|
if (pkt.pts != AV_NOPTS_VALUE)
|
|
|
pkt.pts += av_rescale_q(input_files[ist->file_index].ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
|
|
|
|
|
|
- if (pkt.stream_index < nb_input_files_ts_scale[file_index]
|
|
|
- && input_files_ts_scale[file_index][pkt.stream_index]){
|
|
|
+ if (ist->ts_scale) {
|
|
|
if(pkt.pts != AV_NOPTS_VALUE)
|
|
|
- pkt.pts *= input_files_ts_scale[file_index][pkt.stream_index];
|
|
|
+ pkt.pts *= ist->ts_scale;
|
|
|
if(pkt.dts != AV_NOPTS_VALUE)
|
|
|
- pkt.dts *= input_files_ts_scale[file_index][pkt.stream_index];
|
|
|
+ pkt.dts *= ist->ts_scale;
|
|
|
}
|
|
|
|
|
|
// fprintf(stderr, "next:%"PRId64" dts:%"PRId64" off:%"PRId64" %d\n", ist->next_pts, pkt.dts, input_files[ist->file_index].ts_offset, ist->st->codec->codec_type);
|
|
@@ -3203,8 +3200,8 @@ static int opt_input_ts_scale(const char *opt, const char *arg)
|
|
|
if(stream >= MAX_STREAMS)
|
|
|
ffmpeg_exit(1);
|
|
|
|
|
|
- input_files_ts_scale[nb_input_files] = grow_array(input_files_ts_scale[nb_input_files], sizeof(*input_files_ts_scale[nb_input_files]), &nb_input_files_ts_scale[nb_input_files], stream + 1);
|
|
|
- input_files_ts_scale[nb_input_files][stream]= scale;
|
|
|
+ ts_scale = grow_array(ts_scale, sizeof(*ts_scale), &nb_ts_scale, stream + 1);
|
|
|
+ ts_scale[stream] = scale;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -3222,7 +3219,14 @@ static int opt_start_time(const char *opt, const char *arg)
|
|
|
|
|
|
static int opt_recording_timestamp(const char *opt, const char *arg)
|
|
|
{
|
|
|
- recording_timestamp = parse_time_or_die(opt, arg, 0) / 1000000;
|
|
|
+ char buf[128];
|
|
|
+ int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;
|
|
|
+ struct tm time = *gmtime((time_t*)&recording_timestamp);
|
|
|
+ strftime(buf, sizeof(buf), "creation_time=%FT%T%z", &time);
|
|
|
+ opt_metadata("metadata", buf);
|
|
|
+
|
|
|
+ av_log(NULL, AV_LOG_WARNING, "%s is deprecated, set the 'creation_time' metadata "
|
|
|
+ "tag instead.\n", opt);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -3401,14 +3405,15 @@ static int opt_input_file(const char *opt, const char *filename)
|
|
|
ist->file_index = nb_input_files;
|
|
|
ist->discard = 1;
|
|
|
|
|
|
+ if (i < nb_ts_scale)
|
|
|
+ ist->ts_scale = ts_scale[i];
|
|
|
+
|
|
|
switch (dec->codec_type) {
|
|
|
case AVMEDIA_TYPE_AUDIO:
|
|
|
ist->dec = avcodec_find_decoder_by_name(audio_codec_name);
|
|
|
if(!ist->dec)
|
|
|
ist->dec = avcodec_find_decoder(dec->codec_id);
|
|
|
set_context_opts(dec, avcodec_opts[AVMEDIA_TYPE_AUDIO], AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM, ist->dec);
|
|
|
- channel_layout = dec->channel_layout;
|
|
|
- audio_sample_fmt = dec->sample_fmt;
|
|
|
if(audio_disable)
|
|
|
st->discard= AVDISCARD_ALL;
|
|
|
break;
|
|
@@ -3475,6 +3480,9 @@ static int opt_input_file(const char *opt, const char *filename)
|
|
|
frame_width = 0;
|
|
|
audio_sample_rate = 0;
|
|
|
audio_channels = 0;
|
|
|
+ audio_sample_fmt = AV_SAMPLE_FMT_NONE;
|
|
|
+ av_freep(&ts_scale);
|
|
|
+ nb_ts_scale = 0;
|
|
|
|
|
|
av_freep(&video_codec_name);
|
|
|
av_freep(&audio_codec_name);
|
|
@@ -3535,23 +3543,20 @@ static void new_video_stream(AVFormatContext *oc, int file_idx)
|
|
|
enum CodecID codec_id = CODEC_ID_NONE;
|
|
|
AVCodec *codec= NULL;
|
|
|
|
|
|
- st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0);
|
|
|
- if (!st) {
|
|
|
- fprintf(stderr, "Could not alloc stream\n");
|
|
|
- ffmpeg_exit(1);
|
|
|
- }
|
|
|
- ost = new_output_stream(oc, file_idx);
|
|
|
-
|
|
|
if(!video_stream_copy){
|
|
|
if (video_codec_name) {
|
|
|
codec_id = find_codec_or_die(video_codec_name, AVMEDIA_TYPE_VIDEO, 1,
|
|
|
avcodec_opts[AVMEDIA_TYPE_VIDEO]->strict_std_compliance);
|
|
|
codec = avcodec_find_encoder_by_name(video_codec_name);
|
|
|
- ost->enc = codec;
|
|
|
} else {
|
|
|
codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_VIDEO);
|
|
|
codec = avcodec_find_encoder(codec_id);
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ ost = new_output_stream(oc, file_idx, codec);
|
|
|
+ st = ost->st;
|
|
|
+ if (!video_stream_copy) {
|
|
|
ost->frame_aspect_ratio = frame_aspect_ratio;
|
|
|
frame_aspect_ratio = 0;
|
|
|
#if CONFIG_AVFILTER
|
|
@@ -3560,7 +3565,6 @@ static void new_video_stream(AVFormatContext *oc, int file_idx)
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
- avcodec_get_context_defaults3(st->codec, codec);
|
|
|
ost->bitstream_filters = video_bitstream_filters;
|
|
|
video_bitstream_filters= NULL;
|
|
|
|
|
@@ -3674,26 +3678,18 @@ static void new_audio_stream(AVFormatContext *oc, int file_idx)
|
|
|
AVCodecContext *audio_enc;
|
|
|
enum CodecID codec_id = CODEC_ID_NONE;
|
|
|
|
|
|
- st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0);
|
|
|
- if (!st) {
|
|
|
- fprintf(stderr, "Could not alloc stream\n");
|
|
|
- ffmpeg_exit(1);
|
|
|
- }
|
|
|
- ost = new_output_stream(oc, file_idx);
|
|
|
-
|
|
|
if(!audio_stream_copy){
|
|
|
if (audio_codec_name) {
|
|
|
codec_id = find_codec_or_die(audio_codec_name, AVMEDIA_TYPE_AUDIO, 1,
|
|
|
avcodec_opts[AVMEDIA_TYPE_AUDIO]->strict_std_compliance);
|
|
|
codec = avcodec_find_encoder_by_name(audio_codec_name);
|
|
|
- ost->enc = codec;
|
|
|
} else {
|
|
|
codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_AUDIO);
|
|
|
codec = avcodec_find_encoder(codec_id);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- avcodec_get_context_defaults3(st->codec, codec);
|
|
|
+ ost = new_output_stream(oc, file_idx, codec);
|
|
|
+ st = ost->st;
|
|
|
|
|
|
ost->bitstream_filters = audio_bitstream_filters;
|
|
|
audio_bitstream_filters= NULL;
|
|
@@ -3722,11 +3718,10 @@ static void new_audio_stream(AVFormatContext *oc, int file_idx)
|
|
|
}
|
|
|
if (audio_channels)
|
|
|
audio_enc->channels = audio_channels;
|
|
|
- audio_enc->sample_fmt = audio_sample_fmt;
|
|
|
+ if (audio_sample_fmt != AV_SAMPLE_FMT_NONE)
|
|
|
+ audio_enc->sample_fmt = audio_sample_fmt;
|
|
|
if (audio_sample_rate)
|
|
|
audio_enc->sample_rate = audio_sample_rate;
|
|
|
- audio_enc->channel_layout = channel_layout;
|
|
|
- choose_sample_fmt(st, codec);
|
|
|
}
|
|
|
if (audio_language) {
|
|
|
av_dict_set(&st->metadata, "language", audio_language, 0);
|
|
@@ -3742,21 +3737,16 @@ static void new_audio_stream(AVFormatContext *oc, int file_idx)
|
|
|
static void new_data_stream(AVFormatContext *oc, int file_idx)
|
|
|
{
|
|
|
AVStream *st;
|
|
|
- AVCodec *codec=NULL;
|
|
|
+ OutputStream *ost;
|
|
|
AVCodecContext *data_enc;
|
|
|
|
|
|
- st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0);
|
|
|
- if (!st) {
|
|
|
- fprintf(stderr, "Could not alloc stream\n");
|
|
|
- ffmpeg_exit(1);
|
|
|
- }
|
|
|
- new_output_stream(oc, file_idx);
|
|
|
+ ost = new_output_stream(oc, file_idx, NULL);
|
|
|
+ st = ost->st;
|
|
|
data_enc = st->codec;
|
|
|
if (!data_stream_copy) {
|
|
|
fprintf(stderr, "Data stream encoding not supported yet (only streamcopy)\n");
|
|
|
ffmpeg_exit(1);
|
|
|
}
|
|
|
- avcodec_get_context_defaults3(st->codec, codec);
|
|
|
|
|
|
data_enc->codec_type = AVMEDIA_TYPE_DATA;
|
|
|
|
|
@@ -3784,25 +3774,19 @@ static void new_subtitle_stream(AVFormatContext *oc, int file_idx)
|
|
|
AVCodecContext *subtitle_enc;
|
|
|
enum CodecID codec_id = CODEC_ID_NONE;
|
|
|
|
|
|
- st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0);
|
|
|
- if (!st) {
|
|
|
- fprintf(stderr, "Could not alloc stream\n");
|
|
|
- ffmpeg_exit(1);
|
|
|
- }
|
|
|
- ost = new_output_stream(oc, file_idx);
|
|
|
- subtitle_enc = st->codec;
|
|
|
if(!subtitle_stream_copy){
|
|
|
if (subtitle_codec_name) {
|
|
|
codec_id = find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 1,
|
|
|
avcodec_opts[AVMEDIA_TYPE_SUBTITLE]->strict_std_compliance);
|
|
|
codec = avcodec_find_encoder_by_name(subtitle_codec_name);
|
|
|
- ost->enc = codec;
|
|
|
} else {
|
|
|
codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_SUBTITLE);
|
|
|
codec = avcodec_find_encoder(codec_id);
|
|
|
}
|
|
|
}
|
|
|
- avcodec_get_context_defaults3(st->codec, codec);
|
|
|
+ ost = new_output_stream(oc, file_idx, codec);
|
|
|
+ st = ost->st;
|
|
|
+ subtitle_enc = st->codec;
|
|
|
|
|
|
ost->bitstream_filters = subtitle_bitstream_filters;
|
|
|
subtitle_bitstream_filters= NULL;
|
|
@@ -3938,8 +3922,6 @@ static int opt_output_file(const char *opt, const char *filename)
|
|
|
if (use_subtitle) new_subtitle_stream(oc, nb_output_files);
|
|
|
if (use_data) new_data_stream(oc, nb_output_files);
|
|
|
|
|
|
- oc->timestamp = recording_timestamp;
|
|
|
-
|
|
|
av_dict_copy(&oc->metadata, metadata, 0);
|
|
|
av_dict_free(&metadata);
|
|
|
}
|
|
@@ -4005,6 +3987,7 @@ static int opt_output_file(const char *opt, const char *filename)
|
|
|
frame_height = 0;
|
|
|
audio_sample_rate = 0;
|
|
|
audio_channels = 0;
|
|
|
+ audio_sample_fmt = AV_SAMPLE_FMT_NONE;
|
|
|
|
|
|
av_freep(&forced_key_frames);
|
|
|
uninit_opts();
|