1 /*
2 * WebP encoding support via libwebp
3 * Copyright (c) 2013 Justin Ruggles <justin.ruggles@gmail.com>
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 /**
23 * @file
24 * WebP encoder using libwebp
25 */
26
27 #include <webp/encode.h>
28
35
43 WebPConfig
config;
// libwebp configuration
45
47 {
48 switch (err) {
49 case VP8_ENC_ERROR_OUT_OF_MEMORY:
50 case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
52 case VP8_ENC_ERROR_NULL_PARAMETER:
53 case VP8_ENC_ERROR_INVALID_CONFIGURATION:
54 case VP8_ENC_ERROR_BAD_DIMENSION:
56 }
58 }
59
61 {
64
68 0.0f, 100.0f);
69
74 }
75
76 if (s->
preset >= WEBP_PRESET_DEFAULT) {
78 if (!ret)
83 } else {
84 ret = WebPConfigInit(&s->
config);
85 if (!ret)
87
91
92 ret = WebPValidateConfig(&s->
config);
93 if (!ret)
95 }
96
100
101 return 0;
102 }
103
106 {
109 WebPPicture *pic = NULL;
110 WebPMemoryWriter mw = { 0 };
112
113 if (avctx->
width > WEBP_MAX_DIMENSION || avctx->
height > WEBP_MAX_DIMENSION) {
115 WEBP_MAX_DIMENSION, WEBP_MAX_DIMENSION);
117 }
118
120 if (!pic)
122
123 ret = WebPPictureInit(pic);
124 if (!ret) {
127 }
128 pic->width = avctx->
width;
129 pic->height = avctx->
height;
130
133 /* libwebp will automatically convert RGB input to YUV when
134 encoding lossy. */
137 "Using libwebp for RGB-to-YUV conversion. You may want "
138 "to consider passing in YUV instead for lossy "
139 "encoding.\n");
141 }
142 }
143 pic->use_argb = 1;
144 pic->argb = (uint32_t *)frame->
data[0];
145 pic->argb_stride = frame->
linesize[0] / 4;
146 } else {
150 "Copying frame due to differing chroma linesizes.\n");
152 }
154 if (!alt_frame) {
157 }
162 if (ret < 0)
165 frame = alt_frame;
166 }
167 pic->use_argb = 0;
168 pic->y = frame->
data[0];
169 pic->u = frame->
data[1];
170 pic->v = frame->
data[2];
172 pic->uv_stride = frame->
linesize[1];
174 pic->colorspace = WEBP_YUV420A;
175 pic->a = frame->
data[3];
177 } else {
178 pic->colorspace = WEBP_YUV420;
179 }
180
182 /* We do not have a way to automatically prioritize RGB over YUV
183 in automatic pixel format conversion based on whether we're
184 encoding lossless or lossy, so we do conversion with libwebp as
185 a convenience. */
188 "Using libwebp for YUV-to-RGB conversion. You may want "
189 "to consider passing in RGB instead for lossless "
190 "encoding.\n");
192 }
193
194 #if (WEBP_ENCODER_ABI_VERSION <= 0x201)
195 /* libwebp should do the conversion automatically, but there is a
196 bug that causes it to return an error instead, so a work-around
197 is required.
198 See https://code.google.com/p/webp/issues/detail?id=178 */
199 pic->memory_ = (void*)1; /* something non-null */
200 ret = WebPPictureYUVAToARGB(pic);
201 if (!ret) {
203 "WebPPictureYUVAToARGB() failed with error: %d\n",
204 pic->error_code);
207 }
208 pic->memory_ = NULL; /* restore pointer */
209 #endif
210 }
211 }
212
213 WebPMemoryWriterInit(&mw);
214 pic->custom_ptr = &mw;
215 pic->writer = WebPMemoryWrite;
216
217 ret = WebPEncode(&s->
config, pic);
218 if (!ret) {
220 pic->error_code);
223 }
224
226 if (ret < 0)
228 memcpy(pkt->
data, mw.mem, mw.size);
229
231 *got_packet = 1;
232
234 #if (WEBP_ENCODER_ABI_VERSION > 0x0203)
235 WebPMemoryWriterClear(&mw);
236 #else
237 free(mw.mem); /* must use free() according to libwebp documentation */
238 #endif
239 WebPPictureFree(pic);
242
244 }
245
246 #define OFFSET(x) offsetof(LibWebPContext, x)
247 #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
251 {
"none",
"do not use a preset", 0,
AV_OPT_TYPE_CONST, { .i64 = -1 }, 0, 0,
VE,
"preset" },
252 {
"default",
"default preset", 0,
AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DEFAULT }, 0, 0,
VE,
"preset" },
253 {
"picture",
"digital picture, like portrait, inner shot", 0,
AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PICTURE }, 0, 0,
VE,
"preset" },
254 {
"photo",
"outdoor photograph, with natural lighting", 0,
AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PHOTO }, 0, 0,
VE,
"preset" },
255 {
"drawing",
"hand or line drawing, with high-contrast details", 0,
AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DRAWING }, 0, 0,
VE,
"preset" },
256 {
"icon",
"small-sized colorful images", 0,
AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_ICON }, 0, 0,
VE,
"preset" },
257 {
"text",
"text-like", 0,
AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_TEXT }, 0, 0,
VE,
"preset" },
258 { NULL },
259 };
260
266 };
267
269 { "compression_level", "4" },
270 { "global_quality", "-1" },
271 { NULL },
272 };
273
286 },
287 .priv_class = &class,
289 };