[FFmpeg-devel] [PATCH] WIP: concat demuxer mode concealing input errors

Andrey Utkin andrey.krieger.utkin at gmail.com
Sat Apr 19 05:10:53 CEST 2014


Not sure whether this is important or usable for anybody else.
I'm doing it for a case happening in one of my apps. It happens that some files pending to concatenation are broken, e.g. mp4 files are unfinished and ffmpeg cannot find their moov block, this makes concatenation to stop. For now, as a workaround i ffprobe each chunk before including it to concatenation list, but if we have such mode in concat demuxer itself, we could also handle problems which happen after opening input file, and also have less overhead on those checks.

Currently,
- failure to open the first item is processed likely fine;
- failure of file reading (av_read_frame()) is not tested;
- failure to open non-first items gives bad results because DTS shifting is done wrong, see "// FIXME" place. I have no idea how to make it in a good way, currently.

---8<---

---
 libavformat/concatdec.c | 36 ++++++++++++++++++++++++++++++------
 1 file changed, 30 insertions(+), 6 deletions(-)

diff --git a/libavformat/concatdec.c b/libavformat/concatdec.c
index c79bee5..96e1b93 100644
--- a/libavformat/concatdec.c
+++ b/libavformat/concatdec.c
@@ -207,6 +207,7 @@ static int open_file(AVFormatContext *avf, unsigned fileno)
     }
     cat->cur_file = file;
     if (file->start_time == AV_NOPTS_VALUE)
+        // FIXME
         file->start_time = !fileno ? 0 :
                            cat->files[fileno - 1].start_time +
                            cat->files[fileno - 1].duration;
@@ -238,6 +239,7 @@ static int concat_read_header(AVFormatContext *avf)
     ConcatFile *file = NULL;
     AVStream *st;
     int64_t time = 0;
+    int fileno = 0;
 
     while (1) {
         if ((ret = ff_get_line(avf->pb, buf, sizeof(buf))) <= 0)
@@ -316,8 +318,21 @@ static int concat_read_header(AVFormatContext *avf)
     }
 
     cat->match_streams = !!avf->nb_streams;
-    if ((ret = open_file(avf, 0)) < 0)
-        FAIL(ret);
+    while (1) {
+        ret = open_file(avf, fileno);
+        if (ret < 0) {
+            if (1/* TODO flag*/) {
+                av_log(avf, AV_LOG_DEBUG, "This one failed to open, trying next file\n");
+                if (++fileno >= cat->nb_files)
+                    FAIL(AVERROR_EOF);
+            } else {
+                FAIL(ret);
+            }
+        } else {
+            break;
+        }
+    }
+
     if (!cat->match_streams) {
         for (i = 0; i < cat->avf->nb_streams; i++) {
             if (!(st = avformat_new_stream(avf, NULL)))
@@ -338,13 +353,22 @@ static int open_next_file(AVFormatContext *avf)
 {
     ConcatContext *cat = avf->priv_data;
     unsigned fileno = cat->cur_file - cat->files;
+    int ret;
 
     if (cat->cur_file->duration == AV_NOPTS_VALUE)
         cat->cur_file->duration = cat->avf->duration;
 
-    if (++fileno >= cat->nb_files)
-        return AVERROR_EOF;
-    return open_file(avf, fileno);
+    while (1) {
+        if (++fileno >= cat->nb_files)
+            return AVERROR_EOF;
+
+        ret = open_file(avf, fileno);
+        if (1/* TODO flag */ && ret < 0) {
+            av_log(avf, AV_LOG_DEBUG, "Switching to next file failed, Trying yet next file\n");
+        } else {
+            return ret;
+        }
+    }
 }
 
 static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
@@ -355,7 +379,7 @@ 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 || 1/* TODO flag*/) {
             if ((ret = open_next_file(avf)) < 0)
                 return ret;
             continue;
-- 
1.8.5.3



More information about the ffmpeg-devel mailing list