summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-03-18 15:03:05 +0100
committerwm4 <wm4@nowhere>2017-03-18 15:03:05 +0100
commit46e3dc27af20492dd24d228781b895f25abc3438 (patch)
tree78309b4845a627e9f5302b904157e8f911211d81
parent8e75297c269a2679a5d1683d7d7cb745aba40182 (diff)
downloadmpv-46e3dc27af20492dd24d228781b895f25abc3438.tar.bz2
mpv-46e3dc27af20492dd24d228781b895f25abc3438.tar.xz
screenshot: change details of --screenshot-format handling
This is just a pointless refactor with the only goal of making image_writer_opts.format a number. The pointless part of it is that instead of using some sort of arbitrary ID (in place of a file extension string), we use a AV_CODEC_ID_. There was also some idea of falling back to the libavcodec MJPEG encoder if mpv was not linked against libjpeg, but this fails. libavcodec insist on having AV_PIX_FMT_YUVJ420P, which we pretend does not exist, and which we always map to AV_PIX_FMT_YUV420P (without the J indicating full range), so encoder init fails. This is pretty dumb, but whatever. The not-caring factor is raised by the fact that we don't know that we should convert to full range, because encoders have no proper way to signal this. (Be reminded that AV_PIX_FMT_YUVJ420P is deprecated.)
-rw-r--r--DOCS/interface-changes.rst1
-rw-r--r--DOCS/man/options.rst2
-rw-r--r--player/screenshot.c5
-rw-r--r--video/image_writer.c86
-rw-r--r--video/image_writer.h5
5 files changed, 50 insertions, 49 deletions
diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst
index 76c8e5f596..c82b0a62d0 100644
--- a/DOCS/interface-changes.rst
+++ b/DOCS/interface-changes.rst
@@ -24,6 +24,7 @@ Interface changes
(see git "vo_opengl: remove dxva2 dummy hwdec backend")
- remove ppm, pgm, pgmyuv, tga choices from the --screenshot-format and
--vo-image-format options
+ - the "jpeg" choice in the option above now leads to a ".jpg" file extension
--- mpv 0.24.0 ---
- deprecate --hwdec-api and replace it with --opengl-hwdec-interop.
The new option accepts both --hwdec values, as well as named backends.
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index 469ed29c44..4ee702df61 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -3108,7 +3108,7 @@ Screenshot
:png: PNG
:jpg: JPEG (default)
- :jpeg: JPEG (same as jpg, but with .jpeg file ending)
+ :jpeg: JPEG (alias for jpg)
``--screenshot-tag-colorspace=<yes|no>``
Tag screenshots with the appropriate colorspace.
diff --git a/player/screenshot.c b/player/screenshot.c
index dc3cca3d33..b5bd5ea787 100644
--- a/player/screenshot.c
+++ b/player/screenshot.c
@@ -384,8 +384,9 @@ void screenshot_to_file(struct MPContext *mpctx, const char *filename, int mode,
ctx->osd = osd;
char *ext = mp_splitext(filename, NULL);
- if (ext)
- opts.format = ext;
+ int format = image_writer_format_from_ext(ext);
+ if (format)
+ opts.format = format;
struct mp_image *image = screenshot_get(mpctx, mode);
if (!image) {
screenshot_msg(ctx, SMSG_ERR, "Taking screenshot failed.");
diff --git a/video/image_writer.c b/video/image_writer.c
index 3c280f278d..eda02bef81 100644
--- a/video/image_writer.c
+++ b/video/image_writer.c
@@ -42,7 +42,7 @@
#include "options/m_option.h"
const struct image_writer_opts image_writer_opts_defaults = {
- .format = "jpg",
+ .format = AV_CODEC_ID_MJPEG,
.high_bit_depth = 1,
.png_compression = 7,
.png_filter = 5,
@@ -52,15 +52,22 @@ const struct image_writer_opts image_writer_opts_defaults = {
.tag_csp = 0,
};
+const struct m_opt_choice_alternatives mp_image_writer_formats[] = {
+ {"jpg", AV_CODEC_ID_MJPEG},
+ {"jpeg", AV_CODEC_ID_MJPEG},
+ {"png", AV_CODEC_ID_PNG},
+ {0}
+};
+
#define OPT_BASE_STRUCT struct image_writer_opts
const struct m_option image_writer_opts[] = {
+ OPT_CHOICE_C("format", format, 0, mp_image_writer_formats),
OPT_INTRANGE("jpeg-quality", jpeg_quality, 0, 0, 100),
OPT_INTRANGE("jpeg-smooth", jpeg_smooth, 0, 0, 100),
OPT_FLAG("jpeg-source-chroma", jpeg_source_chroma, 0),
OPT_INTRANGE("png-compression", png_compression, 0, 0, 9),
OPT_INTRANGE("png-filter", png_filter, 0, 0, 5),
- OPT_STRING("format", format, 0),
OPT_FLAG("high-bit-depth", high_bit_depth, 0),
OPT_FLAG("tag-colorspace", tag_csp, 0),
{0},
@@ -69,17 +76,9 @@ const struct m_option image_writer_opts[] = {
struct image_writer_ctx {
struct mp_log *log;
const struct image_writer_opts *opts;
- const struct img_writer *writer;
struct mp_imgfmt_desc original_format;
};
-struct img_writer {
- const char *file_ext;
- bool (*write)(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp);
- const int *pixfmts;
- int lavc_codec;
-};
-
static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp)
{
bool success = 0;
@@ -89,7 +88,7 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp
av_init_packet(&pkt);
- struct AVCodec *codec = avcodec_find_encoder(ctx->writer->lavc_codec);
+ struct AVCodec *codec = avcodec_find_encoder(ctx->opts->format);
AVCodecContext *avctx = NULL;
if (!codec)
goto print_open_fail;
@@ -106,7 +105,7 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp
mp_imgfmt_to_name(image->imgfmt));
goto error_exit;
}
- if (ctx->writer->lavc_codec == AV_CODEC_ID_PNG) {
+ if (codec->id == AV_CODEC_ID_PNG) {
avctx->compression_level = ctx->opts->png_compression;
av_opt_set_int(avctx, "pred", ctx->opts->png_filter,
AV_OPT_SEARCH_CHILDREN);
@@ -237,15 +236,14 @@ static int get_encoder_format(struct AVCodec *codec, int srcfmt, bool highdepth)
return current;
}
-static int get_target_format(struct image_writer_ctx *ctx, int srcfmt)
+static int get_target_format(struct image_writer_ctx *ctx)
{
- if (!ctx->writer->lavc_codec)
- goto unknown;
-
- struct AVCodec *codec = avcodec_find_encoder(ctx->writer->lavc_codec);
+ struct AVCodec *codec = avcodec_find_encoder(ctx->opts->format);
if (!codec)
goto unknown;
+ int srcfmt = ctx->original_format.id;
+
int target = get_encoder_format(codec, srcfmt, ctx->opts->high_bit_depth);
if (!target)
target = get_encoder_format(codec, srcfmt, true);
@@ -256,28 +254,7 @@ static int get_target_format(struct image_writer_ctx *ctx, int srcfmt)
return target;
unknown:
- return IMGFMT_RGB24;
-}
-
-static const struct img_writer img_writers[] = {
- { "png", write_lavc, .lavc_codec = AV_CODEC_ID_PNG },
-#if HAVE_JPEG
- { "jpg", write_jpeg },
- { "jpeg", write_jpeg },
-#endif
-};
-
-static const struct img_writer *get_writer(const struct image_writer_opts *opts)
-{
- const char *type = opts->format;
-
- for (size_t n = 0; n < sizeof(img_writers) / sizeof(img_writers[0]); n++) {
- const struct img_writer *writer = &img_writers[n];
- if (type && strcmp(type, writer->file_ext) == 0)
- return writer;
- }
-
- return &img_writers[0];
+ return IMGFMT_RGB0;
}
const char *image_writer_file_ext(const struct image_writer_opts *opts)
@@ -287,7 +264,16 @@ const char *image_writer_file_ext(const struct image_writer_opts *opts)
if (!opts)
opts = &defs;
- return get_writer(opts)->file_ext;
+ return m_opt_choice_str(mp_image_writer_formats, opts->format);
+}
+
+int image_writer_format_from_ext(const char *ext)
+{
+ for (int n = 0; mp_image_writer_formats[n].name; n++) {
+ if (ext && strcmp(mp_image_writer_formats[n].name, ext) == 0)
+ return mp_image_writer_formats[n].value;
+ }
+ return 0;
}
struct mp_image *convert_image(struct mp_image *image, int destfmt,
@@ -325,9 +311,19 @@ bool write_image(struct mp_image *image, const struct image_writer_opts *opts,
if (!opts)
opts = &defs;
- const struct img_writer *writer = get_writer(opts);
- struct image_writer_ctx ctx = { log, opts, writer, image->fmt };
- int destfmt = get_target_format(&ctx, image->imgfmt);
+ struct image_writer_ctx ctx = { log, opts, image->fmt };
+ bool (*write)(struct image_writer_ctx *, mp_image_t *, FILE *) = write_lavc;
+ int destfmt = 0;
+
+#if HAVE_JPEG
+ if (opts->format == AV_CODEC_ID_MJPEG) {
+ write = write_jpeg;
+ destfmt = IMGFMT_RGB24;
+ }
+#endif
+
+ if (!destfmt)
+ destfmt = get_target_format(&ctx);
struct mp_image *dst = convert_image(image, destfmt, log);
if (!dst)
@@ -338,7 +334,7 @@ bool write_image(struct mp_image *image, const struct image_writer_opts *opts,
if (fp == NULL) {
mp_err(log, "Error opening '%s' for writing!\n", filename);
} else {
- success = writer->write(&ctx, dst, fp);
+ success = write(&ctx, dst, fp);
success = !fclose(fp) && success;
if (!success)
mp_err(log, "Error writing file '%s'!\n", filename);
@@ -351,6 +347,6 @@ bool write_image(struct mp_image *image, const struct image_writer_opts *opts,
void dump_png(struct mp_image *image, const char *filename, struct mp_log *log)
{
struct image_writer_opts opts = image_writer_opts_defaults;
- opts.format = "png";
+ opts.format = AV_CODEC_ID_PNG;
write_image(image, &opts, filename, log);
}
diff --git a/video/image_writer.h b/video/image_writer.h
index 8b7414b62a..723dffc3ef 100644
--- a/video/image_writer.h
+++ b/video/image_writer.h
@@ -21,7 +21,7 @@ struct mp_image;
struct mp_log;
struct image_writer_opts {
- char *format;
+ int format;
int high_bit_depth;
int png_compression;
int png_filter;
@@ -42,6 +42,9 @@ extern const struct m_option image_writer_opts[];
// Return the file extension that will be used, e.g. "png".
const char *image_writer_file_ext(const struct image_writer_opts *opts);
+// Map file extension to format ID - return 0 (which is invalid) if unknown.
+int image_writer_format_from_ext(const char *ext);
+
/*
* Save the given image under the given filename. The parameters csp and opts
* are optional. All pixel formats supported by swscale are supported.