Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH] avformat/img2dec: Option to play sequence backwards
@ 2022-02-11 22:08 Sergio Acereda
  0 siblings, 0 replies; 12+ messages in thread
From: Sergio Acereda @ 2022-02-11 22:08 UTC (permalink / raw)
  To: ffmpeg-devel

This patch should allow to play an image sequence in backwards 
direction, without needing to apply a reverse filter.

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

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

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..7b85e01aca 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,13 @@ 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 +281,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 +314,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 +420,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 +562,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 +603,13 @@ 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;
+    int dir = s1->reverse? -1 : 1;
+    int span = 1 + dir * (s1->img_last - s1->img_first);
+    int rel = timestamp % span;
+    s1->img_number = s1->img_first + dir * rel;
      s1->pts = timestamp;
      return 0;
  }
@@ -619,6 +632,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" },
-- 
2.34.0

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread
* [FFmpeg-devel] [PATCH] avformat/img2dec: Option to play sequence backwards
@ 2022-02-12 11:57 Sergio Acereda
  2022-02-12 19:56 ` Michael Niedermayer
  2022-02-13 11:36 ` Sergio Acereda
  0 siblings, 2 replies; 12+ messages in thread
From: Sergio Acereda @ 2022-02-12 11:57 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Sergio Acereda

This patch should allow playing an image sequence in backwards direction, without needing to apply a reverse filter.

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

Signed-off-by: Sergio Acereda <sergio.acereda@gmail.com>
---
 libavformat/img2.h    |  1 +
 libavformat/img2dec.c | 40 +++++++++++++++++++++++++++-------------
 2 files changed, 28 insertions(+), 13 deletions(-)

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..f7ad85be08 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,13 @@ 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 +281,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 +314,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 +420,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 +562,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;
     }
@@ -585,6 +594,7 @@ static int img_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
 {
     VideoDemuxData *s1 = s->priv_data;
     AVStream *st = s->streams[0];
+    int bad = s1->reverse? (timestamp  < s1->img_last) : (timestamp > s1->img_last);
 
     if (s1->ts_from_file) {
         int index = av_index_search_timestamp(st, timestamp, flags);
@@ -592,12 +602,15 @@ static int img_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
             return -1;
         s1->img_number = ffstream(st)->index_entries[index].pos;
         return 0;
-    }
-
-    if (timestamp < 0 || !s1->loop && timestamp > s1->img_last - s1->img_first)
+    } else if (timestamp < 0 || !s1->loop && bad)
         return -1;
-    s1->img_number = timestamp%(s1->img_last - s1->img_first + 1) + s1->img_first;
-    s1->pts = timestamp;
+    else {
+        int dir = s1->reverse? -1 : 1;
+        int span = 1 + dir * (s1->img_last - s1->img_first);
+        int rel = timestamp % span;
+        s1->img_number = s1->img_first + dir * rel;
+        s1->pts = timestamp;
+    }
     return 0;
 }
 
@@ -619,6 +632,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" },
-- 
2.33.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread
* [FFmpeg-devel] [PATCH] avformat/img2dec: Option to play sequence backwards
@ 2022-02-10  9:31 Sergio Acereda
  2022-02-10 10:37 ` Gyan Doshi
  2022-02-10 12:59 ` Sergio Acereda
  0 siblings, 2 replies; 12+ messages in thread
From: Sergio Acereda @ 2022-02-10  9:31 UTC (permalink / raw)
  To: ffmpeg-devel

Signed-off-by: Sergio Acereda <sergio.acereda@gmail.com>
---
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

---
libavformat/img2.h    |  1 +
libavformat/img2dec.c | 32 ++++++++++++++++++++++----------
2 files changed, 23 insertions(+), 10 deletions(-)

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" },
-- 
2.34.1.windows.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2022-02-13 11:54 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-11 22:08 [FFmpeg-devel] [PATCH] avformat/img2dec: Option to play sequence backwards Sergio Acereda
  -- strict thread matches above, loose matches on Subject: below --
2022-02-12 11:57 Sergio Acereda
2022-02-12 19:56 ` Michael Niedermayer
2022-02-13 11:36 ` Sergio Acereda
2022-02-13 11:53   ` Michael Niedermayer
2022-02-10  9:31 Sergio Acereda
2022-02-10 10:37 ` Gyan Doshi
2022-02-10 12:59 ` Sergio Acereda
2022-02-10 20:50   ` Sergio Acereda
2022-02-11 16:45     ` Sergio Acereda
2022-02-11 17:19       ` Marvin Scholz
2022-02-11 19:39       ` Sergio Acereda

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git