Browse code

Merge commit 'be7c323176e2e5fcf30e3d2ff20975b2f936811b'

* commit 'be7c323176e2e5fcf30e3d2ff20975b2f936811b':
Add a libwebp encoder

Conflicts:
Changelog
doc/encoders.texi
doc/general.texi
libavcodec/version.h
libavformat/img2enc.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>

Michael Niedermayer authored on 2013/12/22 19:53:41
Showing 9 changed files
... ...
@@ -14,6 +14,7 @@ version <next>
14 14
 - Windows resource files for shared libraries
15 15
 - aeval filter
16 16
 - stereoscopic 3d metadata handling
17
+- WebP encoding via libwebp
17 18
 
18 19
 
19 20
 version 2.1:
... ...
@@ -241,6 +241,7 @@ External library support:
241 241
                            native implementation exists [no]
242 242
   --enable-libvpx          enable VP8 and VP9 de/encoding via libvpx [no]
243 243
   --enable-libwavpack      enable wavpack encoding via libwavpack [no]
244
+  --enable-libwebp         enable WebP encoding via libwebp [no]
244 245
   --enable-libx264         enable H.264 encoding via x264 [no]
245 246
   --enable-libxavs         enable AVS encoding via xavs [no]
246 247
   --enable-libxvid         enable Xvid encoding via xvidcore,
... ...
@@ -1290,6 +1291,7 @@ EXTERNAL_LIBRARY_LIST="
1290 1290
     libvorbis
1291 1291
     libvpx
1292 1292
     libwavpack
1293
+    libwebp
1293 1294
     libx264
1294 1295
     libxavs
1295 1296
     libxvid
... ...
@@ -2145,6 +2147,7 @@ libvpx_vp8_encoder_deps="libvpx"
2145 2145
 libvpx_vp9_decoder_deps="libvpx"
2146 2146
 libvpx_vp9_encoder_deps="libvpx"
2147 2147
 libwavpack_encoder_deps="libwavpack"
2148
+libwebp_encoder_deps="libwebp"
2148 2149
 libx264_encoder_deps="libx264"
2149 2150
 libx264rgb_encoder_deps="libx264"
2150 2151
 libxavs_encoder_deps="libxavs"
... ...
@@ -4437,6 +4440,7 @@ enabled libvpx            && {
4437 4437
     enabled libvpx_vp9_decoder && { check_lib2 "vpx/vpx_decoder.h vpx/vp8dx.h" "vpx_codec_vp9_dx" -lvpx || disable libvpx_vp9_decoder; }
4438 4438
     enabled libvpx_vp9_encoder && { check_lib2 "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_vp9_cx VP9E_SET_SVC" -lvpx || disable libvpx_vp9_encoder; } }
4439 4439
 enabled libwavpack        && require libwavpack wavpack/wavpack.h WavpackOpenFileOutput  -lwavpack
4440
+enabled libwebp           && require_pkg_config libwebp webp/encode.h WebPGetEncoderVersion
4440 4441
 enabled libx264           && require libx264 x264.h x264_encoder_encode -lx264 &&
4441 4442
                              { check_cpp_condition x264.h "X264_BUILD >= 118" ||
4442 4443
                                die "ERROR: libx264 must be installed and version must be >= 0.118."; }
... ...
@@ -1365,6 +1365,68 @@ g_error_resilient
1365 1365
 For more information about libvpx see:
