[FFmpeg-cvslog] WebP muxer: support a packet containing animated WebP.

Urvang Joshi git at videolan.org
Fri May 22 01:02:25 CEST 2015


ffmpeg | branch: master | Urvang Joshi <urvang at google.com> | Tue May 19 17:39:54 2015 -0700| [6b56fcbd10a56d2a7a116c0de4ee032b895456c2] | committer: Michael Niedermayer

WebP muxer: support a packet containing animated WebP.

This is the 1st patch in preparation for using WebPAnimEncoder API for encoding
and muxing WebP images.

Signed-off-by: Michael Niedermayer <michaelni at gmx.at>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=6b56fcbd10a56d2a7a116c0de4ee032b895456c2
---

 libavformat/webpenc.c |   79 +++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 64 insertions(+), 15 deletions(-)

diff --git a/libavformat/webpenc.c b/libavformat/webpenc.c
index ee110de..69270c6 100644
--- a/libavformat/webpenc.c
+++ b/libavformat/webpenc.c
@@ -29,6 +29,8 @@ typedef struct WebpContext{
     int frame_count;
     AVPacket last_pkt;
     int loop;
+    int wrote_webp_header;
+    int using_webp_anim_encoder;
 } WebpContext;
 
 static int webp_write_header(AVFormatContext *s)
@@ -46,8 +48,29 @@ static int webp_write_header(AVFormatContext *s)
     }
     avpriv_set_pts_info(st, 24, 1, 1000);
 
-    avio_write(s->pb, "RIFF\0\0\0\0WEBP", 12);
+    return 0;
+}
+
+static int is_animated_webp_packet(AVPacket *pkt)
+{
+    if (pkt->size) {
+        int skip = 0;
+        unsigned flags = 0;
+
+        if (pkt->size < 4)
+            return 0;
+        if (AV_RL32(pkt->data) == AV_RL32("RIFF"))
+            skip = 12;
+
+        if (pkt->size < skip + 4)
+            return 0;
+        if (AV_RL32(pkt->data + skip) == AV_RL32("VP8X")) {
+            flags |= pkt->data[skip + 4 + 4];
+        }
 
+        if (flags & 2)  // ANIMATION_FLAG is on
+            return 1;
+    }
     return 0;
 }
 
@@ -61,15 +84,25 @@ static int flush(AVFormatContext *s, int trailer, int64_t pts)
         unsigned flags = 0;
         int vp8x = 0;
 
+        if (w->last_pkt.size < 4)
+            return 0;
         if (AV_RL32(w->last_pkt.data) == AV_RL32("RIFF"))
             skip = 12;
+
+        if (w->last_pkt.size < skip + 4)
+            return 0;  // Safe to do this as a valid WebP bitstream is >=30 bytes.
         if (AV_RL32(w->last_pkt.data + skip) == AV_RL32("VP8X")) {
             flags |= w->last_pkt.data[skip + 4 + 4];
             vp8x = 1;
             skip += AV_RL32(w->last_pkt.data + skip + 4) + 8;
         }
 
-        w->frame_count ++;
+        if (!w->wrote_webp_header) {
+            avio_write(s->pb, "RIFF\0\0\0\0WEBP", 12);
+            w->wrote_webp_header = 1;
+            if (w->frame_count > 1)  // first non-empty packet
+                w->frame_count = 1;  // so we don't count previous empty packets.
+        }
 
         if (w->frame_count == 1) {
             if (!trailer) {
@@ -116,12 +149,18 @@ static int flush(AVFormatContext *s, int trailer, int64_t pts)
 static int webp_write_packet(AVFormatContext *s, AVPacket *pkt)
 {
     WebpContext *w = s->priv_data;
-    int ret;
-
-    if ((ret = flush(s, 0, pkt->pts)) < 0)
-        return ret;
-
-    av_copy_packet(&w->last_pkt, pkt);
+    w->using_webp_anim_encoder |= is_animated_webp_packet(pkt);
+
+    if (w->using_webp_anim_encoder) {
+        avio_write(s->pb, pkt->data, pkt->size);
+        w->wrote_webp_header = 1;  // for good measure
+    } else {
+        int ret;
+        if ((ret = flush(s, 0, pkt->pts)) < 0)
+            return ret;
+        av_copy_packet(&w->last_pkt, pkt);
+    }
+    ++w->frame_count;
 
     return 0;
 }
@@ -129,14 +168,24 @@ static int webp_write_packet(AVFormatContext *s, AVPacket *pkt)
 static int webp_write_trailer(AVFormatContext *s)
 {
     unsigned filesize;
-    int ret;
-
-    if ((ret = flush(s, 1, AV_NOPTS_VALUE)) < 0)
-        return ret;
+    WebpContext *w = s->priv_data;
 
-    filesize = avio_tell(s->pb);
-    avio_seek(s->pb, 4, SEEK_SET);
-    avio_wl32(s->pb, filesize - 8);
+    if (w->using_webp_anim_encoder) {
+        if ((w->frame_count > 1) && w->loop) {  // Write loop count.
+            avio_seek(s->pb, 42, SEEK_SET);
+            avio_wl16(s->pb, w->loop);
+        }
+    } else {
+        int ret;
+        if ((ret = flush(s, 1, AV_NOPTS_VALUE)) < 0)
+            return ret;
+
+        filesize = avio_tell(s->pb);
+        avio_seek(s->pb, 4, SEEK_SET);
+        avio_wl32(s->pb, filesize - 8);
+        // Note: without the following, avio only writes 8 bytes to the file.
+        avio_seek(s->pb, filesize, SEEK_SET);
+    }
 
     return 0;
 }



More information about the ffmpeg-cvslog mailing list