mirror of https://github.com/mpv-player/mpv
image_writer: add WebP support (lossy or lossless)
This commit is contained in:
parent
8925f10962
commit
0f79444c6d
|
@ -3319,6 +3319,7 @@ Screenshot
|
||||||
:png: PNG
|
:png: PNG
|
||||||
:jpg: JPEG (default)
|
:jpg: JPEG (default)
|
||||||
:jpeg: JPEG (alias for jpg)
|
:jpeg: JPEG (alias for jpg)
|
||||||
|
:webp: WebP
|
||||||
|
|
||||||
``--screenshot-tag-colorspace=<yes|no>``
|
``--screenshot-tag-colorspace=<yes|no>``
|
||||||
Tag screenshots with the appropriate colorspace.
|
Tag screenshots with the appropriate colorspace.
|
||||||
|
@ -3452,6 +3453,13 @@ Screenshot
|
||||||
of compression that can be achieved. For most images, "mixed" achieves the
|
of compression that can be achieved. For most images, "mixed" achieves the
|
||||||
best compression ratio, hence it is the default.
|
best compression ratio, hence it is the default.
|
||||||
|
|
||||||
|
``--screenshot-webp-lossless=<yes|no>``
|
||||||
|
Write lossless WebP files. ``--screenshot-webp-quality`` is ignored if this
|
||||||
|
is set. The default is no.
|
||||||
|
|
||||||
|
``--screenshot-webp-quality=<0-100>``
|
||||||
|
Set the WebP quality level. Higher means better quality. The default is 75.
|
||||||
|
|
||||||
|
|
||||||
Software Scaler
|
Software Scaler
|
||||||
---------------
|
---------------
|
||||||
|
|
|
@ -415,6 +415,8 @@ Available video output drivers are:
|
||||||
JPEG files, extension .jpeg.
|
JPEG files, extension .jpeg.
|
||||||
png
|
png
|
||||||
PNG files.
|
PNG files.
|
||||||
|
webp
|
||||||
|
WebP files.
|
||||||
|
|
||||||
``--vo-image-png-compression=<0-9>``
|
``--vo-image-png-compression=<0-9>``
|
||||||
PNG compression factor (speed vs. file size tradeoff) (default: 7)
|
PNG compression factor (speed vs. file size tradeoff) (default: 7)
|
||||||
|
@ -425,6 +427,10 @@ Available video output drivers are:
|
||||||
JPEG quality factor (default: 90)
|
JPEG quality factor (default: 90)
|
||||||
``--vo-image-jpeg-optimize=<0-100>``
|
``--vo-image-jpeg-optimize=<0-100>``
|
||||||
JPEG optimization factor (default: 100)
|
JPEG optimization factor (default: 100)
|
||||||
|
``--vo-image-webp-lossless=<yes|no>``
|
||||||
|
Enable writing lossless WebP files (default: no)
|
||||||
|
``--vo-image-webp-quality=<0-100>``
|
||||||
|
WebP quality (default: 75)
|
||||||
``--vo-image-outdir=<dirname>``
|
``--vo-image-outdir=<dirname>``
|
||||||
Specify the directory to save the image files to (default: ``./``).
|
Specify the directory to save the image files to (default: ``./``).
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,8 @@ const struct image_writer_opts image_writer_opts_defaults = {
|
||||||
.png_filter = 5,
|
.png_filter = 5,
|
||||||
.jpeg_quality = 90,
|
.jpeg_quality = 90,
|
||||||
.jpeg_source_chroma = 1,
|
.jpeg_source_chroma = 1,
|
||||||
|
.webp_lossless = 0,
|
||||||
|
.webp_quality = 75,
|
||||||
.tag_csp = 0,
|
.tag_csp = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -55,6 +57,7 @@ const struct m_opt_choice_alternatives mp_image_writer_formats[] = {
|
||||||
{"jpg", AV_CODEC_ID_MJPEG},
|
{"jpg", AV_CODEC_ID_MJPEG},
|
||||||
{"jpeg", AV_CODEC_ID_MJPEG},
|
{"jpeg", AV_CODEC_ID_MJPEG},
|
||||||
{"png", AV_CODEC_ID_PNG},
|
{"png", AV_CODEC_ID_PNG},
|
||||||
|
{"webp", AV_CODEC_ID_WEBP},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,6 +69,8 @@ const struct m_option image_writer_opts[] = {
|
||||||
OPT_FLAG("jpeg-source-chroma", jpeg_source_chroma, 0),
|
OPT_FLAG("jpeg-source-chroma", jpeg_source_chroma, 0),
|
||||||
OPT_INTRANGE("png-compression", png_compression, 0, 0, 9),
|
OPT_INTRANGE("png-compression", png_compression, 0, 0, 9),
|
||||||
OPT_INTRANGE("png-filter", png_filter, 0, 0, 5),
|
OPT_INTRANGE("png-filter", png_filter, 0, 0, 5),
|
||||||
|
OPT_FLAG("webp-lossless", webp_lossless, 0),
|
||||||
|
OPT_INTRANGE("webp-quality", webp_quality, 0, 0, 100),
|
||||||
OPT_FLAG("high-bit-depth", high_bit_depth, 0),
|
OPT_FLAG("high-bit-depth", high_bit_depth, 0),
|
||||||
OPT_FLAG("tag-colorspace", tag_csp, 0),
|
OPT_FLAG("tag-colorspace", tag_csp, 0),
|
||||||
{0},
|
{0},
|
||||||
|
@ -96,7 +101,13 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp
|
||||||
|
|
||||||
av_init_packet(&pkt);
|
av_init_packet(&pkt);
|
||||||
|
|
||||||
struct AVCodec *codec = avcodec_find_encoder(ctx->opts->format);
|
struct AVCodec *codec;
|
||||||
|
if (ctx->opts->format == AV_CODEC_ID_WEBP) {
|
||||||
|
codec = avcodec_find_encoder_by_name("libwebp"); // non-animated encoder
|
||||||
|
} else {
|
||||||
|
codec = avcodec_find_encoder(ctx->opts->format);
|
||||||
|
}
|
||||||
|
|
||||||
AVCodecContext *avctx = NULL;
|
AVCodecContext *avctx = NULL;
|
||||||
if (!codec)
|
if (!codec)
|
||||||
goto print_open_fail;
|
goto print_open_fail;
|
||||||
|
@ -109,9 +120,11 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp
|
||||||
avctx->height = image->h;
|
avctx->height = image->h;
|
||||||
avctx->color_range = mp_csp_levels_to_avcol_range(image->params.color.levels);
|
avctx->color_range = mp_csp_levels_to_avcol_range(image->params.color.levels);
|
||||||
avctx->pix_fmt = imgfmt2pixfmt(image->imgfmt);
|
avctx->pix_fmt = imgfmt2pixfmt(image->imgfmt);
|
||||||
// Annoying deprecated garbage for the jpg encoder.
|
if (codec->id == AV_CODEC_ID_MJPEG) {
|
||||||
if (image->params.color.levels == MP_CSP_LEVELS_PC)
|
// Annoying deprecated garbage for the jpg encoder.
|
||||||
avctx->pix_fmt = replace_j_format(avctx->pix_fmt);
|
if (image->params.color.levels == MP_CSP_LEVELS_PC)
|
||||||
|
avctx->pix_fmt = replace_j_format(avctx->pix_fmt);
|
||||||
|
}
|
||||||
if (avctx->pix_fmt == AV_PIX_FMT_NONE) {
|
if (avctx->pix_fmt == AV_PIX_FMT_NONE) {
|
||||||
MP_ERR(ctx, "Image format %s not supported by lavc.\n",
|
MP_ERR(ctx, "Image format %s not supported by lavc.\n",
|
||||||
mp_imgfmt_to_name(image->imgfmt));
|
mp_imgfmt_to_name(image->imgfmt));
|
||||||
|
@ -121,6 +134,11 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp
|
||||||
avctx->compression_level = ctx->opts->png_compression;
|
avctx->compression_level = ctx->opts->png_compression;
|
||||||
av_opt_set_int(avctx, "pred", ctx->opts->png_filter,
|
av_opt_set_int(avctx, "pred", ctx->opts->png_filter,
|
||||||
AV_OPT_SEARCH_CHILDREN);
|
AV_OPT_SEARCH_CHILDREN);
|
||||||
|
} else if (codec->id == AV_CODEC_ID_WEBP) {
|
||||||
|
av_opt_set_int(avctx, "lossless", ctx->opts->webp_lossless,
|
||||||
|
AV_OPT_SEARCH_CHILDREN);
|
||||||
|
av_opt_set_int(avctx, "quality", ctx->opts->webp_quality,
|
||||||
|
AV_OPT_SEARCH_CHILDREN);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avcodec_open2(avctx, codec, NULL) < 0) {
|
if (avcodec_open2(avctx, codec, NULL) < 0) {
|
||||||
|
@ -292,6 +310,7 @@ int image_writer_format_from_ext(const char *ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct mp_image *convert_image(struct mp_image *image, int destfmt,
|
static struct mp_image *convert_image(struct mp_image *image, int destfmt,
|
||||||
|
enum mp_csp_levels yuv_levels,
|
||||||
struct mp_log *log)
|
struct mp_log *log)
|
||||||
{
|
{
|
||||||
int d_w, d_h;
|
int d_w, d_h;
|
||||||
|
@ -308,9 +327,9 @@ static struct mp_image *convert_image(struct mp_image *image, int destfmt,
|
||||||
|
|
||||||
// If RGB, just assume everything is correct.
|
// If RGB, just assume everything is correct.
|
||||||
if (p.color.space != MP_CSP_RGB) {
|
if (p.color.space != MP_CSP_RGB) {
|
||||||
// Currently, assume what FFmpeg's jpg encoder needs.
|
// Currently, assume what FFmpeg's jpg encoder or libwebp needs.
|
||||||
// Of course this works only for non-HDR (no HDR support in libswscale).
|
// Of course this works only for non-HDR (no HDR support in libswscale).
|
||||||
p.color.levels = MP_CSP_LEVELS_PC;
|
p.color.levels = yuv_levels;
|
||||||
p.color.space = MP_CSP_BT_601;
|
p.color.space = MP_CSP_BT_601;
|
||||||
p.chroma_location = MP_CHROMA_CENTER;
|
p.chroma_location = MP_CHROMA_CENTER;
|
||||||
mp_image_params_guess_csp(&p);
|
mp_image_params_guess_csp(&p);
|
||||||
|
@ -354,11 +373,24 @@ bool write_image(struct mp_image *image, const struct image_writer_opts *opts,
|
||||||
destfmt = IMGFMT_RGB24;
|
destfmt = IMGFMT_RGB24;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (opts->format == AV_CODEC_ID_WEBP && !opts->webp_lossless) {
|
||||||
|
// For lossy images, libwebp has its own RGB->YUV conversion.
|
||||||
|
// We don't want that, so force YUV/YUVA here.
|
||||||
|
int alpha = image->fmt.flags & MP_IMGFLAG_ALPHA;
|
||||||
|
destfmt = alpha ? pixfmt2imgfmt(AV_PIX_FMT_YUVA420P) : IMGFMT_420P;
|
||||||
|
}
|
||||||
|
|
||||||
if (!destfmt)
|
if (!destfmt)
|
||||||
destfmt = get_target_format(&ctx);
|
destfmt = get_target_format(&ctx);
|
||||||
|
|
||||||
struct mp_image *dst = convert_image(image, destfmt, log);
|
enum mp_csp_levels levels; // Ignored if destfmt is a RGB format
|
||||||
|
if (opts->format == AV_CODEC_ID_WEBP) {
|
||||||
|
levels = MP_CSP_LEVELS_TV;
|
||||||
|
} else {
|
||||||
|
levels = MP_CSP_LEVELS_PC;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mp_image *dst = convert_image(image, destfmt, levels, log);
|
||||||
if (!dst)
|
if (!dst)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ struct image_writer_opts {
|
||||||
int jpeg_progressive;
|
int jpeg_progressive;
|
||||||
int jpeg_baseline;
|
int jpeg_baseline;
|
||||||
int jpeg_source_chroma;
|
int jpeg_source_chroma;
|
||||||
|
int webp_lossless;
|
||||||
|
int webp_quality;
|
||||||
int tag_csp;
|
int tag_csp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue