Signed-off-by: Marton Balint <c...@passwd.hu> --- doc/demuxers.texi | 13 +++++++++++++ libavformat/concatdec.c | 22 ++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/doc/demuxers.texi b/doc/demuxers.texi index 4bad1c8..4ba797e 100644 --- a/doc/demuxers.texi +++ b/doc/demuxers.texi @@ -129,6 +129,19 @@ directive) will be reduced based on their specified In point. Because of potential packets before the specified In point, packet timestamps may overlap between two concatenated files. +@item @code{out @var{timestamp}} +Out point of the file. When the demuxer reaches the specified timestamp in any +of the streams, it handles it as an end of file condition. Out point is +exclusive, which means that the demuxer will not output packets which has a +timestamp greater or equal to Out point. + +This directive works best with intra frame codecs, because for non-intra frame +ones you will usually not get enough packets to decode the last few frames +before the specified Out point. + +The duration of the files (if not specified by the @code{duration} +directive) will be reduced based on their specified Out point. + @item @code{stream} Introduce a stream in the virtual file. All subsequent stream-related directives apply to the last introduced diff --git a/libavformat/concatdec.c b/libavformat/concatdec.c index 11e6759..eaf34b0 100644 --- a/libavformat/concatdec.c +++ b/libavformat/concatdec.c @@ -44,6 +44,7 @@ typedef struct { int64_t duration; ConcatStream *streams; int64_t inpoint; + int64_t outpoint; int nb_streams; } ConcatFile; @@ -145,6 +146,7 @@ static int add_file(AVFormatContext *avf, char *filename, ConcatFile **rfile, file->start_time = AV_NOPTS_VALUE; file->duration = AV_NOPTS_VALUE; file->inpoint = AV_NOPTS_VALUE; + file->outpoint = AV_NOPTS_VALUE; return 0; @@ -360,7 +362,7 @@ static int concat_read_header(AVFormatContext *avf) } if ((ret = add_file(avf, filename, &file, &nb_files_alloc)) < 0) goto fail; - } else if (!strcmp(keyword, "duration") || !strcmp(keyword, "in")) { + } else if (!strcmp(keyword, "duration") || !strcmp(keyword, "in") || !strcmp(keyword, "out")) { char *dur_str = get_keyword(&cursor); int64_t dur; if (!file) { @@ -377,6 +379,8 @@ static int concat_read_header(AVFormatContext *avf) file->duration = dur; else if (!strcmp(keyword, "in")) file->inpoint = dur; + else if (!strcmp(keyword, "out")) + file->outpoint = dur; } else if (!strcmp(keyword, "stream")) { if (!avformat_new_stream(avf, NULL)) FAIL(AVERROR(ENOMEM)); @@ -443,6 +447,8 @@ static int open_next_file(AVFormatContext *avf) cat->cur_file->duration = cat->avf->duration; if (cat->cur_file->inpoint != AV_NOPTS_VALUE) cat->cur_file->duration -= (cat->cur_file->inpoint - file_start_time); + if (cat->cur_file->outpoint != AV_NOPTS_VALUE) + cat->cur_file->duration -= cat->avf->duration - (cat->cur_file->outpoint - file_start_time); } if (++fileno >= cat->nb_files) { @@ -504,6 +510,16 @@ static int64_t get_cur_file_inpoint(ConcatContext *cat) return file_inpoint; } +/* Returns true if the packet pts is greater or equal to the specified outpoint. */ +static int packet_after_outpoint(ConcatContext *cat, AVPacket *pkt) +{ + if (cat->cur_file->outpoint != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE) { + return av_compare_ts(pkt->pts, cat->avf->streams[pkt->stream_index]->time_base, + cat->cur_file->outpoint, AV_TIME_BASE_Q) >= 0; + } + return 0; +} + static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) { ConcatContext *cat = avf->priv_data; @@ -520,7 +536,9 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) while (1) { ret = av_read_frame(cat->avf, pkt); - if (ret == AVERROR_EOF) { + if (ret == AVERROR_EOF || packet_after_outpoint(cat, pkt)) { + if (ret == 0) + av_packet_unref(pkt); if ((ret = open_next_file(avf)) < 0) return ret; continue; -- 2.1.4 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel