[FFmpeg-devel] [PATCH 1/4] concatdec: add support for specifying inpoint of files

Marton Balint cus at passwd.hu
Mon Jul 6 02:28:48 CEST 2015


Signed-off-by: Marton Balint <cus at 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.
 
+ at 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



More information about the ffmpeg-devel mailing list