[FFmpeg-devel] [PATCHv2 3/5] concatdec: add support for specifying outpoint of files

Marton Balint cus at passwd.hu
Sat Jul 11 19:20:54 CEST 2015


Signed-off-by: Marton Balint <cus at passwd.hu>
---
 doc/demuxers.texi       | 19 +++++++++++++++++++
 libavformat/concatdec.c | 29 +++++++++++++++++++++++++----
 2 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/doc/demuxers.texi b/doc/demuxers.texi
index 27a9409..50b5688 100644
--- a/doc/demuxers.texi
+++ b/doc/demuxers.texi
@@ -129,6 +129,25 @@ 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.
 
+ at item @code{outpoint @var{timestamp}}
+Out point of the file. When the demuxer reaches the specified decoding
+timestamp in any of the streams, it handles it as an end of file condition and
+skips the current and all the remaining packets from all streams.
+
+Out point is exclusive, which means that the demuxer will not output packets
+with a decoding timestamp greater or equal to Out point.
+
+This directive works best with intra frame codecs and formats where all streams
+are tightly interleaved. For non-intra frame codecs you will usually get
+additional packets with presentation timestamp after Out point therefore the
+decoded content will most likely contain frames after Out point too. If your
+streams are not tightly interleaved you may not get all the packets from all
+streams before Out point and you may only will be able to decode the earliest
+stream until 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 fa85b6e..5dcfd02 100644
--- a/libavformat/concatdec.c
+++ b/libavformat/concatdec.c
@@ -46,6 +46,7 @@ typedef struct {
     int64_t duration;
     ConcatStream *streams;
     int64_t inpoint;
+    int64_t outpoint;
     int nb_streams;
 } ConcatFile;
 
@@ -147,6 +148,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;
 
@@ -364,7 +366,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, "inpoint")) {
+        } else if (!strcmp(keyword, "duration") || !strcmp(keyword, "inpoint") || !strcmp(keyword, "outpoint")) {
             char *dur_str = get_keyword(&cursor);
             int64_t dur;
             if (!file) {
@@ -381,6 +383,8 @@ static int concat_read_header(AVFormatContext *avf)
                 file->duration = dur;
             else if (!strcmp(keyword, "inpoint"))
                 file->inpoint = dur;
+            else if (!strcmp(keyword, "outpoint"))
+                file->outpoint = dur;
         } else if (!strcmp(keyword, "stream")) {
             if (!avformat_new_stream(avf, NULL))
                 FAIL(AVERROR(ENOMEM));
@@ -417,8 +421,11 @@ static int concat_read_header(AVFormatContext *avf)
             cat->files[i].start_time = time;
         else
             time = cat->files[i].start_time;
-        if (cat->files[i].duration == AV_NOPTS_VALUE)
-            break;
+        if (cat->files[i].duration == AV_NOPTS_VALUE) {
+            if (cat->files[i].inpoint == AV_NOPTS_VALUE || cat->files[i].outpoint == AV_NOPTS_VALUE)
+                break;
+            cat->files[i].duration = cat->files[i].outpoint - cat->files[i].inpoint;
+        }
         time += cat->files[i].duration;
     }
     if (i == cat->nb_files) {
@@ -446,6 +453,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 - cat->cur_file->file_start_time);
+        if (cat->cur_file->outpoint != AV_NOPTS_VALUE)
+            cat->cur_file->duration -= cat->avf->duration - (cat->cur_file->outpoint - cat->cur_file->file_start_time);
     }
 
     if (++fileno >= cat->nb_files) {
@@ -495,6 +504,16 @@ static int filter_packet(AVFormatContext *avf, ConcatStream *cs, AVPacket *pkt)
     return 0;
 }
 
+/* Returns true if the packet dts 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->dts != AV_NOPTS_VALUE) {
+        return av_compare_ts(pkt->dts, 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;
@@ -511,7 +530,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



More information about the ffmpeg-devel mailing list