summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-04-02 17:21:42 +0200
committerwm4 <wm4@nowhere>2017-04-02 17:21:42 +0200
commit6100a7d75f7233484b7e7c448728ba2138eaebb9 (patch)
treeb5ac88d428e34e3636b7172dbb87e34c23f30335
parentdc7d71fc8e3b418f73a07ab46869850279587351 (diff)
downloadmpv-6100a7d75f7233484b7e7c448728ba2138eaebb9.tar.bz2
mpv-6100a7d75f7233484b7e7c448728ba2138eaebb9.tar.xz
image_writer: make it work with libavcodec's jpg encoder
Now taking a screenshot actually works, if libjpeg is disabled at compile time. In particular, the AV_PIX_FMT_YUVJ formats (with the "J") cause us problems. They have been deprecated years ago, but the libavcodec jpg encoder won't accept anything else. This is made worse by the fact that mpv doesn't have J formats internally - it always uses the color levels metadata to decide the range instead.
-rw-r--r--video/image_writer.c43
1 files changed, 38 insertions, 5 deletions
diff --git a/video/image_writer.c b/video/image_writer.c
index eda02bef81..9855839262 100644
--- a/video/image_writer.c
+++ b/video/image_writer.c
@@ -79,6 +79,16 @@ struct image_writer_ctx {
struct mp_imgfmt_desc original_format;
};
+static enum AVPixelFormat replace_j_format(enum AVPixelFormat fmt)
+{
+ switch (fmt) {
+ case AV_PIX_FMT_YUV420P: return AV_PIX_FMT_YUVJ420P;
+ case AV_PIX_FMT_YUV422P: return AV_PIX_FMT_YUVJ422P;
+ case AV_PIX_FMT_YUV444P: return AV_PIX_FMT_YUVJ444P;
+ }
+ return fmt;
+}
+
static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp)
{
bool success = 0;
@@ -99,7 +109,11 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp
avctx->time_base = AV_TIME_BASE_Q;
avctx->width = image->w;
avctx->height = image->h;
+ avctx->color_range = mp_csp_levels_to_avcol_range(image->params.color.levels);
avctx->pix_fmt = imgfmt2pixfmt(image->imgfmt);
+ // Annoying deprecated garbage for the jpg encoder.
+ 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) {
MP_ERR(ctx, "Image format %s not supported by lavc.\n",
mp_imgfmt_to_name(image->imgfmt));
@@ -127,6 +141,7 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp
pic->format = avctx->pix_fmt;
pic->width = avctx->width;
pic->height = avctx->height;
+ pic->color_range = avctx->color_range;
if (ctx->opts->tag_csp) {
pic->color_primaries = mp_csp_prim_to_avcol_pri(image->params.color.primaries);
pic->color_trc = mp_csp_trc_to_avcol_trc(image->params.color.gamma);
@@ -281,20 +296,38 @@ struct mp_image *convert_image(struct mp_image *image, int destfmt,
{
int d_w, d_h;
mp_image_params_get_dsize(&image->params, &d_w, &d_h);
- bool is_anamorphic = image->w != d_w || image->h != d_h;
- // Caveat: no colorspace/levels conversion done if pixel formats equal
- // it's unclear what colorspace/levels the target wants
- if (image->imgfmt == destfmt && !is_anamorphic)
+ struct mp_image_params p = {
+ .imgfmt = destfmt,
+ .w = d_w,
+ .h = d_h,
+ .p_w = 1,
+ .p_h = 1,
+ };
+ mp_image_params_guess_csp(&p);
+
+ // If RGB, just assume everything is correct.
+ if (p.color.space != MP_CSP_RGB) {
+ // Currently, assume what FFmpeg's jpg encoder needs.
+ // Of course this works only for non-HDR (no HDR support in libswscale).
+ p.color.levels = MP_CSP_LEVELS_PC;
+ p.color.space = MP_CSP_BT_601;
+ p.chroma_location = MP_CHROMA_CENTER;
+ mp_image_params_guess_csp(&p);
+ }
+
+ if (mp_image_params_equal(&p, &image->params))
return mp_image_new_ref(image);
- struct mp_image *dst = mp_image_alloc(destfmt, d_w, d_h);
+ struct mp_image *dst = mp_image_alloc(p.imgfmt, p.w, p.h);
if (!dst) {
mp_err(log, "Out of memory.\n");
return NULL;
}
mp_image_copy_attributes(dst, image);
+ dst->params = p;
+
if (mp_image_swscale(dst, image, mp_sws_hq_flags) < 0) {
mp_err(log, "Error when converting image.\n");
talloc_free(dst);