|
|
|
@@ -264,15 +264,15 @@ typedef struct OutputFile { |
|
|
|
uint64_t limit_filesize; |
|
|
|
} OutputFile; |
|
|
|
|
|
|
|
static InputStream *input_streams = NULL; |
|
|
|
static int nb_input_streams = 0; |
|
|
|
static InputFile *input_files = NULL; |
|
|
|
static int nb_input_files = 0; |
|
|
|
static InputStream **input_streams = NULL; |
|
|
|
static int nb_input_streams = 0; |
|
|
|
static InputFile **input_files = NULL; |
|
|
|
static int nb_input_files = 0; |
|
|
|
|
|
|
|
static OutputStream *output_streams = NULL; |
|
|
|
static int nb_output_streams = 0; |
|
|
|
static OutputFile *output_files = NULL; |
|
|
|
static int nb_output_files = 0; |
|
|
|
static OutputStream **output_streams = NULL; |
|
|
|
static int nb_output_streams = 0; |
|
|
|
static OutputFile **output_files = NULL; |
|
|
|
static int nb_output_files = 0; |
|
|
|
|
|
|
|
typedef struct OptionsContext { |
|
|
|
/* input/output options */ |
|
|
|
@@ -663,38 +663,42 @@ void exit_program(int ret) |
|
|
|
|
|
|
|
/* close files */ |
|
|
|
for (i = 0; i < nb_output_files; i++) { |
|
|
|
AVFormatContext *s = output_files[i].ctx; |
|
|
|
AVFormatContext *s = output_files[i]->ctx; |
|
|
|
if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) |
|
|
|
avio_close(s->pb); |
|
|
|
avformat_free_context(s); |
|
|
|
av_dict_free(&output_files[i].opts); |
|
|
|
av_dict_free(&output_files[i]->opts); |
|
|
|
av_freep(&output_files[i]); |
|
|
|
} |
|
|
|
for (i = 0; i < nb_output_streams; i++) { |
|
|
|
AVBitStreamFilterContext *bsfc = output_streams[i].bitstream_filters; |
|
|
|
AVBitStreamFilterContext *bsfc = output_streams[i]->bitstream_filters; |
|
|
|
while (bsfc) { |
|
|
|
AVBitStreamFilterContext *next = bsfc->next; |
|
|
|
av_bitstream_filter_close(bsfc); |
|
|
|
bsfc = next; |
|
|
|
} |
|
|
|
output_streams[i].bitstream_filters = NULL; |
|
|
|
output_streams[i]->bitstream_filters = NULL; |
|
|
|
|
|
|
|
if (output_streams[i].output_frame) { |
|
|
|
AVFrame *frame = output_streams[i].output_frame; |
|
|
|
if (output_streams[i]->output_frame) { |
|
|
|
AVFrame *frame = output_streams[i]->output_frame; |
|
|
|
if (frame->extended_data != frame->data) |
|
|
|
av_freep(&frame->extended_data); |
|
|
|
av_freep(&frame); |
|
|
|
} |
|
|
|
|
|
|
|
av_freep(&output_streams[i].avfilter); |
|
|
|
av_freep(&output_streams[i]->avfilter); |
|
|
|
av_freep(&output_streams[i]); |
|
|
|
} |
|
|
|
for (i = 0; i < nb_input_files; i++) { |
|
|
|
avformat_close_input(&input_files[i].ctx); |
|
|
|
avformat_close_input(&input_files[i]->ctx); |
|
|
|
av_freep(&input_files[i]); |
|
|
|
} |
|
|
|
for (i = 0; i < nb_input_streams; i++) { |
|
|
|
av_freep(&input_streams[i].decoded_frame); |
|
|
|
av_freep(&input_streams[i].filtered_frame); |
|
|
|
av_dict_free(&input_streams[i].opts); |
|
|
|
free_buffer_pool(&input_streams[i]); |
|
|
|
av_freep(&input_streams[i]->decoded_frame); |
|
|
|
av_freep(&input_streams[i]->filtered_frame); |
|
|
|
av_dict_free(&input_streams[i]->opts); |
|
|
|
free_buffer_pool(input_streams[i]); |
|
|
|
av_freep(&input_streams[i]); |
|
|
|
} |
|
|
|
|
|
|
|
if (vstats_file) |
|
|
|
@@ -860,7 +864,7 @@ static void choose_pixel_fmt(AVStream *st, AVCodec *codec) |
|
|
|
static double |
|
|
|
get_sync_ipts(const OutputStream *ost, int64_t pts) |
|
|
|
{ |
|
|
|
OutputFile *of = &output_files[ost->file_index]; |
|
|
|
OutputFile *of = output_files[ost->file_index]; |
|
|
|
return (double)(pts - of->start_time) / AV_TIME_BASE; |
|
|
|
} |
|
|
|
|
|
|
|
@@ -917,7 +921,7 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost) |
|
|
|
|
|
|
|
static int check_recording_time(OutputStream *ost) |
|
|
|
{ |
|
|
|
OutputFile *of = &output_files[ost->file_index]; |
|
|
|
OutputFile *of = output_files[ost->file_index]; |
|
|
|
|
|
|
|
if (of->recording_time != INT64_MAX && |
|
|
|
av_compare_ts(ost->sync_opts - ost->first_pts, ost->st->codec->time_base, of->recording_time, |
|
|
|
@@ -1514,7 +1518,7 @@ static void print_report(int is_last_report, int64_t timer_start) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
oc = output_files[0].ctx; |
|
|
|
oc = output_files[0]->ctx; |
|
|
|
|
|
|
|
total_size = avio_size(oc->pb); |
|
|
|
if (total_size < 0) // FIXME improve avio_size() so it works with non seekable output too |
|
|
|
@@ -1525,7 +1529,7 @@ static void print_report(int is_last_report, int64_t timer_start) |
|
|
|
vid = 0; |
|
|
|
for (i = 0; i < nb_output_streams; i++) { |
|
|
|
float q = -1; |
|
|
|
ost = &output_streams[i]; |
|
|
|
ost = output_streams[i]; |
|
|
|
enc = ost->st->codec; |
|
|
|
if (!ost->stream_copy && enc->coded_frame) |
|
|
|
q = enc->coded_frame->quality / (float)FF_QP2LAMBDA; |
|
|
|
@@ -1611,9 +1615,9 @@ static void flush_encoders(void) |
|
|
|
int i, ret; |
|
|
|
|
|
|
|
for (i = 0; i < nb_output_streams; i++) { |
|
|
|
OutputStream *ost = &output_streams[i]; |
|
|
|
OutputStream *ost = output_streams[i]; |
|
|
|
AVCodecContext *enc = ost->st->codec; |
|
|
|
AVFormatContext *os = output_files[ost->file_index].ctx; |
|
|
|
AVFormatContext *os = output_files[ost->file_index]->ctx; |
|
|
|
int stop_encoding = 0; |
|
|
|
|
|
|
|
if (!ost->encoding_needed) |
|
|
|
@@ -1692,8 +1696,8 @@ static void flush_encoders(void) |
|
|
|
*/ |
|
|
|
static int check_output_constraints(InputStream *ist, OutputStream *ost) |
|
|
|
{ |
|
|
|
OutputFile *of = &output_files[ost->file_index]; |
|
|
|
int ist_index = ist - input_streams; |
|
|
|
OutputFile *of = output_files[ost->file_index]; |
|
|
|
int ist_index = input_files[ist->file_index]->ist_index + ist->st->index; |
|
|
|
|
|
|
|
if (ost->source_index != ist_index) |
|
|
|
return 0; |
|
|
|
@@ -1706,7 +1710,7 @@ static int check_output_constraints(InputStream *ist, OutputStream *ost) |
|
|
|
|
|
|
|
static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *pkt) |
|
|
|
{ |
|
|
|
OutputFile *of = &output_files[ost->file_index]; |
|
|
|
OutputFile *of = output_files[ost->file_index]; |
|
|
|
int64_t ost_tb_start_time = av_rescale_q(of->start_time, AV_TIME_BASE_Q, ost->st->time_base); |
|
|
|
AVPacket opkt; |
|
|
|
|
|
|
|
@@ -1764,7 +1768,7 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p |
|
|
|
|
|
|
|
static void rate_emu_sleep(InputStream *ist) |
|
|
|
{ |
|
|
|
if (input_files[ist->file_index].rate_emu) { |
|
|
|
if (input_files[ist->file_index]->rate_emu) { |
|
|
|
int64_t pts = av_rescale(ist->last_dts, 1000000, AV_TIME_BASE); |
|
|
|
int64_t now = av_gettime() - ist->start; |
|
|
|
if (pts > now) |
|
|
|
@@ -1866,11 +1870,11 @@ static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output) |
|
|
|
rate_emu_sleep(ist); |
|
|
|
|
|
|
|
for (i = 0; i < nb_output_streams; i++) { |
|
|
|
OutputStream *ost = &output_streams[i]; |
|
|
|
OutputStream *ost = output_streams[i]; |
|
|
|
|
|
|
|
if (!check_output_constraints(ist, ost) || !ost->encoding_needed) |
|
|
|
continue; |
|
|
|
do_audio_out(output_files[ost->file_index].ctx, ost, ist, decoded_frame); |
|
|
|
do_audio_out(output_files[ost->file_index]->ctx, ost, ist, decoded_frame); |
|
|
|
} |
|
|
|
|
|
|
|
return ret; |
|
|
|
@@ -1914,7 +1918,7 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int |
|
|
|
decoded_frame->sample_aspect_ratio = ist->st->sample_aspect_ratio; |
|
|
|
|
|
|
|
for (i = 0; i < nb_output_streams; i++) { |
|
|
|
OutputStream *ost = &output_streams[i]; |
|
|
|
OutputStream *ost = output_streams[i]; |
|
|
|
int frame_size, resample_changed; |
|
|
|
|
|
|
|
if (!check_output_constraints(ist, ost) || !ost->encoding_needed) |
|
|
|
@@ -1978,10 +1982,10 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int |
|
|
|
if (!ost->frame_aspect_ratio) |
|
|
|
ost->st->codec->sample_aspect_ratio = picref->video->pixel_aspect; |
|
|
|
|
|
|
|
do_video_out(output_files[ost->file_index].ctx, ost, filtered_frame, &frame_size, |
|
|
|
do_video_out(output_files[ost->file_index]->ctx, ost, filtered_frame, &frame_size, |
|
|
|
same_quant ? quality : ost->st->codec->global_quality); |
|
|
|
if (vstats_filename && frame_size) |
|
|
|
do_video_stats(output_files[ost->file_index].ctx, ost, frame_size); |
|
|
|
do_video_stats(output_files[ost->file_index]->ctx, ost, frame_size); |
|
|
|
frame_available = ost->output_video_filter && avfilter_poll_frame(ost->output_video_filter->inputs[0]); |
|
|
|
avfilter_unref_buffer(picref); |
|
|
|
} |
|
|
|
@@ -2005,12 +2009,12 @@ static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output) |
|
|
|
rate_emu_sleep(ist); |
|
|
|
|
|
|
|
for (i = 0; i < nb_output_streams; i++) { |
|
|
|
OutputStream *ost = &output_streams[i]; |
|
|
|
OutputStream *ost = output_streams[i]; |
|
|
|
|
|
|
|
if (!check_output_constraints(ist, ost) || !ost->encoding_needed) |
|
|
|
continue; |
|
|
|
|
|
|
|
do_subtitle_out(output_files[ost->file_index].ctx, ost, ist, &subtitle, pkt->pts); |
|
|
|
do_subtitle_out(output_files[ost->file_index]->ctx, ost, ist, &subtitle, pkt->pts); |
|
|
|
} |
|
|
|
|
|
|
|
avsubtitle_free(&subtitle); |
|
|
|
@@ -2113,7 +2117,7 @@ static int output_packet(InputStream *ist, const AVPacket *pkt) |
|
|
|
} |
|
|
|
} |
|
|
|
for (i = 0; pkt && i < nb_output_streams; i++) { |
|
|
|
OutputStream *ost = &output_streams[i]; |
|
|
|
OutputStream *ost = output_streams[i]; |
|
|
|
|
|
|
|
if (!check_output_constraints(ist, ost) || ost->encoding_needed) |
|
|
|
continue; |
|
|
|
@@ -2133,7 +2137,7 @@ static void print_sdp(void) |
|
|
|
if (!avc) |
|
|
|
exit_program(1); |
|
|
|
for (i = 0; i < nb_output_files; i++) |
|
|
|
avc[i] = output_files[i].ctx; |
|
|
|
avc[i] = output_files[i]->ctx; |
|
|
|
|
|
|
|
av_sdp_create(avc, nb_output_files, sdp, sizeof(sdp)); |
|
|
|
printf("SDP:\n%s\n", sdp); |
|
|
|
@@ -2189,7 +2193,7 @@ static void get_default_channel_layouts(OutputStream *ost, InputStream *ist) |
|
|
|
static int init_input_stream(int ist_index, char *error, int error_len) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
InputStream *ist = &input_streams[ist_index]; |
|
|
|
InputStream *ist = input_streams[ist_index]; |
|
|
|
if (ist->decoding_needed) { |
|
|
|
AVCodec *codec = ist->dec; |
|
|
|
if (!codec) { |
|
|
|
@@ -2201,7 +2205,7 @@ static int init_input_stream(int ist_index, char *error, int error_len) |
|
|
|
/* update requested sample format for the decoder based on the |
|
|
|
corresponding encoder sample format */ |
|
|
|
for (i = 0; i < nb_output_streams; i++) { |
|
|
|
OutputStream *ost = &output_streams[i]; |
|
|
|
OutputStream *ost = output_streams[i]; |
|
|
|
if (ost->source_index == ist_index) { |
|
|
|
update_sample_fmt(ist->st->codec, codec, ost->st->codec); |
|
|
|
break; |
|
|
|
@@ -2226,7 +2230,7 @@ static int init_input_stream(int ist_index, char *error, int error_len) |
|
|
|
|
|
|
|
if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { |
|
|
|
for (i = 0; i < nb_output_streams; i++) { |
|
|
|
OutputStream *ost = &output_streams[i]; |
|
|
|
OutputStream *ost = output_streams[i]; |
|
|
|
if (ost->source_index == ist_index) { |
|
|
|
if (!ist->st->codec->channel_layout || !ost->st->codec->channel_layout) |
|
|
|
get_default_channel_layouts(ost, ist); |
|
|
|
@@ -2256,15 +2260,15 @@ static int transcode_init(void) |
|
|
|
|
|
|
|
/* init framerate emulation */ |
|
|
|
for (i = 0; i < nb_input_files; i++) { |
|
|
|
InputFile *ifile = &input_files[i]; |
|
|
|
InputFile *ifile = input_files[i]; |
|
|
|
if (ifile->rate_emu) |
|
|
|
for (j = 0; j < ifile->nb_streams; j++) |
|
|
|
input_streams[j + ifile->ist_index].start = av_gettime(); |
|
|
|
input_streams[j + ifile->ist_index]->start = av_gettime(); |
|
|
|
} |
|
|
|
|
|
|
|
/* output stream init */ |
|
|
|
for (i = 0; i < nb_output_files; i++) { |
|
|
|
oc = output_files[i].ctx; |
|
|
|
oc = output_files[i]->ctx; |
|
|
|
if (!oc->nb_streams && !(oc->oformat->flags & AVFMT_NOSTREAMS)) { |
|
|
|
av_dump_format(oc, i, oc->filename, 1); |
|
|
|
av_log(NULL, AV_LOG_ERROR, "Output file #%d does not contain any stream\n", i); |
|
|
|
@@ -2274,9 +2278,9 @@ static int transcode_init(void) |
|
|
|
|
|
|
|
/* for each output stream, we compute the right encoding parameters */ |
|
|
|
for (i = 0; i < nb_output_streams; i++) { |
|
|
|
ost = &output_streams[i]; |
|
|
|
oc = output_files[ost->file_index].ctx; |
|
|
|
ist = &input_streams[ost->source_index]; |
|
|
|
ost = output_streams[i]; |
|
|
|
oc = output_files[ost->file_index]->ctx; |
|
|
|
ist = input_streams[ost->source_index]; |
|
|
|
|
|
|
|
if (ost->attachment_filename) |
|
|
|
continue; |
|
|
|
@@ -2495,10 +2499,10 @@ static int transcode_init(void) |
|
|
|
|
|
|
|
/* open each encoder */ |
|
|
|
for (i = 0; i < nb_output_streams; i++) { |
|
|
|
ost = &output_streams[i]; |
|
|
|
ost = output_streams[i]; |
|
|
|
if (ost->encoding_needed) { |
|
|
|
AVCodec *codec = ost->enc; |
|
|
|
AVCodecContext *dec = input_streams[ost->source_index].st->codec; |
|
|
|
AVCodecContext *dec = input_streams[ost->source_index]->st->codec; |
|
|
|
if (!codec) { |
|
|
|
snprintf(error, sizeof(error), "Encoder (codec id %d) not found for output stream #%d:%d", |
|
|
|
ost->st->codec->codec_id, ost->file_index, ost->index); |
|
|
|
@@ -2530,7 +2534,7 @@ static int transcode_init(void) |
|
|
|
extra_size += ost->st->codec->extradata_size; |
|
|
|
|
|
|
|
if (ost->st->codec->me_threshold) |
|
|
|
input_streams[ost->source_index].st->codec->debug |= FF_DEBUG_MV; |
|
|
|
input_streams[ost->source_index]->st->codec->debug |= FF_DEBUG_MV; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@@ -2541,13 +2545,13 @@ static int transcode_init(void) |
|
|
|
|
|
|
|
/* discard unused programs */ |
|
|
|
for (i = 0; i < nb_input_files; i++) { |
|
|
|
InputFile *ifile = &input_files[i]; |
|
|
|
InputFile *ifile = input_files[i]; |
|
|
|
for (j = 0; j < ifile->ctx->nb_programs; j++) { |
|
|
|
AVProgram *p = ifile->ctx->programs[j]; |
|
|
|
int discard = AVDISCARD_ALL; |
|
|
|
|
|
|
|
for (k = 0; k < p->nb_stream_indexes; k++) |
|
|
|
if (!input_streams[ifile->ist_index + p->stream_index[k]].discard) { |
|
|
|
if (!input_streams[ifile->ist_index + p->stream_index[k]]->discard) { |
|
|
|
discard = AVDISCARD_DEFAULT; |
|
|
|
break; |
|
|
|
} |
|
|
|
@@ -2557,14 +2561,14 @@ static int transcode_init(void) |
|
|
|
|
|
|
|
/* open files and write file headers */ |
|
|
|
for (i = 0; i < nb_output_files; i++) { |
|
|
|
oc = output_files[i].ctx; |
|
|
|
oc = output_files[i]->ctx; |
|
|
|
oc->interrupt_callback = int_cb; |
|
|
|
if (avformat_write_header(oc, &output_files[i].opts) < 0) { |
|
|
|
if (avformat_write_header(oc, &output_files[i]->opts) < 0) { |
|
|
|
snprintf(error, sizeof(error), "Could not write header for output file #%d (incorrect codec parameters ?)", i); |
|
|
|
ret = AVERROR(EINVAL); |
|
|
|
goto dump_format; |
|
|
|
} |
|
|
|
assert_avoptions(output_files[i].opts); |
|
|
|
assert_avoptions(output_files[i]->opts); |
|
|
|
if (strcmp(oc->oformat->name, "rtp")) { |
|
|
|
want_sdp = 0; |
|
|
|
} |
|
|
|
@@ -2574,13 +2578,13 @@ static int transcode_init(void) |
|
|
|
/* dump the file output parameters - cannot be done before in case |
|
|
|
of stream copy */ |
|
|
|
for (i = 0; i < nb_output_files; i++) { |
|
|
|
av_dump_format(output_files[i].ctx, i, output_files[i].ctx->filename, 1); |
|
|
|
av_dump_format(output_files[i]->ctx, i, output_files[i]->ctx->filename, 1); |
|
|
|
} |
|
|
|
|
|
|
|
/* dump the stream mapping */ |
|
|
|
av_log(NULL, AV_LOG_INFO, "Stream mapping:\n"); |
|
|
|
for (i = 0; i < nb_output_streams; i++) { |
|
|
|
ost = &output_streams[i]; |
|
|
|
ost = output_streams[i]; |
|
|
|
|
|
|
|
if (ost->attachment_filename) { |
|
|
|
/* an attached file */ |
|
|
|
@@ -2589,19 +2593,19 @@ static int transcode_init(void) |
|
|
|
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, |
|
|
|
input_streams[ost->source_index]->file_index, |
|
|
|
input_streams[ost->source_index]->st->index, |
|
|
|
ost->file_index, |
|
|
|
ost->index); |
|
|
|
if (ost->sync_ist != &input_streams[ost->source_index]) |
|
|
|
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->stream_copy) |
|
|
|
av_log(NULL, AV_LOG_INFO, " (copy)"); |
|
|
|
else |
|
|
|
av_log(NULL, AV_LOG_INFO, " (%s -> %s)", input_streams[ost->source_index].dec ? |
|
|
|
input_streams[ost->source_index].dec->name : "?", |
|
|
|
av_log(NULL, AV_LOG_INFO, " (%s -> %s)", input_streams[ost->source_index]->dec ? |
|
|
|
input_streams[ost->source_index]->dec->name : "?", |
|
|
|
ost->enc ? ost->enc->name : "?"); |
|
|
|
av_log(NULL, AV_LOG_INFO, "\n"); |
|
|
|
} |
|
|
|
@@ -2659,16 +2663,16 @@ static int transcode(void) |
|
|
|
OutputFile *of; |
|
|
|
int64_t ipts; |
|
|
|
double opts; |
|
|
|
ost = &output_streams[i]; |
|
|
|
of = &output_files[ost->file_index]; |
|
|
|
os = output_files[ost->file_index].ctx; |
|
|
|
ist = &input_streams[ost->source_index]; |
|
|
|
ost = output_streams[i]; |
|
|
|
of = output_files[ost->file_index]; |
|
|
|
os = output_files[ost->file_index]->ctx; |
|
|
|
ist = input_streams[ost->source_index]; |
|
|
|
if (ost->is_past_recording_time || no_packet[ist->file_index] || |
|
|
|
(os->pb && avio_tell(os->pb) >= of->limit_filesize)) |
|
|
|
continue; |
|
|
|
opts = ost->st->pts.val * av_q2d(ost->st->time_base); |
|
|
|
ipts = ist->last_dts; |
|
|
|
if (!input_files[ist->file_index].eof_reached) { |
|
|
|
if (!input_files[ist->file_index]->eof_reached) { |
|
|
|
if (ipts < ipts_min) { |
|
|
|
ipts_min = ipts; |
|
|
|
if (input_sync) |
|
|
|
@@ -2682,7 +2686,7 @@ static int transcode(void) |
|
|
|
if (ost->frame_number >= ost->max_frames) { |
|
|
|
int j; |
|
|
|
for (j = 0; j < of->ctx->nb_streams; j++) |
|
|
|
output_streams[of->ost_index + j].is_past_recording_time = 1; |
|
|
|
output_streams[of->ost_index + j]->is_past_recording_time = 1; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
@@ -2698,7 +2702,7 @@ static int transcode(void) |
|
|
|
} |
|
|
|
|
|
|
|
/* read a frame from it and output it in the fifo */ |
|
|
|
is = input_files[file_index].ctx; |
|
|
|
is = input_files[file_index]->ctx; |
|
|
|
ret = av_read_frame(is, &pkt); |
|
|
|
if (ret == AVERROR(EAGAIN)) { |
|
|
|
no_packet[file_index] = 1; |
|
|
|
@@ -2706,7 +2710,7 @@ static int transcode(void) |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (ret < 0) { |
|
|
|
input_files[file_index].eof_reached = 1; |
|
|
|
input_files[file_index]->eof_reached = 1; |
|
|
|
if (opt_shortest) |
|
|
|
break; |
|
|
|
else |
|
|
|
@@ -2722,17 +2726,17 @@ static int transcode(void) |
|
|
|
} |
|
|
|
/* the following test is needed in case new streams appear |
|
|
|
dynamically in stream : we ignore them */ |
|
|
|
if (pkt.stream_index >= input_files[file_index].nb_streams) |
|
|
|
if (pkt.stream_index >= input_files[file_index]->nb_streams) |
|
|
|
goto discard_packet; |
|
|
|
ist_index = input_files[file_index].ist_index + pkt.stream_index; |
|
|
|
ist = &input_streams[ist_index]; |
|
|
|
ist_index = input_files[file_index]->ist_index + pkt.stream_index; |
|
|
|
ist = input_streams[ist_index]; |
|
|
|
if (ist->discard) |
|
|
|
goto discard_packet; |
|
|
|
|
|
|
|
if (pkt.dts != AV_NOPTS_VALUE) |
|
|
|
pkt.dts += av_rescale_q(input_files[ist->file_index].ts_offset, AV_TIME_BASE_Q, ist->st->time_base); |
|
|
|
pkt.dts += av_rescale_q(input_files[ist->file_index]->ts_offset, AV_TIME_BASE_Q, ist->st->time_base); |
|
|
|
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); |
|
|
|
pkt.pts += av_rescale_q(input_files[ist->file_index]->ts_offset, AV_TIME_BASE_Q, ist->st->time_base); |
|
|
|
|
|
|
|
if (pkt.pts != AV_NOPTS_VALUE) |
|
|
|
pkt.pts *= ist->ts_scale; |
|
|
|
@@ -2748,10 +2752,10 @@ static int transcode(void) |
|
|
|
int64_t pkt_dts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q); |
|
|
|
int64_t delta = pkt_dts - ist->next_dts; |
|
|
|
if ((FFABS(delta) > 1LL * dts_delta_threshold * AV_TIME_BASE || pkt_dts + 1 < ist->last_dts) && !copy_ts) { |
|
|
|
input_files[ist->file_index].ts_offset -= delta; |
|
|
|
input_files[ist->file_index]->ts_offset -= delta; |
|
|
|
av_log(NULL, AV_LOG_DEBUG, |
|
|
|
"timestamp discontinuity %"PRId64", new offset= %"PRId64"\n", |
|
|
|
delta, input_files[ist->file_index].ts_offset); |
|
|
|
delta, input_files[ist->file_index]->ts_offset); |
|
|
|
pkt.dts-= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base); |
|
|
|
if (pkt.pts != AV_NOPTS_VALUE) |
|
|
|
pkt.pts-= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base); |
|
|
|
@@ -2778,7 +2782,7 @@ static int transcode(void) |
|
|
|
|
|
|
|
/* at the end of stream, we must flush the decoder buffers */ |
|
|
|
for (i = 0; i < nb_input_streams; i++) { |
|
|
|
ist = &input_streams[i]; |
|
|
|
ist = input_streams[i]; |
|
|
|
if (ist->decoding_needed) { |
|
|
|
output_packet(ist, NULL); |
|
|
|
} |
|
|
|
@@ -2789,7 +2793,7 @@ static int transcode(void) |
|
|
|
|
|
|
|
/* write the trailer if needed and close file */ |
|
|
|
for (i = 0; i < nb_output_files; i++) { |
|
|
|
os = output_files[i].ctx; |
|
|
|
os = output_files[i]->ctx; |
|
|
|
av_write_trailer(os); |
|
|
|
} |
|
|
|
|
|
|
|
@@ -2798,7 +2802,7 @@ static int transcode(void) |
|
|
|
|
|
|
|
/* close each encoder */ |
|
|
|
for (i = 0; i < nb_output_streams; i++) { |
|
|
|
ost = &output_streams[i]; |
|
|
|
ost = output_streams[i]; |
|
|
|
if (ost->encoding_needed) { |
|
|
|
av_freep(&ost->st->codec->stats_in); |
|
|
|
avcodec_close(ost->st->codec); |
|
|
|
@@ -2808,7 +2812,7 @@ static int transcode(void) |
|
|
|
|
|
|
|
/* close each decoder */ |
|
|
|
for (i = 0; i < nb_input_streams; i++) { |
|
|
|
ist = &input_streams[i]; |
|
|
|
ist = input_streams[i]; |
|
|
|
if (ist->decoding_needed) { |
|
|
|
avcodec_close(ist->st->codec); |
|
|
|
} |
|
|
|
@@ -2822,7 +2826,7 @@ static int transcode(void) |
|
|
|
|
|
|
|
if (output_streams) { |
|
|
|
for (i = 0; i < nb_output_streams; i++) { |
|
|
|
ost = &output_streams[i]; |
|
|
|
ost = output_streams[i]; |
|
|
|
if (ost) { |
|
|
|
if (ost->stream_copy) |
|
|
|
av_freep(&ost->st->codec->extradata); |
|
|
|
@@ -2913,13 +2917,13 @@ static int opt_map(OptionsContext *o, const char *opt, const char *arg) |
|
|
|
} |
|
|
|
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) { |
|
|
|
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) { |
|
|
|
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); |
|
|
|
exit_program(1); |
|
|
|
@@ -2937,14 +2941,14 @@ static int opt_map(OptionsContext *o, const char *opt, const char *arg) |
|
|
|
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], |
|
|
|
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], |
|
|
|
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; |
|
|
|
o->stream_maps = grow_array(o->stream_maps, sizeof(*o->stream_maps), |
|
|
|
@@ -3129,10 +3133,14 @@ 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; |
|
|
|
InputStream *ist = av_mallocz(sizeof(*ist)); |
|
|
|
|
|
|
|
if (!ist) |
|
|
|
exit_program(1); |
|
|
|
|
|
|
|
input_streams = grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, nb_input_streams + 1); |
|
|
|
ist = &input_streams[nb_input_streams - 1]; |
|
|
|
input_streams[nb_input_streams - 1] = ist; |
|
|
|
|
|
|
|
ist->st = st; |
|
|
|
ist->file_index = nb_input_files; |
|
|
|
ist->discard = 1; |
|
|
|
@@ -3314,11 +3322,14 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena |
|
|
|
av_dump_format(ic, nb_input_files, filename, 0); |
|
|
|
|
|
|
|
input_files = grow_array(input_files, sizeof(*input_files), &nb_input_files, nb_input_files + 1); |
|
|
|
input_files[nb_input_files - 1].ctx = ic; |
|
|
|
input_files[nb_input_files - 1].ist_index = nb_input_streams - ic->nb_streams; |
|
|
|
input_files[nb_input_files - 1].ts_offset = o->input_ts_offset - (copy_ts ? 0 : timestamp); |
|
|
|
input_files[nb_input_files - 1].nb_streams = ic->nb_streams; |
|
|
|
input_files[nb_input_files - 1].rate_emu = o->rate_emu; |
|
|
|
if (!(input_files[nb_input_files - 1] = av_mallocz(sizeof(*input_files[0])))) |
|
|
|
exit_program(1); |
|
|
|
|
|
|
|
input_files[nb_input_files - 1]->ctx = ic; |
|
|
|
input_files[nb_input_files - 1]->ist_index = nb_input_streams - ic->nb_streams; |
|
|
|
input_files[nb_input_files - 1]->ts_offset = o->input_ts_offset - (copy_ts ? 0 : timestamp); |
|
|
|
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; |
|
|
|
@@ -3445,7 +3456,10 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e |
|
|
|
|
|
|
|
output_streams = grow_array(output_streams, sizeof(*output_streams), &nb_output_streams, |
|
|
|
nb_output_streams + 1); |
|
|
|
ost = &output_streams[nb_output_streams - 1]; |
|
|
|
if (!(ost = av_mallocz(sizeof(*ost)))) |
|
|
|
exit_program(1); |
|
|
|
output_streams[nb_output_streams - 1] = ost; |
|
|
|
|
|
|
|
ost->file_index = nb_output_files; |
|
|
|
ost->index = idx; |
|
|
|
ost->st = st; |
|
|
|
@@ -3825,16 +3839,16 @@ static void opt_output_file(void *optctx, const char *filename) |
|
|
|
if (index >= 0) {\ |
|
|
|
ost = new_ ## type ## _stream(o, oc);\ |
|
|
|
ost->source_index = index;\ |
|
|
|
ost->sync_ist = &input_streams[index];\ |
|
|
|
input_streams[index].discard = 0;\ |
|
|
|
input_streams[index].st->discard = AVDISCARD_NONE;\ |
|
|
|
ost->sync_ist = input_streams[index];\ |
|
|
|
input_streams[index]->discard = 0;\ |
|
|
|
input_streams[index]->st->discard = AVDISCARD_NONE;\ |
|
|
|
} |
|
|
|
|
|
|
|
/* video: highest resolution */ |
|
|
|
if (!o->video_disable && oc->oformat->video_codec != CODEC_ID_NONE) { |
|
|
|
int area = 0, idx = -1; |
|
|
|
for (i = 0; i < nb_input_streams; i++) { |
|
|
|
ist = &input_streams[i]; |
|
|
|
ist = input_streams[i]; |
|
|
|
if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && |
|
|
|
ist->st->codec->width * ist->st->codec->height > area) { |
|
|
|
area = ist->st->codec->width * ist->st->codec->height; |
|
|
|
@@ -3848,7 +3862,7 @@ static void opt_output_file(void *optctx, const char *filename) |
|
|
|
if (!o->audio_disable && oc->oformat->audio_codec != CODEC_ID_NONE) { |
|
|
|
int channels = 0, idx = -1; |
|
|
|
for (i = 0; i < nb_input_streams; i++) { |
|
|
|
ist = &input_streams[i]; |
|
|
|
ist = input_streams[i]; |
|
|
|
if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && |
|
|
|
ist->st->codec->channels > channels) { |
|
|
|
channels = ist->st->codec->channels; |
|
|
|
@@ -3861,7 +3875,7 @@ static void opt_output_file(void *optctx, const char *filename) |
|
|
|
/* subtitles: pick first */ |
|
|
|
if (!o->subtitle_disable && oc->oformat->subtitle_codec != CODEC_ID_NONE) { |
|
|
|
for (i = 0; i < nb_input_streams; i++) |
|
|
|
if (input_streams[i].st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { |
|
|
|
if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { |
|
|
|
NEW_STREAM(subtitle, i); |
|
|
|
break; |
|
|
|
} |
|
|
|
@@ -3874,7 +3888,7 @@ static void opt_output_file(void *optctx, const char *filename) |
|
|
|
if (map->disabled) |
|
|
|
continue; |
|
|
|
|
|
|
|
ist = &input_streams[input_files[map->file_index].ist_index + map->stream_index]; |
|
|
|
ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index]; |
|
|
|
switch (ist->st->codec->codec_type) { |
|
|
|
case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc); break; |
|
|
|
case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc); break; |
|
|
|
@@ -3887,8 +3901,8 @@ static void opt_output_file(void *optctx, const char *filename) |
|
|
|
exit_program(1); |
|
|
|
} |
|
|
|
|
|
|
|
ost->source_index = input_files[map->file_index].ist_index + map->stream_index; |
|
|
|
ost->sync_ist = &input_streams[input_files[map->sync_file_index].ist_index + |
|
|
|
ost->source_index = input_files[map->file_index]->ist_index + map->stream_index; |
|
|
|
ost->sync_ist = input_streams[input_files[map->sync_file_index]->ist_index + |
|
|
|
map->sync_stream_index]; |
|
|
|
ist->discard = 0; |
|
|
|
ist->st->discard = AVDISCARD_NONE; |
|
|
|
@@ -3932,14 +3946,17 @@ static void opt_output_file(void *optctx, const char *filename) |
|
|
|
} |
|
|
|
|
|
|
|
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; |
|
|
|
output_files[nb_output_files - 1].recording_time = o->recording_time; |
|
|
|
if (!(output_files[nb_output_files - 1] = av_mallocz(sizeof(*output_files[0])))) |
|
|
|
exit_program(1); |
|
|
|
|
|
|
|
output_files[nb_output_files - 1]->ctx = oc; |
|
|
|
output_files[nb_output_files - 1]->ost_index = nb_output_streams - oc->nb_streams; |
|
|
|
output_files[nb_output_files - 1]->recording_time = o->recording_time; |
|
|
|
if (o->recording_time != INT64_MAX) |
|
|
|
oc->duration = o->recording_time; |
|
|
|
output_files[nb_output_files - 1].start_time = o->start_time; |
|
|
|
output_files[nb_output_files - 1].limit_filesize = o->limit_filesize; |
|
|
|
av_dict_copy(&output_files[nb_output_files - 1].opts, format_opts, 0); |
|
|
|
output_files[nb_output_files - 1]->start_time = o->start_time; |
|
|
|
output_files[nb_output_files - 1]->limit_filesize = o->limit_filesize; |
|
|
|
av_dict_copy(&output_files[nb_output_files - 1]->opts, format_opts, 0); |
|
|
|
|
|
|
|
/* check filename in case of an image number is expected */ |
|
|
|
if (oc->oformat->flags & AVFMT_NEEDNUMBER) { |
|
|
|
@@ -3956,7 +3973,7 @@ static void opt_output_file(void *optctx, const char *filename) |
|
|
|
/* open the file */ |
|
|
|
if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, |
|
|
|
&oc->interrupt_callback, |
|
|
|
&output_files[nb_output_files - 1].opts)) < 0) { |
|
|
|
&output_files[nb_output_files - 1]->opts)) < 0) { |
|
|
|
print_error(filename, err); |
|
|
|
exit_program(1); |
|
|
|
} |
|
|
|
@@ -3965,7 +3982,7 @@ static void opt_output_file(void *optctx, const char *filename) |
|
|
|
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); |
|
|
|
av_dict_set(&output_files[nb_output_files - 1]->opts, "preload", buf, 0); |
|
|
|
} |
|
|
|
oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE); |
|
|
|
oc->flags |= AVFMT_FLAG_NONBLOCK; |
|
|
|
@@ -3981,7 +3998,7 @@ static void opt_output_file(void *optctx, const char *filename) |
|
|
|
av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index); |
|
|
|
exit_program(1); |
|
|
|
} |
|
|
|
copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc, input_files[in_file_index].ctx, o); |
|
|
|
copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc, input_files[in_file_index]->ctx, o); |
|
|
|
} |
|
|
|
|
|
|
|
/* copy chapters */ |
|
|
|
@@ -3990,7 +4007,7 @@ static void opt_output_file(void *optctx, const char *filename) |
|
|
|
/* copy chapters from the first input file that has them*/ |
|
|
|
o->chapters_input_file = -1; |
|
|
|
for (i = 0; i < nb_input_files; i++) |
|
|
|
if (input_files[i].ctx->nb_chapters) { |
|
|
|
if (input_files[i]->ctx->nb_chapters) { |
|
|
|
o->chapters_input_file = i; |
|
|
|
break; |
|
|
|
} |
|
|
|
@@ -4001,20 +4018,20 @@ static void opt_output_file(void *optctx, const char *filename) |
|
|
|
} |
|
|
|
} |
|
|
|
if (o->chapters_input_file >= 0) |
|
|
|
copy_chapters(&input_files[o->chapters_input_file], &output_files[nb_output_files - 1], |
|
|
|
copy_chapters(input_files[o->chapters_input_file], output_files[nb_output_files - 1], |
|
|
|
!o->metadata_chapters_manual); |
|
|
|
|
|
|
|
/* copy global metadata by default */ |
|
|
|
if (!o->metadata_global_manual && nb_input_files) |
|
|
|
av_dict_copy(&oc->metadata, input_files[0].ctx->metadata, |
|
|
|
av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata, |
|
|
|
AV_DICT_DONT_OVERWRITE); |
|
|
|
if (!o->metadata_streams_manual) |
|
|
|
for (i = output_files[nb_output_files - 1].ost_index; i < nb_output_streams; i++) { |
|
|
|
for (i = output_files[nb_output_files - 1]->ost_index; i < nb_output_streams; i++) { |
|
|
|
InputStream *ist; |
|
|
|
if (output_streams[i].source_index < 0) /* this is true e.g. for attached files */ |
|
|
|
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); |
|
|
|
ist = input_streams[output_streams[i]->source_index]; |
|
|
|
av_dict_copy(&output_streams[i]->st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE); |
|
|
|
} |
|
|
|
|
|
|
|
/* process manually set metadata */ |
|
|
|
@@ -4173,8 +4190,8 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg) |
|
|
|
if (nb_input_files) { |
|
|
|
int i, j, fr; |
|
|
|
for (j = 0; j < nb_input_files; j++) { |
|
|
|
for (i = 0; i < input_files[j].nb_streams; i++) { |
|
|
|
AVCodecContext *c = input_files[j].ctx->streams[i]->codec; |
|
|
|
for (i = 0; i < input_files[j]->nb_streams; i++) { |
|
|
|
AVCodecContext *c = input_files[j]->ctx->streams[i]->codec; |
|
|
|
if (c->codec_type != AVMEDIA_TYPE_VIDEO) |
|
|
|
continue; |
|
|
|
fr = c->time_base.den * 1000 / c->time_base.num; |
|
|
|
|