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 <leo.izen@gmail.com>
This commit is contained in:
Leo Izen
2025-04-25 05:39:48 -04:00
parent f147df1393
commit 2b38b382cf
+15
View File
@@ -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)