From 2b38b382cf24a7a03a955bcbb8e3eaa1b3e035c9 Mon Sep 17 00:00:00 2001 From: Leo Izen Date: Tue, 31 Jan 2023 11:05:46 -0500 Subject: [PATCH] video/image_writer: tag bits_per_raw_sample when pixfmt changes This populates the AVCodecContext->bits_per_raw_sample field value when the pixel format of the screenshot being written doesn't match the pixel format of the original video. For example, if the original video was 10-bit and the screenshot is 16-bit, it populates this field so the encoder can make use of it. Currently libjxl and png encoders are known to accept this tag and set the corresponding metadata (via BitDepthHeader, or sBIT). This feature is only enabled if screenshot-sw=yes is enabled, because screenshots from a hardware buffer are always natively at max-depth. Signed-off-by: Leo Izen --- video/image_writer.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/video/image_writer.c b/video/image_writer.c index 0b7eb36c0c..ba2cbec734 100644 --- a/video/image_writer.c +++ b/video/image_writer.c @@ -179,6 +179,21 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp avctx->width = image->w; avctx->height = image->h; avctx->pix_fmt = imgfmt2pixfmt(image->imgfmt); + + /* + * tagging avctx->bits_per_raw_sample indicates the number of significant + * bits. For example, if the original video was 10-bit, and the GPU buffer is + * 16-bit, this tells lavc that only 10 bits are significant. lavc encoders may + * ignore this value, but some codecs can make use of it (for example, PNG's + * sBIT chunk or JXL's bit depth header) + */ + if (memcmp(image->fmt.bpp, ctx->original_format.bpp, sizeof(image->fmt.bpp))) { + int depth = 0; + for (int i = 0; i < MP_ARRAY_SIZE(ctx->original_format.comps); i++) + depth = MPMAX(depth, ctx->original_format.comps[i].size); + avctx->bits_per_raw_sample = depth; + } + if (codec->id == AV_CODEC_ID_MJPEG) { // Annoying deprecated garbage for the jpg encoder. if (image->params.repr.levels == PL_COLOR_LEVELS_FULL)