diff mbox series

[FFmpeg-devel,FFmpeg-devel,v2] avformat/img2dec: Option to play sequence backwards

Message ID 8500927F-727E-426C-A6FB-1DD8684C1817@gmail.com
State New
Headers show
Series [FFmpeg-devel,FFmpeg-devel,v2] avformat/img2dec: Option to play sequence backwards | expand

Checks

Context Check Description
andriy/configure_x86 warning Failed to apply patch
andriy/configure_ppc warning Failed to apply patch
andriy/configure_aarch64_jetson warning Failed to apply patch
yinshiyou/configure_loongarch64 warning Failed to apply patch
andriy/configure_armv7_RPi4 warning Failed to apply patch

Commit Message

Sergio Acereda Feb. 11, 2022, 3:27 p.m. UTC
This patch should allow to play a image sequence in backwards direction, without needing to apply a reverse filter.

$ ffmpeg -i sequence%05.png forward.mkv
$ ffmpeg -reverse 1 sequence%05.png backward.mkv


Signed-off-by: Sergio Acereda <sergio.acereda@gmail.com>
---
libavformat/img2.h    |  1 +
libavformat/img2dec.c | 32 ++++++++++++++++++++++----------
2 files changed, 23 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/libavformat/img2.h b/libavformat/img2.h
index 5fd8ff77fc..3d01c00537 100644
--- a/libavformat/img2.h
+++ b/libavformat/img2.h
@@ -59,6 +59,7 @@  typedef struct VideoDemuxData {
#endif
    int start_number;
    int start_number_range;
+    int reverse;
    int frame_size;
    int ts_from_file;
    int export_path_metadata; /**< enabled when set to 1. */
diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c
index 8608252d83..90465441f1 100644
--- a/libavformat/img2dec.c
+++ b/libavformat/img2dec.c
@@ -105,10 +105,12 @@  static int is_glob(const char *path)
 * @param plast_index  pointer to index updated with the last number in the range
 * @param path         path which has to be matched by the image files in the range
 * @param start_index  minimum accepted value for the first index in the range
+ * @param start_index_range range for looking at the first sequence number
+ * @param reverse      play backwards
 * @return -1 if no image file could be found
 */
static int find_image_range(AVIOContext *pb, int *pfirst_index, int *plast_index,
-                            const char *path, int start_index, int start_index_range)
+                            const char *path, int start_index, int start_index_range, int reverse)
{
    char buf[1024];
    int range, last_index, range1, first_index;
@@ -152,8 +154,14 @@  static int find_image_range(AVIOContext *pb, int *pfirst_index, int *plast_index
            break;
        last_index += range;
    }
-    *pfirst_index = first_index;
-    *plast_index  = last_index;
+    if (reverse) {
+        *pfirst_index = last_index;
+        *plast_index  = first_index;
+    }
+    else {
+        *pfirst_index = first_index;
+        *plast_index  = last_index;
+    }
    return 0;

fail:
@@ -274,7 +282,7 @@  int ff_img_read_header(AVFormatContext *s1)
        }
        if ((s->pattern_type == PT_GLOB_SEQUENCE && !s->use_glob) || s->pattern_type == PT_SEQUENCE) {
            if (find_image_range(s1->pb, &first_index, &last_index, s->path,
-                                 s->start_number, s->start_number_range) < 0) {
+                                 s->start_number, s->start_number_range, s->reverse) < 0) {
                av_log(s1, AV_LOG_ERROR,
                       "Could find no file with path '%s' and index in the range %d-%d\n",
                       s->path, s->start_number, s->start_number + s->start_number_range - 1);
@@ -307,7 +315,7 @@  int ff_img_read_header(AVFormatContext *s1)
        /* compute duration */
        if (!s->ts_from_file) {
            st->start_time = 0;
-            st->duration   = last_index - first_index + 1;
+            st->duration   = abs(last_index - first_index) + 1;
        }
    }

@@ -413,11 +421,12 @@  int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt)
    AVCodecParameters *par = s1->streams[0]->codecpar;

    if (!s->is_pipe) {
+        int bad = s->reverse? (s->img_number < s->img_last) : (s->img_number > s->img_last);
        /* loop over input */
-        if (s->loop && s->img_number > s->img_last) {
+        if (s->loop && bad) {
            s->img_number = s->img_first;
        }
-        if (s->img_number > s->img_last)
+        if (bad)
            return AVERROR_EOF;
        if (s->pattern_type == PT_NONE) {
            av_strlcpy(filename_bytes, s->path, sizeof(filename_bytes));
@@ -554,8 +563,9 @@  int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt)
        }
        goto fail;
    } else {
+        int step = s->reverse? -1 : 1;
        s->img_count++;
-        s->img_number++;
+        s->img_number += step;
        s->pts++;
        return 0;
    }
@@ -594,9 +604,10 @@  static int img_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
        return 0;
    }

-    if (timestamp < 0 || !s1->loop && timestamp > s1->img_last - s1->img_first)
+    int bad = s1->reverse? (timestamp < s1->img_last) : (timestamp > s1->img_last);
+    if (timestamp < 0 || !s1->loop && bad)
        return -1;
-    s1->img_number = timestamp%(s1->img_last - s1->img_first + 1) + s1->img_first;
+    s1->img_number = timestamp%abs(s1->img_last - s1->img_first + 1) + s1->img_first;
    s1->pts = timestamp;
    return 0;
}
@@ -619,6 +630,7 @@  const AVOption ff_img_options[] = {
    { "none",         "disable pattern matching",            0, AV_OPT_TYPE_CONST,  {.i64=PT_NONE         }, INT_MIN, INT_MAX, DEC, "pattern_type" },
    { "start_number", "set first number in the sequence",    OFFSET(start_number), AV_OPT_TYPE_INT,    {.i64 = 0   }, INT_MIN, INT_MAX, DEC },
    { "start_number_range", "set range for looking at the first sequence number", OFFSET(start_number_range), AV_OPT_TYPE_INT, {.i64 = 5}, 1, INT_MAX, DEC },
+    { "reverse",      "reverse direction",                   OFFSET(reverse),      AV_OPT_TYPE_INT,    {.i64 = 0   }, 0, 1, DEC },
    { "ts_from_file", "set frame timestamp from file's one", OFFSET(ts_from_file), AV_OPT_TYPE_INT,    {.i64 = 0   }, 0, 2,       DEC, "ts_type" },
    { "none", "none",                   0, AV_OPT_TYPE_CONST,    {.i64 = 0   }, 0, 2,       DEC, "ts_type" },
    { "sec",  "second precision",       0, AV_OPT_TYPE_CONST,    {.i64 = 1   }, 0, 2,       DEC, "ts_type" },