int ofile_idx, ostream_idx; // output
} AudioChannelMap;
-static const OptionDef options[];
+static const OptionDef *options;
#define MAX_STREAMS 1024 /* arbitrary sanity check value */
int64_t start; /* time when read started */
/* predicted dts of the next packet read for this stream or (when there are
- * several frames in a packet) of the next frame in current packet */
+ * several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */
int64_t next_dts;
- /* dts of the last packet read for this stream */
- int64_t dts;
+ int64_t dts; ///< dts of the last packet read for this stream (in AV_TIME_BASE units)
- int64_t next_pts; /* synthetic pts for the next decode frame */
- int64_t pts; /* current pts of the decoded frame */
+ int64_t next_pts; ///< synthetic pts for the next decode frame (in AV_TIME_BASE units)
+ int64_t pts; ///< current pts of the decoded frame (in AV_TIME_BASE units)
+ int wrap_correction_done;
double ts_scale;
int is_start; /* is 1 at the start and after a discontinuity */
int saw_first_ts;
typedef struct InputFile {
AVFormatContext *ctx;
int eof_reached; /* true if eof reached */
+ int unavailable; /* true if the file is unavailable (possibly temporarily) */
int ist_index; /* index of first stream in input_streams */
int64_t ts_offset;
int nb_streams; /* number of stream that ffmpeg is aware of; may be different
from ctx.nb_streams if new streams appear during av_read_frame() */
+ int nb_streams_warn; /* number of streams that the user was warned of */
int rate_emu;
#if HAVE_PTHREADS
double swr_dither_scale;
AVDictionary *opts;
int is_past_recording_time;
+ int unavailable; /* true if the steram is unavailable (possibly temporarily) */
int stream_copy;
const char *attachment_filename;
int copy_initial_nonkeyframes;
AVFormatContext *ctx;
AVDictionary *opts;
int ost_index; /* index of the first stream in output_streams */
- int64_t recording_time; /* desired length of the resulting file in microseconds */
- int64_t start_time; /* start time in microseconds */
+ int64_t recording_time; ///< desired length of the resulting file in microseconds == AV_TIME_BASE units
+ int64_t start_time; ///< start time in microseconds == AV_TIME_BASE units
uint64_t limit_filesize; /* filesize limit expressed in bytes */
} OutputFile;
else
nb = 1;
+ /* shift timestamp to honor -ss and make check_recording_time() work with -t */
+ pts = av_rescale_q(pts, ist->st->time_base, AV_TIME_BASE_Q)
+ - output_files[ost->file_index]->start_time;
for (i = 0; i < nb; i++) {
- ost->sync_opts = av_rescale_q(pts, ist->st->time_base, enc->time_base);
+ ost->sync_opts = av_rescale_q(pts, AV_TIME_BASE_Q, enc->time_base);
if (!check_recording_time(ost))
return;
- sub->pts = av_rescale_q(pts, ist->st->time_base, AV_TIME_BASE_Q);
+ sub->pts = pts;
// start_display_time is required to be 0
sub->pts += av_rescale_q(sub->start_display_time, (AVRational){ 1, 1000 }, AV_TIME_BASE_Q);
sub->end_display_time -= sub->start_display_time;
opkt.data = pkt->data;
opkt.size = pkt->size;
}
- if (of->ctx->oformat->flags & AVFMT_RAWPICTURE) {
+
+ if (ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && (of->ctx->oformat->flags & AVFMT_RAWPICTURE)) {
/* store AVPicture in AVPacket, as expected by the output format */
avpicture_fill(&pict, opkt.data, ost->st->codec->pix_fmt, ost->st->codec->width, ost->st->codec->height);
opkt.data = (uint8_t *)&pict;
AVFrame *decoded_frame;
AVCodecContext *avctx = ist->st->codec;
int i, ret, resample_changed;
+ AVRational decoded_frame_tb;
if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame()))
return AVERROR(ENOMEM);
return ret;
}
- /* if the decoder provides a pts, use it instead of the last packet pts.
- the decoder could be delaying output by a packet or more. */
- if (decoded_frame->pts != AV_NOPTS_VALUE)
- ist->dts = ist->next_dts = ist->pts = ist->next_pts = decoded_frame->pts;
- else if (decoded_frame->pkt_pts != AV_NOPTS_VALUE) {
- decoded_frame->pts = decoded_frame->pkt_pts;
- pkt->pts = AV_NOPTS_VALUE;
- } else if (pkt->pts != AV_NOPTS_VALUE) {
- decoded_frame->pts = pkt->pts;
- pkt->pts = AV_NOPTS_VALUE;
- }else
- decoded_frame->pts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base);
-
-
#if 1
/* increment next_dts to use for the case where the input stream does not
have timestamps or there are multiple frames in the packet */
}
}
+ /* if the decoder provides a pts, use it instead of the last packet pts.
+ the decoder could be delaying output by a packet or more. */
+ if (decoded_frame->pts != AV_NOPTS_VALUE) {
+ ist->dts = ist->next_dts = ist->pts = ist->next_pts = av_rescale_q(decoded_frame->pts, avctx->time_base, AV_TIME_BASE_Q);
+ decoded_frame_tb = avctx->time_base;
+ } else if (decoded_frame->pkt_pts != AV_NOPTS_VALUE) {
+ decoded_frame->pts = decoded_frame->pkt_pts;
+ pkt->pts = AV_NOPTS_VALUE;
+ decoded_frame_tb = ist->st->time_base;
+ } else if (pkt->pts != AV_NOPTS_VALUE) {
+ decoded_frame->pts = pkt->pts;
+ pkt->pts = AV_NOPTS_VALUE;
+ decoded_frame_tb = ist->st->time_base;
+ }else {
+ decoded_frame->pts = ist->dts;
+ decoded_frame_tb = AV_TIME_BASE_Q;
+ }
if (decoded_frame->pts != AV_NOPTS_VALUE)
decoded_frame->pts = av_rescale_q(decoded_frame->pts,
- ist->st->time_base,
+ decoded_frame_tb,
(AVRational){1, ist->st->codec->sample_rate});
for (i = 0; i < ist->nb_filters; i++)
av_buffersrc_add_frame(ist->filters[i]->filter, decoded_frame, 0);
+ decoded_frame->pts = AV_NOPTS_VALUE;
+
return ret;
}
}
}
+static void report_new_stream(int input_index, AVPacket *pkt)
+{
+ InputFile *file = input_files[input_index];
+ AVStream *st = file->ctx->streams[pkt->stream_index];
+
+ if (pkt->stream_index < file->nb_streams_warn)
+ return;
+ av_log(file->ctx, AV_LOG_WARNING,
+ "New %s stream %d:%d at pos:%"PRId64" and DTS:%ss\n",
+ av_get_media_type_string(st->codec->codec_type),
+ input_index, pkt->stream_index,
+ pkt->pos, av_ts2timestr(pkt->dts, &st->time_base));
+ file->nb_streams_warn = pkt->stream_index + 1;
+}
+
static int transcode_init(void)
{
int ret = 0, i, j, k;
* overhead
*/
if(!strcmp(oc->oformat->name, "avi")) {
- if ( copy_tb<0 && av_q2d(icodec->time_base)*icodec->ticks_per_frame > 2*av_q2d(ist->st->time_base)
+ if ( copy_tb<0 && av_q2d(ist->st->r_frame_rate) >= av_q2d(ist->st->avg_frame_rate)
+ && 0.5/av_q2d(ist->st->r_frame_rate) > av_q2d(ist->st->time_base)
+ && 0.5/av_q2d(ist->st->r_frame_rate) > av_q2d(icodec->time_base)
+ && av_q2d(ist->st->time_base) < 1.0/500 && av_q2d(icodec->time_base) < 1.0/500
+ || copy_tb==2){
+ codec->time_base.num = ist->st->r_frame_rate.den;
+ codec->time_base.den = 2*ist->st->r_frame_rate.num;
+ codec->ticks_per_frame = 2;
+ } else if ( copy_tb<0 && av_q2d(icodec->time_base)*icodec->ticks_per_frame > 2*av_q2d(ist->st->time_base)
&& av_q2d(ist->st->time_base) < 1.0/500
|| copy_tb==0){
codec->time_base = icodec->time_base;
ist->decoding_needed = 1;
ost->encoding_needed = 1;
- if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
- if (ost->filter && !ost->frame_rate.num)
- ost->frame_rate = av_buffersink_get_frame_rate(ost->filter->filter);
- if (ist && !ost->frame_rate.num)
- ost->frame_rate = ist->st->r_frame_rate.num ? ist->st->r_frame_rate : (AVRational){25, 1};
- if (ost->enc && ost->enc->supported_framerates && !ost->force_fps) {
- int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates);
- ost->frame_rate = ost->enc->supported_framerates[idx];
- }
- }
-
if (!ost->filter &&
(codec->codec_type == AVMEDIA_TYPE_VIDEO ||
codec->codec_type == AVMEDIA_TYPE_AUDIO)) {
}
}
+ if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (ost->filter && !ost->frame_rate.num)
+ ost->frame_rate = av_buffersink_get_frame_rate(ost->filter->filter);
+ if (ist && !ost->frame_rate.num)
+ ost->frame_rate = ist->st->r_frame_rate.num ? ist->st->r_frame_rate : (AVRational){25, 1};
+// ost->frame_rate = ist->st->avg_frame_rate.num ? ist->st->avg_frame_rate : (AVRational){25, 1};
+ if (ost->enc && ost->enc->supported_framerates && !ost->force_fps) {
+ int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates);
+ ost->frame_rate = ost->enc->supported_framerates[idx];
+ }
+ }
+
switch (codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
codec->sample_fmt = ost->filter->filter->inputs[0]->format;
return 0;
}
-static int select_input_file(uint8_t *no_packet)
+static int input_acceptable(InputStream *ist)
{
- int64_t ipts_min = INT64_MAX;
- int i, file_index = -1;
-
- for (i = 0; i < nb_input_streams; i++) {
- InputStream *ist = input_streams[i];
- int64_t ipts = ist->pts;
+ av_assert1(!ist->discard);
+ return !input_files[ist->file_index]->unavailable &&
+ !input_files[ist->file_index]->eof_reached;
+}
- if (ist->discard || no_packet[ist->file_index])
- continue;
- if (!input_files[ist->file_index]->eof_reached) {
- if (ipts < ipts_min) {
- ipts_min = ipts;
+static int find_graph_input(FilterGraph *graph)
+{
+ int i, nb_req_max = 0, file_index = -1;
+
+ for (i = 0; i < graph->nb_inputs; i++) {
+ int nb_req = av_buffersrc_get_nb_failed_requests(graph->inputs[i]->filter);
+ if (nb_req > nb_req_max) {
+ InputStream *ist = graph->inputs[i]->ist;
+ if (input_acceptable(ist)) {
+ nb_req_max = nb_req;
file_index = ist->file_index;
}
}
return file_index;
}
+/**
+ * Select the input file to read from.
+ *
+ * @return >=0 index of the input file to use;
+ * -1 if no file is acceptable;
+ * -2 to read from filters without reading from a file
+ */
+static int select_input_file(void)
+{
+ int i, ret, nb_active_out = nb_output_streams, ost_index = -1;
+ int64_t opts_min;
+ OutputStream *ost;
+ AVFilterBufferRef *dummy;
+
+ for (i = 0; i < nb_output_streams; i++)
+ nb_active_out -= output_streams[i]->unavailable =
+ output_streams[i]->is_past_recording_time;
+ while (nb_active_out) {
+ opts_min = INT64_MAX;
+ ost_index = -1;
+ for (i = 0; i < nb_output_streams; i++) {
+ OutputStream *ost = output_streams[i];
+ int64_t opts = av_rescale_q(ost->st->cur_dts, ost->st->time_base,
+ AV_TIME_BASE_Q);
+ if (!ost->unavailable && opts < opts_min) {
+ opts_min = opts;
+ ost_index = i;
+ }
+ }
+ if (ost_index < 0)
+ return -1;
+
+ ost = output_streams[ost_index];
+ if (ost->source_index >= 0) {
+ /* ost is directly connected to an input */
+ InputStream *ist = input_streams[ost->source_index];
+ if (input_acceptable(ist))
+ return ist->file_index;
+ } else {
+ /* ost is connected to a complex filtergraph */
+ av_assert1(ost->filter);
+ ret = av_buffersink_get_buffer_ref(ost->filter->filter, &dummy,
+ AV_BUFFERSINK_FLAG_PEEK);
+ if (ret >= 0)
+ return -2;
+ ret = find_graph_input(ost->filter->graph);
+ if (ret >= 0)
+ return ret;
+ }
+ ost->unavailable = 1;
+ nb_active_out--;
+ }
+ return -1;
+}
+
static int check_keyboard_interaction(int64_t cur_time)
{
int i, ret, key;
AVFormatContext *is, *os;
OutputStream *ost;
InputStream *ist;
- uint8_t *no_packet;
int no_packet_count = 0;
int64_t timer_start;
- if (!(no_packet = av_mallocz(nb_input_files)))
- exit_program(1);
-
ret = transcode_init();
if (ret < 0)
goto fail;
}
/* select the stream that we must read now */
- file_index = select_input_file(no_packet);
+ file_index = select_input_file();
/* if none, if is finished */
+ if (file_index == -2) {
+ poll_filters() ;
+ continue;
+ }
if (file_index < 0) {
if (no_packet_count) {
no_packet_count = 0;
- memset(no_packet, 0, nb_input_files);
+ for (i = 0; i < nb_input_files; i++)
+ input_files[i]->unavailable = 0;
av_usleep(10000);
continue;
}
ret = get_input_packet(input_files[file_index], &pkt);
if (ret == AVERROR(EAGAIN)) {
- no_packet[file_index] = 1;
+ input_files[file_index]->unavailable = 1;
no_packet_count++;
continue;
}
ist = input_streams[input_files[file_index]->ist_index + i];
if (ist->decoding_needed)
output_packet(ist, NULL);
+ poll_filters();
}
if (opt_shortest)
}
no_packet_count = 0;
- memset(no_packet, 0, nb_input_files);
+ for (i = 0; i < nb_input_files; i++)
+ input_files[i]->unavailable = 0;
if (do_pkt_dump) {
av_pkt_dump_log2(NULL, AV_LOG_DEBUG, &pkt, do_hex_dump,
}
/* 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) {
+ report_new_stream(file_index, &pkt);
goto discard_packet;
+ }
ist_index = input_files[file_index]->ist_index + pkt.stream_index;
ist = input_streams[ist_index];
if (ist->discard)
goto discard_packet;
+ if(!ist->wrap_correction_done && input_files[file_index]->ctx->start_time != AV_NOPTS_VALUE && ist->st->pts_wrap_bits < 64){
+ uint64_t stime = av_rescale_q(input_files[file_index]->ctx->start_time, AV_TIME_BASE_Q, ist->st->time_base);
+ uint64_t stime2= stime + (1LL<<ist->st->pts_wrap_bits);
+ ist->wrap_correction_done = 1;
+ if(pkt.dts != AV_NOPTS_VALUE && pkt.dts > stime && pkt.dts - stime > stime2 - pkt.dts) {
+ pkt.dts -= 1LL<<ist->st->pts_wrap_bits;
+ ist->wrap_correction_done = 0;
+ }
+ if(pkt.pts != AV_NOPTS_VALUE && pkt.pts > stime && pkt.pts - stime > stime2 - pkt.pts) {
+ pkt.pts -= 1LL<<ist->st->pts_wrap_bits;
+ ist->wrap_correction_done = 0;
+ }
+ }
+
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);
if (pkt.pts != AV_NOPTS_VALUE)
av_log(NULL, AV_LOG_INFO, "demuxer -> ist_index:%d type:%s "
"next_dts:%s next_dts_time:%s next_pts:%s next_pts_time:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%"PRId64"\n",
ist_index, av_get_media_type_string(ist->st->codec->codec_type),
- av_ts2str(ist->next_dts), av_ts2timestr(ist->next_dts, &ist->st->time_base),
- av_ts2str(ist->next_pts), av_ts2timestr(ist->next_pts, &ist->st->time_base),
+ av_ts2str(ist->next_dts), av_ts2timestr(ist->next_dts, &AV_TIME_BASE_Q),
+ av_ts2str(ist->next_pts), av_ts2timestr(ist->next_pts, &AV_TIME_BASE_Q),
av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ist->st->time_base),
av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ist->st->time_base),
input_files[ist->file_index]->ts_offset);
ret = 0;
fail:
- av_freep(&no_packet);
#if HAVE_PTHREADS
free_input_threads();
#endif
}
#define OFFSET(x) offsetof(OptionsContext, x)
-static const OptionDef options[] = {
+static const OptionDef real_options[] = {
/* main options */
#include "cmdutils_common_opts.h"
{ "f", HAS_ARG | OPT_STRING | OPT_OFFSET, {.off = OFFSET(format)}, "force format", "fmt" },
OptionsContext o = { 0 };
int64_t ti;
+ options = real_options;
reset_options(&o, 0);
av_log_set_flags(AV_LOG_SKIP_REPEATED);