mirror of https://github.com/mpv-player/mpv
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.
This commit is contained in:
parent
dc7d71fc8e
commit
6100a7d75f
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue