Signed-off-by: Marton Balint <c...@passwd.hu> --- doc/demuxers.texi | 17 +++++++++++++++++ libavformat/concatdec.c | 48 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 52 insertions(+), 13 deletions(-)
diff --git a/doc/demuxers.texi b/doc/demuxers.texi index 35a1561..4bad1c8 100644 --- a/doc/demuxers.texi +++ b/doc/demuxers.texi @@ -112,6 +112,23 @@ file is not available or accurate. If the duration is set for all files, then it is possible to seek in the whole concatenated video. +@item @code{in @var{timestamp}} +In point of the file. When the demuxer opens the file it instantly seeks to the +specified timestamp. Seeking is done so that all streams can be presented +successfully at In point. + +This directive works best with intra frame codecs, because for non-intra frame +ones you will usually get extra packets before the actual In point and the +decoded content will most likely contain frames before In point too. + +For each file, packets before the file In point will have timestamps less than +the calculated start timestamp of the file (negative in case of the first +file), and the duration of the files (if not specified by the @code{duration} +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{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 e95ff34..c61a1a3 100644 --- a/libavformat/concatdec.c +++ b/libavformat/concatdec.c @@ -43,6 +43,7 @@ typedef struct { int64_t start_time; int64_t duration; ConcatStream *streams; + int64_t inpoint; int nb_streams; } ConcatFile; @@ -142,6 +143,7 @@ static int add_file(AVFormatContext *avf, char *filename, ConcatFile **rfile, file->url = url; file->start_time = AV_NOPTS_VALUE; file->duration = AV_NOPTS_VALUE; + file->inpoint = AV_NOPTS_VALUE; return 0; @@ -308,6 +310,10 @@ static int open_file(AVFormatContext *avf, unsigned fileno) cat->files[fileno - 1].duration; if ((ret = match_streams(avf)) < 0) return ret; + if (file->inpoint != AV_NOPTS_VALUE) { + if ((ret = avformat_seek_file(cat->avf, -1, INT64_MIN, file->inpoint, file->inpoint, 0) < 0)) + return ret; + } return 0; } @@ -353,20 +359,23 @@ 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")) { + } else if (!strcmp(keyword, "duration") || !strcmp(keyword, "in")) { char *dur_str = get_keyword(&cursor); int64_t dur; if (!file) { - av_log(avf, AV_LOG_ERROR, "Line %d: duration without file\n", - line); + av_log(avf, AV_LOG_ERROR, "Line %d: %s without file\n", + line, keyword); FAIL(AVERROR_INVALIDDATA); } if ((ret = av_parse_time(&dur, dur_str, 1)) < 0) { - av_log(avf, AV_LOG_ERROR, "Line %d: invalid duration '%s'\n", - line, dur_str); + av_log(avf, AV_LOG_ERROR, "Line %d: invalid %s '%s'\n", + line, keyword, dur_str); goto fail; } - file->duration = dur; + if (!strcmp(keyword, "duration")) + file->duration = dur; + else if (!strcmp(keyword, "in")) + file->inpoint = dur; } else if (!strcmp(keyword, "stream")) { if (!avformat_new_stream(avf, NULL)) FAIL(AVERROR(ENOMEM)); @@ -428,8 +437,12 @@ static int open_next_file(AVFormatContext *avf) ConcatContext *cat = avf->priv_data; unsigned fileno = cat->cur_file - cat->files; - if (cat->cur_file->duration == AV_NOPTS_VALUE) + if (cat->cur_file->duration == AV_NOPTS_VALUE) { + int64_t file_start_time = (cat->avf->start_time == AV_NOPTS_VALUE) ? 0 : cat->avf->start_time; 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 (++fileno >= cat->nb_files) return AVERROR_EOF; @@ -476,11 +489,23 @@ static int filter_packet(AVFormatContext *avf, ConcatStream *cs, AVPacket *pkt) return 0; } +static int64_t get_cur_file_inpoint(ConcatContext *cat) +{ + int64_t file_inpoint = cat->cur_file->inpoint; + if (file_inpoint == AV_NOPTS_VALUE) { + int64_t file_start_time = cat->avf->start_time; + if (file_start_time == AV_NOPTS_VALUE) + file_start_time = 0; + return file_start_time; + } + return file_inpoint; +} + static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) { ConcatContext *cat = avf->priv_data; int ret; - int64_t file_start_time, delta; + int64_t delta; ConcatStream *cs; AVStream *st; @@ -517,10 +542,7 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base)); - file_start_time = cat->avf->start_time; - if (file_start_time == AV_NOPTS_VALUE) - file_start_time = 0; - delta = av_rescale_q(cat->cur_file->start_time - file_start_time, + delta = av_rescale_q(cat->cur_file->start_time - get_cur_file_inpoint(cat), AV_TIME_BASE_Q, cat->avf->streams[pkt->stream_index]->time_base); if (pkt->pts != AV_NOPTS_VALUE) @@ -547,7 +569,7 @@ static int try_seek(AVFormatContext *avf, int stream, int64_t min_ts, int64_t ts, int64_t max_ts, int flags) { ConcatContext *cat = avf->priv_data; - int64_t t0 = cat->cur_file->start_time - cat->avf->start_time; + int64_t t0 = cat->cur_file->start_time - get_cur_file_inpoint(cat); ts -= t0; min_ts = min_ts == INT64_MIN ? INT64_MIN : min_ts - t0; -- 2.1.4 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel