diff mbox series

[FFmpeg-devel,v3,1/2] libavcodec/libaomenc.c: Support gray input

Message ID 20200407181157.74792-1-ryo.hirafuji@gmail.com
State Superseded
Headers show
Series [FFmpeg-devel,v3,1/2] libavcodec/libaomenc.c: Support gray input | expand

Checks

Context Check Description
andriy/ffmpeg-patchwork success Make fate finished

Commit Message

Ryo Hirafuji April 7, 2020, 6:11 p.m. UTC
From: Ryo Hirafuji <psi@7io.org>

AV1 decoders, libaomdec and libdav1d, both support grayscale image.
However, libaomenc does not support it yet.
In this patch, I add a grayscale image support also to libaomenc.

Fixes ticket #7599
---
 libavcodec/libaomenc.c | 51 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 44 insertions(+), 7 deletions(-)

Comments

James Almer April 7, 2020, 6:23 p.m. UTC | #1
On 4/7/2020 3:11 PM, Ryo Hirafuji wrote:
> From: Ryo Hirafuji <psi@7io.org>
> 
> AV1 decoders, libaomdec and libdav1d, both support grayscale image.
> However, libaomenc does not support it yet.
> In this patch, I add a grayscale image support also to libaomenc.
> 
> Fixes ticket #7599
> ---
>  libavcodec/libaomenc.c | 51 ++++++++++++++++++++++++++++++++++++------
>  1 file changed, 44 insertions(+), 7 deletions(-)
> 
> diff --git a/libavcodec/libaomenc.c b/libavcodec/libaomenc.c
> index 096aadbe1c..a3c5ae8f54 100644
> --- a/libavcodec/libaomenc.c
> +++ b/libavcodec/libaomenc.c
> @@ -154,7 +154,7 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx,
>      av_log(avctx, level, "aom_codec_enc_cfg\n");
>      av_log(avctx, level, "generic settings\n"
>                           "  %*s%u\n  %*s%u\n  %*s%u\n  %*s%u\n  %*s%u\n"
> -                         "  %*s%u\n  %*s%u\n"
> +                         "  %*s%u\n  %*s%u\n  %*s%u\n"
>                           "  %*s{%u/%u}\n  %*s%u\n  %*s%d\n  %*s%u\n",
>             width, "g_usage:",           cfg->g_usage,
>             width, "g_threads:",         cfg->g_threads,
> @@ -163,6 +163,7 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx,
>             width, "g_h:",               cfg->g_h,
>             width, "g_bit_depth:",       cfg->g_bit_depth,
>             width, "g_input_bit_depth:", cfg->g_input_bit_depth,
> +           width, "monochrome:",        cfg->monochrome,
>             width, "g_timebase:",        cfg->g_timebase.num, cfg->g_timebase.den,
>             width, "g_error_resilient:", cfg->g_error_resilient,
>             width, "g_pass:",            cfg->g_pass,
> @@ -276,6 +277,25 @@ static int set_pix_fmt(AVCodecContext *avctx, aom_codec_caps_t codec_caps,
>      AOMContext av_unused *ctx = avctx->priv_data;
>      enccfg->g_bit_depth = enccfg->g_input_bit_depth = 8;
>      switch (avctx->pix_fmt) {
> +    case AV_PIX_FMT_GRAY8:
> +        enccfg->monochrome = 1u;
> +        enccfg->g_profile = FF_PROFILE_AV1_MAIN;
> +        *img_fmt = AOM_IMG_FMT_I420;
> +        return 0;
> +    case AV_PIX_FMT_GRAY10:
> +    case AV_PIX_FMT_GRAY12:
> +        if (codec_caps & AOM_CODEC_CAP_HIGHBITDEPTH) {
> +            enccfg->monochrome = 1u;
> +            enccfg->g_profile =
> +                avctx->pix_fmt == AV_PIX_FMT_GRAY10 ? FF_PROFILE_AV1_MAIN
> +                                                    : FF_PROFILE_AV1_PROFESSIONAL;
> +            enccfg->g_bit_depth = enccfg->g_input_bit_depth =
> +                avctx->pix_fmt == AV_PIX_FMT_GRAY10 ? 10 : 12;
> +            *img_fmt = AOM_IMG_FMT_I42016;
> +            *flags |= AOM_CODEC_USE_HIGHBITDEPTH;
> +            return 0;
> +        }
> +        break;

You can merge these with the AV_PIX_FMT_YUV420P* cases below, doing
something like

enccfg->monochrome = avctx->pix_fmt == AV_PIX_FMT_GRAY8;

and

enccfg->monochrome = avctx->pix_fmt == AV_PIX_FMT_GRAY10 ||
                     avctx->pix_fmt == AV_PIX_FMT_GRAY12;

to enable monochrome in the gray cases.

>      case AV_PIX_FMT_YUV420P:
>          enccfg->g_profile = FF_PROFILE_AV1_MAIN;
>          *img_fmt = AOM_IMG_FMT_I420;
> @@ -979,12 +999,25 @@ static int aom_encode(AVCodecContext *avctx, AVPacket *pkt,
>  
>      if (frame) {
>          rawimg                      = &ctx->rawimg;
> -        rawimg->planes[AOM_PLANE_Y] = frame->data[0];
> -        rawimg->planes[AOM_PLANE_U] = frame->data[1];
> -        rawimg->planes[AOM_PLANE_V] = frame->data[2];
> -        rawimg->stride[AOM_PLANE_Y] = frame->linesize[0];
> -        rawimg->stride[AOM_PLANE_U] = frame->linesize[1];
> -        rawimg->stride[AOM_PLANE_V] = frame->linesize[2];
> +        if (frame->format == AV_PIX_FMT_GRAY8 ||
> +            frame->format == AV_PIX_FMT_GRAY10 ||
> +            frame->format == AV_PIX_FMT_GRAY12) {
> +            rawimg->monochrome = 1;
> +            rawimg->planes[AOM_PLANE_Y] = frame->data[0];
> +            rawimg->planes[AOM_PLANE_U] = frame->data[0];
> +            rawimg->planes[AOM_PLANE_V] = frame->data[0];
> +            rawimg->stride[AOM_PLANE_Y] = frame->linesize[0];
> +            rawimg->stride[AOM_PLANE_U] = frame->linesize[0];
> +            rawimg->stride[AOM_PLANE_V] = frame->linesize[0];

Are these meant to all point to the Y plane, or can they be NULL/0? If
so, then leaving this chunk as it was should AFAIK work.

> +        } else {
> +            rawimg->monochrome = 0;
> +            rawimg->planes[AOM_PLANE_Y] = frame->data[0];
> +            rawimg->planes[AOM_PLANE_U] = frame->data[1];
> +            rawimg->planes[AOM_PLANE_V] = frame->data[2];
> +            rawimg->stride[AOM_PLANE_Y] = frame->linesize[0];
> +            rawimg->stride[AOM_PLANE_U] = frame->linesize[1];
> +            rawimg->stride[AOM_PLANE_V] = frame->linesize[2];
> +        }
>          timestamp                   = frame->pts;
>          switch (frame->color_range) {
>          case AVCOL_RANGE_MPEG:
> @@ -1025,6 +1058,7 @@ static int aom_encode(AVCodecContext *avctx, AVPacket *pkt,
>  }
>  
>  static const enum AVPixelFormat av1_pix_fmts[] = {
> +    AV_PIX_FMT_GRAY8,
>      AV_PIX_FMT_YUV420P,
>      AV_PIX_FMT_YUV422P,
>      AV_PIX_FMT_YUV444P,
> @@ -1032,6 +1066,9 @@ static const enum AVPixelFormat av1_pix_fmts[] = {
>  };
>  
>  static const enum AVPixelFormat av1_pix_fmts_highbd[] = {
> +    AV_PIX_FMT_GRAY8,
> +    AV_PIX_FMT_GRAY10,
> +    AV_PIX_FMT_GRAY12,
>      AV_PIX_FMT_YUV420P,
>      AV_PIX_FMT_YUV422P,
>      AV_PIX_FMT_YUV444P,
>
Ryo Hirafuji April 7, 2020, 6:36 p.m. UTC | #2
James, thank you for your review!


> You can merge these with the AV_PIX_FMT_YUV420P* cases below, doing
> something like
> enccfg->monochrome = avctx->pix_fmt == AV_PIX_FMT_GRAY8;
> and
> enccfg->monochrome = avctx->pix_fmt == AV_PIX_FMT_GRAY10 ||
>                      avctx->pix_fmt == AV_PIX_FMT_GRAY12;
> to enable monochrome in the gray cases.


It sounds great. Thanks, I will change in patch v4.

 Are these meant to all point to the Y plane, or can they be NULL/0? If
> so, then leaving this chunk as it was should AFAIK work.


U plane and V plane will be ignored when "monochorme=1", but it crashes
with SIGSEGV when U plane or V plane is NULL.
So we have to set some valid pointers.
If aom_image is allocated by aom_img_alloc function, U plane and V plane
are allocated.
But we use aom_img_wrap function, so we have to prepare some valid pointers
ourselves.

> +            rawimg->planes[AOM_PLANE_Y] = frame->data[0];
> +            rawimg->planes[AOM_PLANE_U] = frame->data[1];
> +            rawimg->planes[AOM_PLANE_V] = frame->data[2];
> +            rawimg->stride[AOM_PLANE_Y] = frame->linesize[0];
> +            rawimg->stride[AOM_PLANE_U] = frame->linesize[1];
> +            rawimg->stride[AOM_PLANE_V] = frame->linesize[2];

I also tested with this code before, but frame->data[1] or frame->[2]
sometimes becomes NULL or (maybe) invalid pointer for gray data.
(gray doesn't have U and V, so I think it's not strange.)

2020年4月8日(水) 3:23 James Almer <jamrial@gmail.com>:

> On 4/7/2020 3:11 PM, Ryo Hirafuji wrote:
> > From: Ryo Hirafuji <psi@7io.org>
> >
> > AV1 decoders, libaomdec and libdav1d, both support grayscale image.
> > However, libaomenc does not support it yet.
> > In this patch, I add a grayscale image support also to libaomenc.
> >
> > Fixes ticket #7599
> > ---
> >  libavcodec/libaomenc.c | 51 ++++++++++++++++++++++++++++++++++++------
> >  1 file changed, 44 insertions(+), 7 deletions(-)
> >
> > diff --git a/libavcodec/libaomenc.c b/libavcodec/libaomenc.c
> > index 096aadbe1c..a3c5ae8f54 100644
> > --- a/libavcodec/libaomenc.c
> > +++ b/libavcodec/libaomenc.c
> > @@ -154,7 +154,7 @@ static av_cold void dump_enc_cfg(AVCodecContext
> *avctx,
> >      av_log(avctx, level, "aom_codec_enc_cfg\n");
> >      av_log(avctx, level, "generic settings\n"
> >                           "  %*s%u\n  %*s%u\n  %*s%u\n  %*s%u\n  %*s%u\n"
> > -                         "  %*s%u\n  %*s%u\n"
> > +                         "  %*s%u\n  %*s%u\n  %*s%u\n"
> >                           "  %*s{%u/%u}\n  %*s%u\n  %*s%d\n  %*s%u\n",
> >             width, "g_usage:",           cfg->g_usage,
> >             width, "g_threads:",         cfg->g_threads,
> > @@ -163,6 +163,7 @@ static av_cold void dump_enc_cfg(AVCodecContext
> *avctx,
> >             width, "g_h:",               cfg->g_h,
> >             width, "g_bit_depth:",       cfg->g_bit_depth,
> >             width, "g_input_bit_depth:", cfg->g_input_bit_depth,
> > +           width, "monochrome:",        cfg->monochrome,
> >             width, "g_timebase:",        cfg->g_timebase.num,
> cfg->g_timebase.den,
> >             width, "g_error_resilient:", cfg->g_error_resilient,
> >             width, "g_pass:",            cfg->g_pass,
> > @@ -276,6 +277,25 @@ static int set_pix_fmt(AVCodecContext *avctx,
> aom_codec_caps_t codec_caps,
> >      AOMContext av_unused *ctx = avctx->priv_data;
> >      enccfg->g_bit_depth = enccfg->g_input_bit_depth = 8;
> >      switch (avctx->pix_fmt) {
> > +    case AV_PIX_FMT_GRAY8:
> > +        enccfg->monochrome = 1u;
> > +        enccfg->g_profile = FF_PROFILE_AV1_MAIN;
> > +        *img_fmt = AOM_IMG_FMT_I420;
> > +        return 0;
> > +    case AV_PIX_FMT_GRAY10:
> > +    case AV_PIX_FMT_GRAY12:
> > +        if (codec_caps & AOM_CODEC_CAP_HIGHBITDEPTH) {
> > +            enccfg->monochrome = 1u;
> > +            enccfg->g_profile =
> > +                avctx->pix_fmt == AV_PIX_FMT_GRAY10 ?
> FF_PROFILE_AV1_MAIN
> > +                                                    :
> FF_PROFILE_AV1_PROFESSIONAL;
> > +            enccfg->g_bit_depth = enccfg->g_input_bit_depth =
> > +                avctx->pix_fmt == AV_PIX_FMT_GRAY10 ? 10 : 12;
> > +            *img_fmt = AOM_IMG_FMT_I42016;
> > +            *flags |= AOM_CODEC_USE_HIGHBITDEPTH;
> > +            return 0;
> > +        }
> > +        break;
>
> You can merge these with the AV_PIX_FMT_YUV420P* cases below, doing
> something like
>
> enccfg->monochrome = avctx->pix_fmt == AV_PIX_FMT_GRAY8;
>
> and
>
> enccfg->monochrome = avctx->pix_fmt == AV_PIX_FMT_GRAY10 ||
>                      avctx->pix_fmt == AV_PIX_FMT_GRAY12;
>
> to enable monochrome in the gray cases.
>
> >      case AV_PIX_FMT_YUV420P:
> >          enccfg->g_profile = FF_PROFILE_AV1_MAIN;
> >          *img_fmt = AOM_IMG_FMT_I420;
> > @@ -979,12 +999,25 @@ static int aom_encode(AVCodecContext *avctx,
> AVPacket *pkt,
> >
> >      if (frame) {
> >          rawimg                      = &ctx->rawimg;
> > -        rawimg->planes[AOM_PLANE_Y] = frame->data[0];
> > -        rawimg->planes[AOM_PLANE_U] = frame->data[1];
> > -        rawimg->planes[AOM_PLANE_V] = frame->data[2];
> > -        rawimg->stride[AOM_PLANE_Y] = frame->linesize[0];
> > -        rawimg->stride[AOM_PLANE_U] = frame->linesize[1];
> > -        rawimg->stride[AOM_PLANE_V] = frame->linesize[2];
> > +        if (frame->format == AV_PIX_FMT_GRAY8 ||
> > +            frame->format == AV_PIX_FMT_GRAY10 ||
> > +            frame->format == AV_PIX_FMT_GRAY12) {
> > +            rawimg->monochrome = 1;
> > +            rawimg->planes[AOM_PLANE_Y] = frame->data[0];
> > +            rawimg->planes[AOM_PLANE_U] = frame->data[0];
> > +            rawimg->planes[AOM_PLANE_V] = frame->data[0];
> > +            rawimg->stride[AOM_PLANE_Y] = frame->linesize[0];
> > +            rawimg->stride[AOM_PLANE_U] = frame->linesize[0];
> > +            rawimg->stride[AOM_PLANE_V] = frame->linesize[0];
>
> Are these meant to all point to the Y plane, or can they be NULL/0? If
> so, then leaving this chunk as it was should AFAIK work.
>
> > +        } else {
> > +            rawimg->monochrome = 0;
> > +            rawimg->planes[AOM_PLANE_Y] = frame->data[0];
> > +            rawimg->planes[AOM_PLANE_U] = frame->data[1];
> > +            rawimg->planes[AOM_PLANE_V] = frame->data[2];
> > +            rawimg->stride[AOM_PLANE_Y] = frame->linesize[0];
> > +            rawimg->stride[AOM_PLANE_U] = frame->linesize[1];
> > +            rawimg->stride[AOM_PLANE_V] = frame->linesize[2];
> > +        }
> >          timestamp                   = frame->pts;
> >          switch (frame->color_range) {
> >          case AVCOL_RANGE_MPEG:
> > @@ -1025,6 +1058,7 @@ static int aom_encode(AVCodecContext *avctx,
> AVPacket *pkt,
> >  }
> >
> >  static const enum AVPixelFormat av1_pix_fmts[] = {
> > +    AV_PIX_FMT_GRAY8,
> >      AV_PIX_FMT_YUV420P,
> >      AV_PIX_FMT_YUV422P,
> >      AV_PIX_FMT_YUV444P,
> > @@ -1032,6 +1066,9 @@ static const enum AVPixelFormat av1_pix_fmts[] = {
> >  };
> >
> >  static const enum AVPixelFormat av1_pix_fmts_highbd[] = {
> > +    AV_PIX_FMT_GRAY8,
> > +    AV_PIX_FMT_GRAY10,
> > +    AV_PIX_FMT_GRAY12,
> >      AV_PIX_FMT_YUV420P,
> >      AV_PIX_FMT_YUV422P,
> >      AV_PIX_FMT_YUV444P,
> >
>
> _______________________________________________
> 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/libaomenc.c b/libavcodec/libaomenc.c
index 096aadbe1c..a3c5ae8f54 100644
--- a/libavcodec/libaomenc.c
+++ b/libavcodec/libaomenc.c
@@ -154,7 +154,7 @@  static av_cold void dump_enc_cfg(AVCodecContext *avctx,
     av_log(avctx, level, "aom_codec_enc_cfg\n");
     av_log(avctx, level, "generic settings\n"
                          "  %*s%u\n  %*s%u\n  %*s%u\n  %*s%u\n  %*s%u\n"
-                         "  %*s%u\n  %*s%u\n"
+                         "  %*s%u\n  %*s%u\n  %*s%u\n"
                          "  %*s{%u/%u}\n  %*s%u\n  %*s%d\n  %*s%u\n",
            width, "g_usage:",           cfg->g_usage,
            width, "g_threads:",         cfg->g_threads,
@@ -163,6 +163,7 @@  static av_cold void dump_enc_cfg(AVCodecContext *avctx,
            width, "g_h:",               cfg->g_h,
            width, "g_bit_depth:",       cfg->g_bit_depth,
            width, "g_input_bit_depth:", cfg->g_input_bit_depth,
+           width, "monochrome:",        cfg->monochrome,
            width, "g_timebase:",        cfg->g_timebase.num, cfg->g_timebase.den,
            width, "g_error_resilient:", cfg->g_error_resilient,
            width, "g_pass:",            cfg->g_pass,
@@ -276,6 +277,25 @@  static int set_pix_fmt(AVCodecContext *avctx, aom_codec_caps_t codec_caps,
     AOMContext av_unused *ctx = avctx->priv_data;
     enccfg->g_bit_depth = enccfg->g_input_bit_depth = 8;
     switch (avctx->pix_fmt) {
+    case AV_PIX_FMT_GRAY8:
+        enccfg->monochrome = 1u;
+        enccfg->g_profile = FF_PROFILE_AV1_MAIN;
+        *img_fmt = AOM_IMG_FMT_I420;
+        return 0;
+    case AV_PIX_FMT_GRAY10:
+    case AV_PIX_FMT_GRAY12:
+        if (codec_caps & AOM_CODEC_CAP_HIGHBITDEPTH) {
+            enccfg->monochrome = 1u;
+            enccfg->g_profile =
+                avctx->pix_fmt == AV_PIX_FMT_GRAY10 ? FF_PROFILE_AV1_MAIN
+                                                    : FF_PROFILE_AV1_PROFESSIONAL;
+            enccfg->g_bit_depth = enccfg->g_input_bit_depth =
+                avctx->pix_fmt == AV_PIX_FMT_GRAY10 ? 10 : 12;
+            *img_fmt = AOM_IMG_FMT_I42016;
+            *flags |= AOM_CODEC_USE_HIGHBITDEPTH;
+            return 0;
+        }
+        break;
     case AV_PIX_FMT_YUV420P:
         enccfg->g_profile = FF_PROFILE_AV1_MAIN;
         *img_fmt = AOM_IMG_FMT_I420;
@@ -979,12 +999,25 @@  static int aom_encode(AVCodecContext *avctx, AVPacket *pkt,
 
     if (frame) {
         rawimg                      = &ctx->rawimg;
-        rawimg->planes[AOM_PLANE_Y] = frame->data[0];
-        rawimg->planes[AOM_PLANE_U] = frame->data[1];
-        rawimg->planes[AOM_PLANE_V] = frame->data[2];
-        rawimg->stride[AOM_PLANE_Y] = frame->linesize[0];
-        rawimg->stride[AOM_PLANE_U] = frame->linesize[1];
-        rawimg->stride[AOM_PLANE_V] = frame->linesize[2];
+        if (frame->format == AV_PIX_FMT_GRAY8 ||
+            frame->format == AV_PIX_FMT_GRAY10 ||
+            frame->format == AV_PIX_FMT_GRAY12) {
+            rawimg->monochrome = 1;
+            rawimg->planes[AOM_PLANE_Y] = frame->data[0];
+            rawimg->planes[AOM_PLANE_U] = frame->data[0];
+            rawimg->planes[AOM_PLANE_V] = frame->data[0];
+            rawimg->stride[AOM_PLANE_Y] = frame->linesize[0];
+            rawimg->stride[AOM_PLANE_U] = frame->linesize[0];
+            rawimg->stride[AOM_PLANE_V] = frame->linesize[0];
+        } else {
+            rawimg->monochrome = 0;
+            rawimg->planes[AOM_PLANE_Y] = frame->data[0];
+            rawimg->planes[AOM_PLANE_U] = frame->data[1];
+            rawimg->planes[AOM_PLANE_V] = frame->data[2];
+            rawimg->stride[AOM_PLANE_Y] = frame->linesize[0];
+            rawimg->stride[AOM_PLANE_U] = frame->linesize[1];
+            rawimg->stride[AOM_PLANE_V] = frame->linesize[2];
+        }
         timestamp                   = frame->pts;
         switch (frame->color_range) {
         case AVCOL_RANGE_MPEG:
@@ -1025,6 +1058,7 @@  static int aom_encode(AVCodecContext *avctx, AVPacket *pkt,
 }
 
 static const enum AVPixelFormat av1_pix_fmts[] = {
+    AV_PIX_FMT_GRAY8,
     AV_PIX_FMT_YUV420P,
     AV_PIX_FMT_YUV422P,
     AV_PIX_FMT_YUV444P,
@@ -1032,6 +1066,9 @@  static const enum AVPixelFormat av1_pix_fmts[] = {
 };
 
 static const enum AVPixelFormat av1_pix_fmts_highbd[] = {
+    AV_PIX_FMT_GRAY8,
+    AV_PIX_FMT_GRAY10,
+    AV_PIX_FMT_GRAY12,
     AV_PIX_FMT_YUV420P,
     AV_PIX_FMT_YUV422P,
     AV_PIX_FMT_YUV444P,