aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2013-12-22 11:53:41 +0100
committerMichael Niedermayer <michaelni@gmx.at>2013-12-22 11:53:41 +0100
commit6fe5f770db3ac2a5fb77d2f3bb4eb977be440bbd (patch)
tree6d894ef0fb24a5394ce4341e2404d6668f8d23f1
parent9b195dd5793edb88a72d53cb080c2216e91a5849 (diff)
parentbe7c323176e2e5fcf30e3d2ff20975b2f936811b (diff)
downloadffmpeg-6fe5f770db3ac2a5fb77d2f3bb4eb977be440bbd.tar.gz
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>
-rw-r--r--Changelog1
-rwxr-xr-xconfigure4
-rw-r--r--doc/encoders.texi62
-rw-r--r--doc/general.texi4
-rw-r--r--libavcodec/Makefile1
-rw-r--r--libavcodec/allcodecs.c1
-rw-r--r--libavcodec/libwebpenc.c287
-rw-r--r--libavcodec/version.h4
-rw-r--r--libavformat/img2enc.c2
9 files changed, 361 insertions, 5 deletions
diff --git a/Changelog b/Changelog
index 494feb5b64..dd68a01980 100644
--- a/Changelog
+++ b/Changelog
@@ -14,6 +14,7 @@ version <next>
- Windows resource files for shared libraries
- aeval filter
- stereoscopic 3d metadata handling
+- WebP encoding via libwebp
version 2.1:
diff --git a/configure b/configure
index 5f0d8b995d..c7bb778054 100755
--- a/configure
+++ b/configure
@@ -241,6 +241,7 @@ External library support:
native implementation exists [no]
--enable-libvpx enable VP8 and VP9 de/encoding via libvpx [no]
--enable-libwavpack enable wavpack encoding via libwavpack [no]
+ --enable-libwebp enable WebP encoding via libwebp [no]
--enable-libx264 enable H.264 encoding via x264 [no]
--enable-libxavs enable AVS encoding via xavs [no]
--enable-libxvid enable Xvid encoding via xvidcore,
@@ -1290,6 +1291,7 @@ EXTERNAL_LIBRARY_LIST="
libvorbis
libvpx
libwavpack
+ libwebp
libx264
libxavs
libxvid
@@ -2145,6 +2147,7 @@ libvpx_vp8_encoder_deps="libvpx"
libvpx_vp9_decoder_deps="libvpx"
libvpx_vp9_encoder_deps="libvpx"
libwavpack_encoder_deps="libwavpack"
+libwebp_encoder_deps="libwebp"
libx264_encoder_deps="libx264"
libx264rgb_encoder_deps="libx264"
libxavs_encoder_deps="libxavs"
@@ -4437,6 +4440,7 @@ enabled libvpx && {
enabled libvpx_vp9_decoder && { check_lib2 "vpx/vpx_decoder.h vpx/vp8dx.h" "vpx_codec_vp9_dx" -lvpx || disable libvpx_vp9_decoder; }
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; } }
enabled libwavpack && require libwavpack wavpack/wavpack.h WavpackOpenFileOutput -lwavpack
+enabled libwebp && require_pkg_config libwebp webp/encode.h WebPGetEncoderVersion
enabled libx264 && require libx264 x264.h x264_encoder_encode -lx264 &&
{ check_cpp_condition x264.h "X264_BUILD >= 118" ||
die "ERROR: libx264 must be installed and version must be >= 0.118."; }
diff --git a/doc/encoders.texi b/doc/encoders.texi
index a93edb4b93..ea5b3e4165 100644
--- a/doc/encoders.texi
+++ b/doc/encoders.texi
@@ -1365,6 +1365,68 @@ g_error_resilient
For more information about libvpx see:
@url{http://www.webmproject.org/}
+
+@section libwebp
+
+libwebp WebP Image encoder wrapper
+
+libwebp is Google's official encoder for WebP images. It can encode in either
+lossy or lossless mode. Lossy images are essentially a wrapper around a VP8
+frame. Lossless images are a separate codec developed by Google.
+
+@subsection Pixel Format
+
+Currently, libwebp only supports YUV420 for lossy and RGB for lossless due
+to limitations of the format and libwebp. Alpha is supported for either mode.
+Because of API limitations, if RGB is passed in when encoding lossy or YUV is
+passed in for encoding lossless, the pixel format will automatically be
+converted using functions from libwebp. This is not ideal and is done only for
+convenience.
+
+@subsection Options
+
+@table @option
+
+@item -lossless @var{boolean}
+Enables/Disables use of lossless mode. Default is 0.
+
+@item -compression_level @var{integer}
+For lossy, this is a quality/speed tradeoff. Higher values give better quality
+for a given size at the cost of increased encoding time. For lossless, this is
+a size/speed tradeoff. Higher values give smaller size at the cost of increased
+encoding time. More specifically, it controls the number of extra algorithms
+and compression tools used, and varies the combination of these tools. This
+maps to the @var{method} option in libwebp. The valid range is 0 to 6.
+Default is 4.
+
+@item -qscale @var{float}
+For lossy encoding, this controls image quality, 0 to 100. For lossless
+encoding, this controls the effort and time spent at compressing more. The
+default value is 75. Note that for usage via libavcodec, this option is called
+@var{global_quality} and must be multiplied by @var{FF_QP2LAMBDA}.
+
+@item -preset @var{type}
+Configuration preset. This does some automatic settings based on the general
+type of the image.
+@table @option
+@item none
+Do not use a preset.
+@item default
+Use the encoder default.
+@item picture
+Digital picture, like portrait, inner shot
+@item photo
+Outdoor photograph, with natural lighting
+@item drawing
+Hand or line drawing, with high-contrast details
+@item icon
+Small-sized colorful images
+@item text
+Text-like
+@end table
+
+@end table
+
@section libx264
x264 H.264/MPEG-4 AVC encoder wrapper.
diff --git a/doc/general.texi b/doc/general.texi
index a3221d54fb..0ac6455979 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -491,8 +491,8 @@ following image formats are supported:
@tab YUV, JPEG and some extension is not supported yet.
@item Truevision Targa @tab X @tab X
@tab Targa (.TGA) image format
-@item WebP @tab @tab X
- @tab WebP image format
+@item WebP @tab E @tab X
+ @tab WebP image format, encoding supported through external library libwebp
@item XBM @tab X @tab X
@tab X BitMap image format
@item XFace @tab X @tab X
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 4ce11f16bb..fbcc576735 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -734,6 +734,7 @@ OBJS-$(CONFIG_LIBVPX_VP8_ENCODER) += libvpxenc.o
OBJS-$(CONFIG_LIBVPX_VP9_DECODER) += libvpxdec.o libvpx.o
OBJS-$(CONFIG_LIBVPX_VP9_ENCODER) += libvpxenc.o libvpx.o
OBJS-$(CONFIG_LIBWAVPACK_ENCODER) += libwavpackenc.o
+OBJS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc.o
OBJS-$(CONFIG_LIBX264_ENCODER) += libx264.o
OBJS-$(CONFIG_LIBXAVS_ENCODER) += libxavs.o
OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvid.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 6d084acb64..ffa828baf0 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -509,6 +509,7 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (LIBVPX_VP8, libvpx_vp8);
REGISTER_ENCDEC (LIBVPX_VP9, libvpx_vp9);
REGISTER_ENCODER(LIBWAVPACK, libwavpack);
+ REGISTER_ENCODER(LIBWEBP, libwebp);
REGISTER_ENCODER(LIBX264, libx264);
REGISTER_ENCODER(LIBX264RGB, libx264rgb);
REGISTER_ENCODER(LIBXAVS, libxavs);
diff --git a/libavcodec/libwebpenc.c b/libavcodec/libwebpenc.c
new file mode 100644
index 0000000000..5e0c7a8236
--- /dev/null
+++ b/libavcodec/libwebpenc.c
@@ -0,0 +1,287 @@
+/*
+ * WebP encoding support via libwebp
+ * Copyright (c) 2013 Justin Ruggles <justin.ruggles@gmail.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * WebP encoder using libwebp
+ */
+
+#include <webp/encode.h>
+
+#include "libavutil/common.h"
+#include "libavutil/frame.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "avcodec.h"
+#include "internal.h"
+
+typedef struct LibWebPContext {
+ AVClass *class; // class for AVOptions
+ float quality; // lossy quality 0 - 100
+ int lossless; // use lossless encoding
+ int preset; // configuration preset
+ int chroma_warning; // chroma linesize mismatch warning has been printed
+ int conversion_warning; // pixel format conversion warning has been printed
+ WebPConfig config; // libwebp configuration
+} LibWebPContext;
+
+static int libwebp_error_to_averror(int err)
+{
+ switch (err) {
+ case VP8_ENC_ERROR_OUT_OF_MEMORY:
+ case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
+ return AVERROR(ENOMEM);
+ case VP8_ENC_ERROR_NULL_PARAMETER:
+ case VP8_ENC_ERROR_INVALID_CONFIGURATION:
+ case VP8_ENC_ERROR_BAD_DIMENSION:
+ return AVERROR(EINVAL);
+ }
+ return AVERROR_UNKNOWN;
+}
+
+static av_cold int libwebp_encode_init(AVCodecContext *avctx)
+{
+ LibWebPContext *s = avctx->priv_data;
+ int ret;
+
+ if (avctx->global_quality < 0)
+ avctx->global_quality = 75 * FF_QP2LAMBDA;
+ s->quality = av_clipf(avctx->global_quality / (float)FF_QP2LAMBDA,
+ 0.0f, 100.0f);
+
+ if (avctx->compression_level < 0 || avctx->compression_level > 6) {
+ av_log(avctx, AV_LOG_WARNING, "invalid compression level: %d\n",
+ avctx->compression_level);
+ avctx->compression_level = av_clip(avctx->compression_level, 0, 6);
+ }
+
+ if (s->preset >= WEBP_PRESET_DEFAULT) {
+ ret = WebPConfigPreset(&s->config, s->preset, s->quality);
+ if (!ret)
+ return AVERROR_UNKNOWN;
+ s->lossless = s->config.lossless;
+ s->quality = s->config.quality;
+ avctx->compression_level = s->config.method;
+ } else {
+ ret = WebPConfigInit(&s->config);
+ if (!ret)
+ return AVERROR_UNKNOWN;
+
+ s->config.lossless = s->lossless;
+ s->config.quality = s->quality;
+ s->config.method = avctx->compression_level;
+
+ ret = WebPValidateConfig(&s->config);
+ if (!ret)
+ return AVERROR(EINVAL);
+ }
+
+ av_log(avctx, AV_LOG_DEBUG, "%s - quality=%.1f method=%d\n",
+ s->lossless ? "Lossless" : "Lossy", s->quality,
+ avctx->compression_level);
+
+ return 0;
+}
+
+static int libwebp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *frame, int *got_packet)
+{
+ LibWebPContext *s = avctx->priv_data;
+ AVFrame *alt_frame = NULL;
+ WebPPicture *pic = NULL;
+ WebPMemoryWriter mw = { 0 };
+ int ret;
+
+ if (avctx->width > WEBP_MAX_DIMENSION || avctx->height > WEBP_MAX_DIMENSION) {
+ av_log(avctx, AV_LOG_ERROR, "Picture size is too large. Max is %dx%d.\n",
+ WEBP_MAX_DIMENSION, WEBP_MAX_DIMENSION);
+ return AVERROR(EINVAL);
+ }
+
+ pic = av_malloc(sizeof(*pic));
+ if (!pic)
+ return AVERROR(ENOMEM);
+
+ ret = WebPPictureInit(pic);
+ if (!ret) {
+ ret = AVERROR_UNKNOWN;
+ goto end;
+ }
+ pic->width = avctx->width;
+ pic->height = avctx->height;
+
+ if (avctx->pix_fmt == AV_PIX_FMT_RGB32) {
+ if (!s->lossless) {
+ /* libwebp will automatically convert RGB input to YUV when
+ encoding lossy. */
+ if (!s->conversion_warning) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Using libwebp for RGB-to-YUV conversion. You may want "
+ "to consider passing in YUV instead for lossy "
+ "encoding.\n");
+ s->conversion_warning = 1;
+ }
+ }
+ pic->use_argb = 1;
+ pic->argb = (uint32_t *)frame->data[0];
+ pic->argb_stride = frame->linesize[0] / 4;
+ } else {
+ if (frame->linesize[1] != frame->linesize[2]) {
+ if (!s->chroma_warning) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Copying frame due to differing chroma linesizes.\n");
+ s->chroma_warning = 1;
+ }
+ alt_frame = av_frame_alloc();
+ if (!alt_frame) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ alt_frame->width = frame->width;
+ alt_frame->height = frame->height;
+ alt_frame->format = frame->format;
+ ret = av_frame_get_buffer(alt_frame, 32);
+ if (ret < 0)
+ goto end;
+ av_image_copy(alt_frame->data, alt_frame->linesize,
+ frame->data, frame->linesize,
+ avctx->pix_fmt, frame->width, frame->height);
+ frame = alt_frame;
+ }
+ pic->use_argb = 0;
+ pic->y = frame->data[0];
+ pic->u = frame->data[1];
+ pic->v = frame->data[2];
+ pic->y_stride = frame->linesize[0];
+ pic->uv_stride = frame->linesize[1];
+ if (avctx->pix_fmt == AV_PIX_FMT_YUVA420P) {
+ pic->colorspace = WEBP_YUV420A;
+ pic->a = frame->data[3];
+ pic->a_stride = frame->linesize[3];
+ } else {
+ pic->colorspace = WEBP_YUV420;
+ }
+
+ if (s->lossless) {
+ /* We do not have a way to automatically prioritize RGB over YUV
+ in automatic pixel format conversion based on whether we're
+ encoding lossless or lossy, so we do conversion with libwebp as
+ a convenience. */
+ if (!s->conversion_warning) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Using libwebp for YUV-to-RGB conversion. You may want "
+ "to consider passing in RGB instead for lossless "
+ "encoding.\n");
+ s->conversion_warning = 1;
+ }
+
+#if (WEBP_ENCODER_ABI_VERSION <= 0x201)
+ /* libwebp should do the conversion automatically, but there is a
+ bug that causes it to return an error instead, so a work-around
+ is required.
+ See https://code.google.com/p/webp/issues/detail?id=178 */
+ pic->memory_ = (void*)1; /* something non-null */
+ ret = WebPPictureYUVAToARGB(pic);
+ if (!ret) {
+ av_log(avctx, AV_LOG_ERROR,
+ "WebPPictureYUVAToARGB() failed with error: %d\n",
+ pic->error_code);
+ ret = libwebp_error_to_averror(pic->error_code);
+ goto end;
+ }
+ pic->memory_ = NULL; /* restore pointer */
+#endif
+ }
+ }
+
+ WebPMemoryWriterInit(&mw);
+ pic->custom_ptr = &mw;
+ pic->writer = WebPMemoryWrite;
+
+ ret = WebPEncode(&s->config, pic);
+ if (!ret) {
+ av_log(avctx, AV_LOG_ERROR, "WebPEncode() failed with error: %d\n",
+ pic->error_code);
+ ret = libwebp_error_to_averror(pic->error_code);
+ goto end;
+ }
+
+ ret = ff_alloc_packet(pkt, mw.size);
+ if (ret < 0)
+ goto end;
+ memcpy(pkt->data, mw.mem, mw.size);
+
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+
+end:
+ free(mw.mem); /* must use free() according to libwebp documentation */
+ WebPPictureFree(pic);
+ av_freep(&pic);
+ av_frame_free(&alt_frame);
+
+ return ret;
+}
+
+#define OFFSET(x) offsetof(LibWebPContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "lossless", "Use lossless mode", OFFSET(lossless), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
+ { "preset", "Configuration preset", OFFSET(preset), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, WEBP_PRESET_TEXT, VE, "preset" },
+ { "none", "do not use a preset", 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, 0, 0, VE, "preset" },
+ { "default", "default preset", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DEFAULT }, 0, 0, VE, "preset" },
+ { "picture", "digital picture, like portrait, inner shot", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PICTURE }, 0, 0, VE, "preset" },
+ { "photo", "outdoor photograph, with natural lighting", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PHOTO }, 0, 0, VE, "preset" },
+ { "drawing", "hand or line drawing, with high-contrast details", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DRAWING }, 0, 0, VE, "preset" },
+ { "icon", "small-sized colorful images", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_ICON }, 0, 0, VE, "preset" },
+ { "text", "text-like", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_TEXT }, 0, 0, VE, "preset" },
+ { NULL },
+};
+
+static const AVClass class = {
+ .class_name = "libwebp",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static const AVCodecDefault libwebp_defaults[] = {
+ { "compression_level", "4" },
+ { "global_quality", "-1" },
+ { NULL },
+};
+
+AVCodec ff_libwebp_encoder = {
+ .name = "libwebp",
+ .long_name = NULL_IF_CONFIG_SMALL("libwebp WebP image"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_WEBP,
+ .priv_data_size = sizeof(LibWebPContext),
+ .init = libwebp_encode_init,
+ .encode2 = libwebp_encode_frame,
+ .pix_fmts = (const enum AVPixelFormat[]) {
+ AV_PIX_FMT_RGB32,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_NONE
+ },
+ .priv_class = &class,
+ .defaults = libwebp_defaults,
+};
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 1993fa60c0..0d75976bd6 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,8 +29,8 @@
#include "libavutil/avutil.h"
#define LIBAVCODEC_VERSION_MAJOR 55
-#define LIBAVCODEC_VERSION_MINOR 45
-#define LIBAVCODEC_VERSION_MICRO 103
+#define LIBAVCODEC_VERSION_MINOR 46
+#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \
diff --git a/libavformat/img2enc.c b/libavformat/img2enc.c
index 3529e12c55..f61b0ca30b 100644
--- a/libavformat/img2enc.c
+++ b/libavformat/img2enc.c
@@ -194,7 +194,7 @@ AVOutputFormat ff_image2_muxer = {
.long_name = NULL_IF_CONFIG_SMALL("image2 sequence"),
.extensions = "bmp,dpx,jls,jpeg,jpg,ljpg,pam,pbm,pcx,pgm,pgmyuv,png,"
"ppm,sgi,tga,tif,tiff,jp2,j2c,j2k,xwd,sun,ras,rs,im1,im8,im24,"
- "sunras,xbm,xface",
+ "sunras,webp,xbm,xface",
.priv_data_size = sizeof(VideoMuxData),
.video_codec = AV_CODEC_ID_MJPEG,
.write_header = write_header,