FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
webpenc.c
Go to the documentation of this file.
1 /*
2  * webp muxer
3  * Copyright (c) 2014 Michael Niedermayer
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "libavutil/intreadwrite.h"
23 #include "libavutil/opt.h"
24 #include "avformat.h"
25 #include "internal.h"
26 
27 typedef struct WebpContext{
28  AVClass *class;
31  int loop;
32 } WebpContext;
33 
35 {
36  AVStream *st;
37 
38  if (s->nb_streams != 1) {
39  av_log(s, AV_LOG_ERROR, "Only exactly 1 stream is supported\n");
40  return AVERROR(EINVAL);
41  }
42  st = s->streams[0];
43  if (st->codec->codec_id != AV_CODEC_ID_WEBP) {
44  av_log(s, AV_LOG_ERROR, "Only WebP is supported\n");
45  return AVERROR(EINVAL);
46  }
47  avpriv_set_pts_info(st, 24, 1, 1000);
48 
49  avio_write(s->pb, "RIFF\0\0\0\0WEBP", 12);
50 
51  return 0;
52 }
53 
54 static int flush(AVFormatContext *s, int trailer, int64_t pts)
55 {
56  WebpContext *w = s->priv_data;
57  AVStream *st = s->streams[0];
58 
59  if (w->last_pkt.size) {
60  int skip = 0;
61  unsigned flags = 0;
62  int vp8x = 0;
63 
64  if (AV_RL32(w->last_pkt.data) == AV_RL32("RIFF"))
65  skip = 12;
66  if (AV_RL32(w->last_pkt.data + skip) == AV_RL32("VP8X")) {
67  flags |= w->last_pkt.data[skip + 4 + 4];
68  vp8x = 1;
69  skip += AV_RL32(w->last_pkt.data + skip + 4) + 8;
70  }
71 
72  w->frame_count ++;
73 
74  if (w->frame_count == 1) {
75  if (!trailer) {
76  vp8x = 1;
77  flags |= 2 + 16;
78  }
79 
80  if (vp8x) {
81  avio_write(s->pb, "VP8X", 4);
82  avio_wl32(s->pb, 10);
83  avio_w8(s->pb, flags);
84  avio_wl24(s->pb, 0);
85  avio_wl24(s->pb, st->codec->width - 1);
86  avio_wl24(s->pb, st->codec->height - 1);
87  }
88  if (!trailer) {
89  avio_write(s->pb, "ANIM", 4);
90  avio_wl32(s->pb, 6);
91  avio_wl32(s->pb, 0xFFFFFFFF);
92  avio_wl16(s->pb, w->loop);
93  }
94  }
95 
96  if (w->frame_count > trailer) {
97  avio_write(s->pb, "ANMF", 4);
98  avio_wl32(s->pb, 16 + w->last_pkt.size - skip);
99  avio_wl24(s->pb, 0);
100  avio_wl24(s->pb, 0);
101  avio_wl24(s->pb, st->codec->width - 1);
102  avio_wl24(s->pb, st->codec->height - 1);
103  if (w->last_pkt.pts != AV_NOPTS_VALUE && pts != AV_NOPTS_VALUE) {
104  avio_wl24(s->pb, pts - w->last_pkt.pts);
105  } else
106  avio_wl24(s->pb, w->last_pkt.duration);
107  avio_w8(s->pb, 0);
108  }
109  avio_write(s->pb, w->last_pkt.data + skip, w->last_pkt.size - skip);
111  }
112 
113  return 0;
114 }
115 
117 {
118  WebpContext *w = s->priv_data;
119  int ret;
120 
121  if ((ret = flush(s, 0, pkt->pts)) < 0)
122  return ret;
123 
124  av_copy_packet(&w->last_pkt, pkt);
125 
126  return 0;
127 }
128 
130 {
131  unsigned filesize;
132  int ret;
133 
134  if ((ret = flush(s, 1, AV_NOPTS_VALUE)) < 0)
135  return ret;
136 
137  filesize = avio_tell(s->pb);
138  avio_seek(s->pb, 4, SEEK_SET);
139  avio_wl32(s->pb, filesize - 8);
140 
141  return 0;
142 }
143 
144 #define OFFSET(x) offsetof(WebpContext, x)
145 #define ENC AV_OPT_FLAG_ENCODING_PARAM
146 static const AVOption options[] = {
147  { "loop", "Number of times to loop the output: 0 - infinite loop", OFFSET(loop),
148  AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 65535, ENC },
149  { NULL },
150 };
151 
152 static const AVClass webp_muxer_class = {
153  .class_name = "WebP muxer",
154  .item_name = av_default_item_name,
155  .version = LIBAVUTIL_VERSION_INT,
156  .option = options,
157 };
159  .name = "webp",
160  .long_name = NULL_IF_CONFIG_SMALL("WebP"),
161  .extensions = "webp",
162  .priv_data_size = sizeof(WebpContext),
163  .video_codec = AV_CODEC_ID_WEBP,
167  .priv_class = &webp_muxer_class,
169 };