diff mbox series

[FFmpeg-devel,v2] hw_base_enc: inject side data to crop output for AV1

Message ID 20240914065925.149320-1-dev@lynne.ee
State New
Headers show
Series [FFmpeg-devel,v2] hw_base_enc: inject side data to crop output for AV1 | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Lynne Sept. 14, 2024, 6:58 a.m. UTC
Unlike H264/H265, AV1 contains no fields to crop encoded output
to specific sizes.
AMD's hardware cannot handle encoding of unaligned dimensions for
AV1, hence it codes 1920x1080 as 1920x1088.

Add side data to crop the output back to the original dimensions.
There's an AV1-spec extension planned to fix this here:
https://github.com/AOMediaCodec/av1-spec/pull/346

But it seems to have stuck for now.
---
 libavcodec/hw_base_encode.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

Comments

Anton Khirnov Sept. 23, 2024, 4:50 a.m. UTC | #1
Quoting Lynne via ffmpeg-devel (2024-09-14 08:58:46)
> @@ -551,6 +552,30 @@ int ff_hw_base_encode_set_output_property(FFHWBaseEncodeContext *ctx,
>                                  (3 * ctx->output_delay + ctx->async_depth)];
>      }
>  
> +    if ((avctx->codec_id == AV_CODEC_ID_AV1) &&
> +        ((avctx->coded_width != avctx->width) ||
> +         (avctx->coded_height != avctx->height))) {
> +        int err;
> +        size_t crop_data_size = 4*4;
> +
> +        uint8_t *crop_data = av_mallocz(crop_data_size);
> +        if (!crop_data) {
> +            av_buffer_unref(&pkt->buf);
> +            return AVERROR(ENOMEM);
> +        }
> +
> +        AV_WL32(&crop_data[2], ctx->surface_width - avctx->width);
> +        AV_WL32(&crop_data[3], ctx->surface_height - avctx->height);
> +
> +        err = av_packet_add_side_data(pkt, AV_PKT_DATA_FRAME_CROPPING,
> +                                      crop_data, crop_data_size);
> +        if (err < 0) {
> +            av_buffer_unref(&pkt->buf);

Not av_packet_unref()?
David Rosca Oct. 1, 2024, 9:56 a.m. UTC | #2
On Sat, Sep 14, 2024 at 8:59 AM Lynne via ffmpeg-devel
<ffmpeg-devel@ffmpeg.org> wrote:
>
> Unlike H264/H265, AV1 contains no fields to crop encoded output
> to specific sizes.
> AMD's hardware cannot handle encoding of unaligned dimensions for
> AV1, hence it codes 1920x1080 as 1920x1088.
>
> Add side data to crop the output back to the original dimensions.
> There's an AV1-spec extension planned to fix this here:
> https://github.com/AOMediaCodec/av1-spec/pull/346
>
> But it seems to have stuck for now.
> ---
>  libavcodec/hw_base_encode.c | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
>
> diff --git a/libavcodec/hw_base_encode.c b/libavcodec/hw_base_encode.c
> index 7b6ec97d3b..c28f1aa91c 100644
> --- a/libavcodec/hw_base_encode.c
> +++ b/libavcodec/hw_base_encode.c
> @@ -22,6 +22,7 @@
>  #include "libavutil/log.h"
>  #include "libavutil/mem.h"
>  #include "libavutil/pixdesc.h"
> +#include "libavutil/intreadwrite.h"
>
>  #include "encode.h"
>  #include "avcodec.h"
> @@ -551,6 +552,30 @@ int ff_hw_base_encode_set_output_property(FFHWBaseEncodeContext *ctx,
>                                  (3 * ctx->output_delay + ctx->async_depth)];
>      }
>
> +    if ((avctx->codec_id == AV_CODEC_ID_AV1) &&
> +        ((avctx->coded_width != avctx->width) ||
> +         (avctx->coded_height != avctx->height))) {
> +        int err;
> +        size_t crop_data_size = 4*4;
> +
> +        uint8_t *crop_data = av_mallocz(crop_data_size);
> +        if (!crop_data) {
> +            av_buffer_unref(&pkt->buf);
> +            return AVERROR(ENOMEM);
> +        }
> +
> +        AV_WL32(&crop_data[2], ctx->surface_width - avctx->width);

Should this be avctx->coded_width - avctx->width instead?
Also there is a flag_no_delay early return above in this function, so
this code doesn't run when I try to add support for this in vaapi
encode.

> +        AV_WL32(&crop_data[3], ctx->surface_height - avctx->height);
> +
> +        err = av_packet_add_side_data(pkt, AV_PKT_DATA_FRAME_CROPPING,
> +                                      crop_data, crop_data_size);

This doesn't seem to be currently picked up by movenc/matroskaenc as
both will only take the side data from avctx->coded_side_data?

> +        if (err < 0) {
> +            av_buffer_unref(&pkt->buf);
> +            av_free(crop_data);
> +            return err;
> +        }
> +    }
> +
>      return 0;
>  }
>
> --
> 2.45.2.753.g447d99e1c3b
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
diff mbox series

Patch

diff --git a/libavcodec/hw_base_encode.c b/libavcodec/hw_base_encode.c
index 7b6ec97d3b..c28f1aa91c 100644
--- a/libavcodec/hw_base_encode.c
+++ b/libavcodec/hw_base_encode.c
@@ -22,6 +22,7 @@ 
 #include "libavutil/log.h"
 #include "libavutil/mem.h"
 #include "libavutil/pixdesc.h"
+#include "libavutil/intreadwrite.h"
 
 #include "encode.h"
 #include "avcodec.h"
@@ -551,6 +552,30 @@  int ff_hw_base_encode_set_output_property(FFHWBaseEncodeContext *ctx,
                                 (3 * ctx->output_delay + ctx->async_depth)];
     }
 
+    if ((avctx->codec_id == AV_CODEC_ID_AV1) &&
+        ((avctx->coded_width != avctx->width) ||
+         (avctx->coded_height != avctx->height))) {
+        int err;
+        size_t crop_data_size = 4*4;
+
+        uint8_t *crop_data = av_mallocz(crop_data_size);
+        if (!crop_data) {
+            av_buffer_unref(&pkt->buf);
+            return AVERROR(ENOMEM);
+        }
+
+        AV_WL32(&crop_data[2], ctx->surface_width - avctx->width);
+        AV_WL32(&crop_data[3], ctx->surface_height - avctx->height);
+
+        err = av_packet_add_side_data(pkt, AV_PKT_DATA_FRAME_CROPPING,
+                                      crop_data, crop_data_size);
+        if (err < 0) {
+            av_buffer_unref(&pkt->buf);
+            av_free(crop_data);
+            return err;
+        }
+    }
+
     return 0;
 }