1366 1366
 @url{http://www.webmproject.org/}
1367 1367
 
1368
+
1369
+@section libwebp
1370
+
1371
+libwebp WebP Image encoder wrapper
1372
+
1373
+libwebp is Google's official encoder for WebP images. It can encode in either
1374
+lossy or lossless mode. Lossy images are essentially a wrapper around a VP8
1375
+frame. Lossless images are a separate codec developed by Google.
1376
+
1377
+@subsection Pixel Format
1378
+
1379
+Currently, libwebp only supports YUV420 for lossy and RGB for lossless due
1380
+to limitations of the format and libwebp. Alpha is supported for either mode.
1381
+Because of API limitations, if RGB is passed in when encoding lossy or YUV is
1382
+passed in for encoding lossless, the pixel format will automatically be
1383
+converted using functions from libwebp. This is not ideal and is done only for
1384
+convenience.
1385
+
1386
+@subsection Options
1387
+
1388
+@table @option
1389
+
1390
+@item -lossless @var{boolean}
1391
+Enables/Disables use of lossless mode. Default is 0.
1392
+
1393
+@item -compression_level @var{integer}
1394
+For lossy, this is a quality/speed tradeoff. Higher values give better quality
1395
+for a given size at the cost of increased encoding time. For lossless, this is
1396
+a size/speed tradeoff. Higher values give smaller size at the cost of increased
1397
+encoding time. More specifically, it controls the number of extra algorithms
1398
+and compression tools used, and varies the combination of these tools. This
1399
+maps to the @var{method} option in libwebp. The valid range is 0 to 6.
1400
+Default is 4.
1401
+
1402
+@item -qscale @var{float}
1403
+For lossy encoding, this controls image quality, 0 to 100. For lossless
1404
+encoding, this controls the effort and time spent at compressing more. The
1405
+default value is 75. Note that for usage via libavcodec, this option is called
1406
+@var{global_quality} and must be multiplied by @var{FF_QP2LAMBDA}.
1407
+
1408
+@item -preset @var{type}
1409
+Configuration preset. This does some automatic settings based on the general
1410
+type of the image.
1411
+@table @option
1412
+@item none
1413
+Do not use a preset.
1414
+@item default
1415
+Use the encoder default.
1416
+@item picture
1417
+Digital picture, like portrait, inner shot
1418
+@item photo
1419
+Outdoor photograph, with natural lighting
1420
+@item drawing
1421
+Hand or line drawing, with high-contrast details
1422
+@item icon
1423
+Small-sized colorful images
1424
+@item text
1425
+Text-like
1426
+@end table
1427
+
1428
+@end table
1429
+
1368 1430
 @section libx264
1369 1431
 
1370 1432
 x264 H.264/MPEG-4 AVC encoder wrapper.
... ...
@@ -491,8 +491,8 @@ following image formats are supported:
491 491
     @tab YUV, JPEG and some extension is not supported yet.
492 492
 @item Truevision Targa  @tab X @tab X
493 493
     @tab Targa (.TGA) image format
494
-@item WebP         @tab @tab X
495
-    @tab WebP image format
494
+@item WebP         @tab E @tab X
495
+    @tab WebP image format, encoding supported through external library libwebp
496 496
 @item XBM  @tab X @tab X
497 497
     @tab X BitMap image format
498 498
 @item XFace @tab X @tab X
... ...
@@ -734,6 +734,7 @@ OBJS-$(CONFIG_LIBVPX_VP8_ENCODER)         += libvpxenc.o
734 734
 OBJS-$(CONFIG_LIBVPX_VP9_DECODER)         += libvpxdec.o libvpx.o
735 735
 OBJS-$(CONFIG_LIBVPX_VP9_ENCODER)         += libvpxenc.o libvpx.o
736 736
 OBJS-$(CONFIG_LIBWAVPACK_ENCODER)         += libwavpackenc.o
737
+OBJS-$(CONFIG_LIBWEBP_ENCODER)            += libwebpenc.o
737 738
 OBJS-$(CONFIG_LIBX264_ENCODER)            += libx264.o
738 739
 OBJS-$(CONFIG_LIBXAVS_ENCODER)            += libxavs.o
739 740
 OBJS-$(CONFIG_LIBXVID_ENCODER)            += libxvid.o
... ...
@@ -509,6 +509,7 @@ void avcodec_register_all(void)
509 509
     REGISTER_ENCDEC (LIBVPX_VP8,        libvpx_vp8);
510 510
     REGISTER_ENCDEC (LIBVPX_VP9,        libvpx_vp9);
511 511
     REGISTER_ENCODER(LIBWAVPACK,        libwavpack);
512
+    REGISTER_ENCODER(LIBWEBP,           libwebp);
512 513
     REGISTER_ENCODER(LIBX264,           libx264);
513 514
     REGISTER_ENCODER(LIBX264RGB,        libx264rgb);
514 515
     REGISTER_ENCODER(LIBXAVS,           libxavs);
515 516
new file mode 100644
... ...
@@ -0,0 +1,287 @@
0
+/*
1
+ * WebP encoding support via libwebp
2
+ * Copyright (c) 2013 Justin Ruggles <justin.ruggles@gmail.com>
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+/**
22
+ * @file
23
+ * WebP encoder using libwebp
24
+ */
25
+
26
+#include <webp/encode.h>
27
+
28
+#include "libavutil/common.h"
29
+#include "libavutil/frame.h"
30
+#include "libavutil/imgutils.h"
31
+#include "libavutil/opt.h"
32
+#include "avcodec.h"
33
+#include "internal.h"
34
+
35
+typedef struct LibWebPContext {
36
+    AVClass *class;         // class for AVOptions
37
+    float quality;          // lossy quality 0 - 100
38
+    int lossless;           // use lossless encoding
39
+    int preset;             // configuration preset
40
+    int chroma_warning;     // chroma linesize mismatch warning has been printed
41
+    int conversion_warning; // pixel format conversion warning has been printed
42
+    WebPConfig config;      // libwebp configuration
43
+} LibWebPContext;
44
+
45
+static int libwebp_error_to_averror(int err)
46
+{
47
+    switch (err) {
48
+    case VP8_ENC_ERROR_OUT_OF_MEMORY:
49
+    case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
50
+        return AVERROR(ENOMEM);
51
+    case VP8_ENC_ERROR_NULL_PARAMETER:
52
+    case VP8_ENC_ERROR_INVALID_CONFIGURATION:
53
+    case VP8_ENC_ERROR_BAD_DIMENSION:
54
+        return AVERROR(EINVAL);
55
+    }
56
+    return AVERROR_UNKNOWN;
57
+}
58
+
59
+static av_cold int libwebp_encode_init(AVCodecContext *avctx)
60
+{
61
+    LibWebPContext *s = avctx->priv_data;
62
+    int ret;
63
+
64
+    if (avctx->global_quality < 0)
65
+        avctx->global_quality = 75 * FF_QP2LAMBDA;
66
+    s->quality = av_clipf(avctx->global_quality / (float)FF_QP2LAMBDA,
67
+                          0.0f, 100.0f);
68
+
69
+    if (avctx->compression_level < 0 || avctx->compression_level > 6) {
70
+        av_log(avctx, AV_LOG_WARNING, "invalid compression level: %d\n",
71
+               avctx->compression_level);
72
+        avctx->compression_level = av_clip(avctx->compression_level, 0, 6);
73
+    }
74
+
75
+    if (s->preset >= WEBP_PRESET_DEFAULT) {
76
+        ret = WebPConfigPreset(&s->config, s->preset, s->quality);
77
+        if (!ret)
78
+            return AVERROR_UNKNOWN;
79
+        s->lossless              = s->config.lossless;
80
+        s->quality               = s->config.quality;
81
+        avctx->compression_level = s->config.method;
82
+    } else {
83
+        ret = WebPConfigInit(&s->config);
84
+        if (!ret)
85
+            return AVERROR_UNKNOWN;
86
+
87
+        s->config.lossless = s->lossless;
88
+        s->config.quality  = s->quality;
89
+        s->config.method   = avctx->compression_level;
90
+
91
+        ret = WebPValidateConfig(&s->config);
92
+        if (!ret)
93
+            return AVERROR(EINVAL);
94
+    }
95
+
96
+    av_log(avctx, AV_LOG_DEBUG, "%s - quality=%.1f method=%d\n",
97
+           s->lossless ? "Lossless" : "Lossy", s->quality,
98
+           avctx->compression_level);
99
+
100
+    return 0;
101
+}
102
+
103
+static int libwebp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
104
+                                const AVFrame *frame, int *got_packet)
105
+{
106
+    LibWebPContext *s  = avctx->priv_data;
107
+    AVFrame *alt_frame = NULL;
108
+    WebPPicture *pic = NULL;
109
+    WebPMemoryWriter mw = { 0 };
110
+    int ret;
111
+
112
+    if (avctx->width > WEBP_MAX_DIMENSION || avctx->height > WEBP_MAX_DIMENSION) {
113
+        av_log(avctx, AV_LOG_ERROR, "Picture size is too large. Max is %dx%d.\n",
114
+               WEBP_MAX_DIMENSION, WEBP_MAX_DIMENSION);
115
+        return AVERROR(EINVAL);
116
+    }
117
+
118
+    pic = av_malloc(sizeof(*pic));
119
+    if (!pic)
120
+        return AVERROR(ENOMEM);
121
+
122
+    ret = WebPPictureInit(pic);
123
+    if (!ret) {
124
+        ret = AVERROR_UNKNOWN;
125
+        goto end;
126
+    }
127
+    pic->width  = avctx->width;
128
+    pic->height = avctx->height;
129
+
130
+    if (avctx->pix_fmt == AV_PIX_FMT_RGB32) {
131
+        if (!s->lossless) {
132
+            /* libwebp will automatically convert RGB input to YUV when
133
+               encoding lossy. */
134
+            if (!s->conversion_warning) {
135
+                av_log(avctx, AV_LOG_WARNING,
136
+                       "Using libwebp for RGB-to-YUV conversion. You may want "
137
+                       "to consider passing in YUV instead for lossy "
138
+                       "encoding.\n");
139
+                s->conversion_warning = 1;
140
+            }
141
+        }
142
+        pic->use_argb    = 1;
143
+        pic->argb        = (uint32_t *)frame->data[0];
144
+        pic->argb_stride = frame->linesize[0] / 4;
145
+    } else {
146
+        if (frame->linesize[1] != frame->linesize[2]) {
147
+            if (!s->chroma_warning) {
148
+                av_log(avctx, AV_LOG_WARNING,
149
+                       "Copying frame due to differing chroma linesizes.\n");
150
+                s->chroma_warning = 1;
151
+            }
152
+            alt_frame = av_frame_alloc();
153
+            if (!alt_frame) {
154
+                ret = AVERROR(ENOMEM);
155
+                goto end;
156
+            }
157
+            alt_frame->width  = frame->width;
158
+            alt_frame->height = frame->height;
159
+            alt_frame->format = frame->format;
160
+            ret = av_frame_get_buffer(alt_frame, 32);
161
+            if (ret < 0)
162
+                goto end;
163
+            av_image_copy(alt_frame->data, alt_frame->linesize,
164
+                          frame->data, frame->linesize,
165
+                          avctx->pix_fmt, frame->width, frame->height);
166
+            frame = alt_frame;
167
+        }
168
+        pic->use_argb  = 0;
169
+        pic->y         = frame->data[0];
170
+        pic->u         = frame->data[1];
171
+        pic->v         = frame->data[2];
172
+        pic->y_stride  = frame->linesize[0];
173
+        pic->uv_stride = frame->linesize[1];
174
+        if (avctx->pix_fmt == AV_PIX_FMT_YUVA420P) {
175
+            pic->colorspace = WEBP_YUV420A;
176
+            pic->a          = frame->data[3];
177
+            pic->a_stride   = frame->linesize[3];
178
+        } else {
179
+            pic->colorspace = WEBP_YUV420;
180
+        }
181
+
182
+        if (s->lossless) {
183
+            /* We do not have a way to automatically prioritize RGB over YUV
184
+               in automatic pixel format conversion based on whether we're
185
+               encoding lossless or lossy, so we do conversion with libwebp as
186
+               a convenience. */
187
+            if (!s->conversion_warning) {
188
+                av_log(avctx, AV_LOG_WARNING,
189
+                       "Using libwebp for YUV-to-RGB conversion. You may want "
190
+                       "to consider passing in RGB instead for lossless "
191
+                       "encoding.\n");
192
+                s->conversion_warning = 1;
193
+            }
194
+
195
+#if (WEBP_ENCODER_ABI_VERSION <= 0x201)
196
+            /* libwebp should do the conversion automatically, but there is a
197
+               bug that causes it to return an error instead, so a work-around
198
+               is required.
199
+               See https://code.google.com/p/webp/issues/detail?id=178 */
200
+            pic->memory_ = (void*)1;  /* something non-null */
201
+            ret = WebPPictureYUVAToARGB(pic);
202
+            if (!ret) {
203
+                av_log(avctx, AV_LOG_ERROR,
204
+                       "WebPPictureYUVAToARGB() failed with error: %d\n",
205
+                       pic->error_code);
206
+                ret = libwebp_error_to_averror(pic->error_code);
207
+                goto end;
208
+            }
209
+            pic->memory_ = NULL;  /* restore pointer */
210
+#endif
211
+        }
212
+    }
213
+
214
+    WebPMemoryWriterInit(&mw);
215
+    pic->custom_ptr = &mw;
216
+    pic->writer     = WebPMemoryWrite;
217
+
218
+    ret = WebPEncode(&s->config, pic);
219
+    if (!ret) {
220
+        av_log(avctx, AV_LOG_ERROR, "WebPEncode() failed with error: %d\n",
221
+               pic->error_code);
222
+        ret = libwebp_error_to_averror(pic->error_code);
223
+        goto end;
224
+    }
225
+
226
+    ret = ff_alloc_packet(pkt, mw.size);
227
+    if (ret < 0)
228
+        goto end;
229
+    memcpy(pkt->data, mw.mem, mw.size);
230
+
231
+    pkt->flags |= AV_PKT_FLAG_KEY;
232
+    *got_packet = 1;
233
+
234
+end:
235
+    free(mw.mem); /* must use free() according to libwebp documentation */
236
+    WebPPictureFree(pic);
237
+    av_freep(&pic);
238
+    av_frame_free(&alt_frame);
239
+
240
+    return ret;
241
+}
242
+
243
+#define OFFSET(x) offsetof(LibWebPContext, x)
244
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
245
+static const AVOption options[] = {
246
+    { "lossless",   "Use lossless mode",       OFFSET(lossless), AV_OPT_TYPE_INT,   { .i64 =  0 },  0, 1,                           VE           },
247
+    { "preset",     "Configuration preset",    OFFSET(preset),   AV_OPT_TYPE_INT,   { .i64 = -1 }, -1, WEBP_PRESET_TEXT,            VE, "preset" },
248
+    { "none",       "do not use a preset",                              0, AV_OPT_TYPE_CONST, { .i64 = -1                  }, 0, 0, VE, "preset" },
249
+    { "default",    "default preset",                                   0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DEFAULT }, 0, 0, VE, "preset" },
250
+    { "picture",    "digital picture, like portrait, inner shot",       0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PICTURE }, 0, 0, VE, "preset" },
251
+    { "photo",      "outdoor photograph, with natural lighting",        0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PHOTO   }, 0, 0, VE, "preset" },
252
+    { "drawing",    "hand or line drawing, with high-contrast details", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DRAWING }, 0, 0, VE, "preset" },
253
+    { "icon",       "small-sized colorful images",                      0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_ICON    }, 0, 0, VE, "preset" },
254
+    { "text",       "text-like",                                        0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_TEXT    }, 0, 0, VE, "preset" },
255
+    { NULL },
256
+};
257
+
258
+static const AVClass class = {
259
+    .class_name = "libwebp",
260
+    .item_name  = av_default_item_name,
261
+    .option     = options,
262
+    .version    = LIBAVUTIL_VERSION_INT,
263
+};
264
+
265
+static const AVCodecDefault libwebp_defaults[] = {
266
+    { "compression_level",  "4"  },
267
+    { "global_quality",     "-1" },
268
+    { NULL },
269
+};
270
+
271
+AVCodec ff_libwebp_encoder = {
272
+    .name           = "libwebp",
273
+    .long_name      = NULL_IF_CONFIG_SMALL("libwebp WebP image"),
274
+    .type           = AVMEDIA_TYPE_VIDEO,
275
+    .id             = AV_CODEC_ID_WEBP,
276
+    .priv_data_size = sizeof(LibWebPContext),
277
+    .init           = libwebp_encode_init,
278
+    .encode2        = libwebp_encode_frame,
279
+    .pix_fmts       = (const enum AVPixelFormat[]) {
280
+        AV_PIX_FMT_RGB32,
281
+        AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P,
282
+        AV_PIX_FMT_NONE
283
+    },
284
+    .priv_class     = &class,
285
+    .defaults       = libwebp_defaults,
286
+};
... ...
@@ -29,8 +29,8 @@
29 29
 #include "libavutil/avutil.h"
30 30
 
31 31
 #define LIBAVCODEC_VERSION_MAJOR 55
32
-#define LIBAVCODEC_VERSION_MINOR  45
33
-#define LIBAVCODEC_VERSION_MICRO 103
32
+#define LIBAVCODEC_VERSION_MINOR  46
33
+#define LIBAVCODEC_VERSION_MICRO 100
34 34
 
35 35
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
36 36
                                                LIBAVCODEC_VERSION_MINOR, \
... ...
@@ -194,7 +194,7 @@ AVOutputFormat ff_image2_muxer = {
194 194
     .long_name      = NULL_IF_CONFIG_SMALL("image2 sequence"),
195 195
     .extensions     = "bmp,dpx,jls,jpeg,jpg,ljpg,pam,pbm,pcx,pgm,pgmyuv,png,"
196 196
                       "ppm,sgi,tga,tif,tiff,jp2,j2c,j2k,xwd,sun,ras,rs,im1,im8,im24,"
197
-                      "sunras,xbm,xface",
197
+                      "sunras,webp,xbm,xface",
198 198
     .priv_data_size = sizeof(VideoMuxData),
199 199
     .video_codec    = AV_CODEC_ID_MJPEG,
200 200
     .write_header   = write_header,