[FFmpeg-devel] [PATCH]lavc/h264: Output pix_fmt GRAY for monochrome input.

James Almer jamrial at gmail.com
Tue Aug 7 23:26:29 EEST 2018


On 8/7/2018 4:51 PM, Carl Eugen Hoyos wrote:
> Hi!
> 
> Attached patch makes the h264 decoder output AV_PIX_FMT_GRAY for
> monochrome h264 streams.
> fate output is identical (and identical with the reference decoder) if
> compared with extractplanes=y.
> 
> Please review, Carl Eugen
> 
> 
> 0001-lavc-h264-Output-pix_fmt-GRAY-for-monochrome-input.patch
> 
> 
> From 6434eff6c14698db192ec2f8777d2b4d2fdd3e8c Mon Sep 17 00:00:00 2001
> From: Carl Eugen Hoyos <ceffmpeg at gmail.com>
> Date: Tue, 7 Aug 2018 21:48:47 +0200
> Subject: [PATCH] lavc/h264: Output pix_fmt GRAY for monochrome input.
> 
> fate output is identical when compared with extractplanes=y.
> ---
>  libavcodec/h264_mb.c                               |   10 +-
>  libavcodec/h264_mb_template.c                      |   11 +-
>  libavcodec/h264_parser.c                           |    3 +
>  libavcodec/h264_slice.c                            |   17 +-
>  libavcodec/h264dec.h                               |    1 +
>  .../fate/h264-conformance-frext-hpcamolq_brcm_b    |  200 ++++++++++----------
>  .../fate/h264-conformance-frext-hpcvmolq_brcm_b    |  200 ++++++++++----------
>  7 files changed, 229 insertions(+), 213 deletions(-)
> 
> diff --git a/libavcodec/h264_mb.c b/libavcodec/h264_mb.c
> index 3cd17b7..a269b5c 100644
> --- a/libavcodec/h264_mb.c
> +++ b/libavcodec/h264_mb.c
> @@ -250,7 +250,7 @@ static av_always_inline void mc_dir_part(const H264Context *h, H264SliceContext
>      if (!square)
>          qpix_op[luma_xy](dest_y + delta, src_y + delta, sl->mb_linesize);
>  
> -    if (CONFIG_GRAY && h->flags & AV_CODEC_FLAG_GRAY)
> +    if (CHROMA400(h) || CONFIG_GRAY && h->flags & AV_CODEC_FLAG_GRAY)
>          return;
>  
>      if (chroma_idc == 3 /* yuv444 */) {
> @@ -425,7 +425,7 @@ static av_always_inline void mc_part_weighted(const H264Context *h, H264SliceCon
>              int weight1 = 64 - weight0;
>              luma_weight_avg(dest_y, tmp_y, sl->mb_linesize,
>                              height, 5, weight0, weight1, 0);
> -            if (!CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY)) {
> +            if (!CHROMA400(h) && (!CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY))) {
>                  chroma_weight_avg(dest_cb, tmp_cb, sl->mb_uvlinesize,
>                                    chroma_height, 5, weight0, weight1, 0);
>                  chroma_weight_avg(dest_cr, tmp_cr, sl->mb_uvlinesize,
> @@ -438,7 +438,7 @@ static av_always_inline void mc_part_weighted(const H264Context *h, H264SliceCon
>                              sl->pwt.luma_weight[refn1][1][0],
>                              sl->pwt.luma_weight[refn0][0][1] +
>                              sl->pwt.luma_weight[refn1][1][1]);
> -            if (!CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY)) {
> +            if (!CHROMA400(h) && (!CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY))) {
>                  chroma_weight_avg(dest_cb, tmp_cb, sl->mb_uvlinesize, chroma_height,
>                                    sl->pwt.chroma_log2_weight_denom,
>                                    sl->pwt.chroma_weight[refn0][0][0][0],
> @@ -465,7 +465,7 @@ static av_always_inline void mc_part_weighted(const H264Context *h, H264SliceCon
>                         sl->pwt.luma_log2_weight_denom,
>                         sl->pwt.luma_weight[refn][list][0],
>                         sl->pwt.luma_weight[refn][list][1]);
> -        if (!CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY)) {
> +        if (!CHROMA400(h) && (!CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY))) {
>              if (sl->pwt.use_weight_chroma) {
>                  chroma_weight_op(dest_cb, sl->mb_uvlinesize, chroma_height,
>                                   sl->pwt.chroma_log2_weight_denom,
> @@ -566,7 +566,7 @@ static av_always_inline void xchg_mb_border(const H264Context *h, H264SliceConte
>              XCHG(sl->top_borders[top_idx][sl->mb_x + 1],
>                   src_y + (17 << pixel_shift), 1);
>          }
> -        if (simple || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY)) {
> +        if (!CHROMA400(h) && (simple || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY))) {
>              if (chroma444) {
>                  if (deblock_topleft) {
>                      XCHG(top_border_m1 + (24 << pixel_shift), src_cb - (7 << pixel_shift), 1);
> diff --git a/libavcodec/h264_mb_template.c b/libavcodec/h264_mb_template.c
> index d5ea26a..2abc864 100644
> --- a/libavcodec/h264_mb_template.c
> +++ b/libavcodec/h264_mb_template.c
> @@ -52,6 +52,7 @@ static av_noinline void FUNC(hl_decode_mb)(const H264Context *h, H264SliceContex
>      void (*idct_add)(uint8_t *dst, int16_t *block, int stride);
>      const int block_h   = 16 >> h->chroma_y_shift;
>      const int chroma422 = CHROMA422(h);
> +    const int chroma400 = CHROMA400(h);
>  
>      dest_y  = h->cur_pic.f->data[0] + ((mb_x << PIXEL_SHIFT)     + mb_y * sl->linesize)  * 16;
>      dest_cb = h->cur_pic.f->data[1] +  (mb_x << PIXEL_SHIFT) * 8 + mb_y * sl->uvlinesize * block_h;
> @@ -108,7 +109,7 @@ static av_noinline void FUNC(hl_decode_mb)(const H264Context *h, H264SliceContex
>                  for (j = 0; j < 16; j++)
>                      tmp_y[j] = get_bits(&gb, bit_depth);
>              }
> -            if (SIMPLE || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY)) {
> +            if (!chroma400 && (SIMPLE || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY))) {
>                  if (!h->ps.sps->chroma_format_idc) {

I think this becomes dead code. Your change makes sure this chunk is
never reached if the stream is chroma400, so this check here will always
be false.

>                      for (i = 0; i < block_h; i++) {
>                          uint16_t *tmp_cb = (uint16_t *)(dest_cb + i * uvlinesize);
> @@ -133,7 +134,7 @@ static av_noinline void FUNC(hl_decode_mb)(const H264Context *h, H264SliceContex
>          } else {
>              for (i = 0; i < 16; i++)
>                  memcpy(dest_y + i * linesize, sl->intra_pcm_ptr + i * 16, 16);
> -            if (SIMPLE || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY)) {
> +            if (!chroma400 && (SIMPLE || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY))) {
>                  if (!h->ps.sps->chroma_format_idc) {

Same

>                      for (i = 0; i < 8; i++) {
>                          memset(dest_cb + i * uvlinesize, 1 << (bit_depth - 1), 8);
> @@ -155,7 +156,7 @@ static av_noinline void FUNC(hl_decode_mb)(const H264Context *h, H264SliceContex
>                  xchg_mb_border(h, sl, dest_y, dest_cb, dest_cr, linesize,
>                                 uvlinesize, 1, 0, SIMPLE, PIXEL_SHIFT);
>  
> -            if (SIMPLE || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY)) {
> +            if (!chroma400 && (SIMPLE || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY))) {
>                  h->hpc.pred8x8[sl->chroma_pred_mode](dest_cb, uvlinesize);
>                  h->hpc.pred8x8[sl->chroma_pred_mode](dest_cr, uvlinesize);
>              }
> @@ -190,7 +191,7 @@ static av_noinline void FUNC(hl_decode_mb)(const H264Context *h, H264SliceContex
>          hl_decode_mb_idct_luma(h, sl, mb_type, SIMPLE, transform_bypass,
>                                 PIXEL_SHIFT, block_offset, linesize, dest_y, 0);
>  
> -        if ((SIMPLE || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY)) &&
> +        if ((!CHROMA400(h) && (SIMPLE || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY))) &&
>              (sl->cbp & 0x30)) {
>              uint8_t *dest[2] = { dest_cb, dest_cr };
>              if (transform_bypass) {
> @@ -264,7 +265,7 @@ static av_noinline void FUNC(hl_decode_mb_444)(const H264Context *h, H264SliceCo
>      int i, j, p;
>      const int *block_offset = &h->block_offset[0];
>      const int transform_bypass = !SIMPLE && (sl->qscale == 0 && h->ps.sps->transform_bypass);
> -    const int plane_count      = (SIMPLE || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY)) ? 3 : 1;
> +    const int plane_count      = !CHROMA400(h) && (SIMPLE || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY)) ? 3 : 1;
>  
>      for (p = 0; p < plane_count; p++) {
>          dest[p] = h->cur_pic.f->data[p] +
> diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
> index 5f9a9c4..8670b78 100644
> --- a/libavcodec/h264_parser.c
> +++ b/libavcodec/h264_parser.c
> @@ -401,16 +401,19 @@ static inline int parse_nal_units(AVCodecParserContext *s,
>              case 9:
>                  if (sps->chroma_format_idc == 3)      s->format = AV_PIX_FMT_YUV444P9;
>                  else if (sps->chroma_format_idc == 2) s->format = AV_PIX_FMT_YUV422P9;
> +                else if (sps->chroma_format_idc == 1) s->format = AV_PIX_FMT_GRAY9;
>                  else                                  s->format = AV_PIX_FMT_YUV420P9;
>                  break;
>              case 10:
>                  if (sps->chroma_format_idc == 3)      s->format = AV_PIX_FMT_YUV444P10;
>                  else if (sps->chroma_format_idc == 2) s->format = AV_PIX_FMT_YUV422P10;
> +                else if (sps->chroma_format_idc == 1) s->format = AV_PIX_FMT_GRAY10;
>                  else                                  s->format = AV_PIX_FMT_YUV420P10;
>                  break;
>              case 8:
>                  if (sps->chroma_format_idc == 3)      s->format = AV_PIX_FMT_YUV444P;
>                  else if (sps->chroma_format_idc == 2) s->format = AV_PIX_FMT_YUV422P;
> +                else if (sps->chroma_format_idc == 1) s->format = AV_PIX_FMT_GRAY8;

chroma_format_idc == 1 is yuv420p*, so use it here and put gray in the
last else.

>                  else                                  s->format = AV_PIX_FMT_YUV420P;
>                  break;
>              default:
> diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
> index ede9a1a..f98268a 100644
> --- a/libavcodec/h264_slice.c
> +++ b/libavcodec/h264_slice.c
> @@ -497,7 +497,7 @@ static int h264_frame_start(H264Context *h)
>  
>      if ((ret = alloc_picture(h, pic)) < 0)
>          return ret;
> -    if(!h->frame_recovered && !h->avctx->hwaccel)
> +    if(!h->frame_recovered && !h->avctx->hwaccel && !CHROMA400(h))
>          ff_color_frame(pic->f, c);
>  
>      h->cur_pic_ptr = pic;
> @@ -564,6 +564,7 @@ static av_always_inline void backup_mb_border(const H264Context *h, H264SliceCon
>      const int pixel_shift = h->pixel_shift;
>      int chroma444 = CHROMA444(h);
>      int chroma422 = CHROMA422(h);
> +    int chroma400 = CHROMA400(h);
>  
>      src_y  -= linesize;
>      src_cb -= uvlinesize;
> @@ -576,7 +577,7 @@ static av_always_inline void backup_mb_border(const H264Context *h, H264SliceCon
>                  AV_COPY128(top_border, src_y + 15 * linesize);
>                  if (pixel_shift)
>                      AV_COPY128(top_border + 16, src_y + 15 * linesize + 16);
> -                if (simple || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY)) {
> +                if (!chroma400 && (simple || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY))) {
>                      if (chroma444) {
>                          if (pixel_shift) {
>                              AV_COPY128(top_border + 32, src_cb + 15 * uvlinesize);
> @@ -619,7 +620,7 @@ static av_always_inline void backup_mb_border(const H264Context *h, H264SliceCon
>      if (pixel_shift)
>          AV_COPY128(top_border + 16, src_y + 16 * linesize + 16);
>  
> -    if (simple || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY)) {
> +    if (!chroma400 && (simple || !CONFIG_GRAY || !(h->flags & AV_CODEC_FLAG_GRAY))) {
>          if (chroma444) {
>              if (pixel_shift) {
>                  AV_COPY128(top_border + 32, src_cb + 16 * linesize);
> @@ -772,6 +773,8 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
>                  *fmt++ = AV_PIX_FMT_GBRP9;
>              } else
>                  *fmt++ = AV_PIX_FMT_YUV444P9;
> +        } else if (CHROMA400(h)) {
> +            *fmt++ = AV_PIX_FMT_GRAY9;
>          } else if (CHROMA422(h))
>              *fmt++ = AV_PIX_FMT_YUV422P9;
>          else
> @@ -783,6 +786,8 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
>                  *fmt++ = AV_PIX_FMT_GBRP10;
>              } else
>                  *fmt++ = AV_PIX_FMT_YUV444P10;
> +        } else if (CHROMA400(h)) {
> +            *fmt++ = AV_PIX_FMT_GRAY10;
>          } else if (CHROMA422(h))
>              *fmt++ = AV_PIX_FMT_YUV422P10;
>          else
> @@ -794,6 +799,8 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
>                  *fmt++ = AV_PIX_FMT_GBRP12;
>              } else
>                  *fmt++ = AV_PIX_FMT_YUV444P12;
> +        } else if (CHROMA400(h)) {
> +            *fmt++ = AV_PIX_FMT_GRAY12;
>          } else if (CHROMA422(h))
>              *fmt++ = AV_PIX_FMT_YUV422P12;
>          else
> @@ -805,6 +812,8 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
>                  *fmt++ = AV_PIX_FMT_GBRP14;
>              } else
>                  *fmt++ = AV_PIX_FMT_YUV444P14;
> +        } else if (CHROMA400(h)) {
> +            *fmt++ = AV_PIX_FMT_GRAY14;
>          } else if (CHROMA422(h))
>              *fmt++ = AV_PIX_FMT_YUV422P14;
>          else
> @@ -824,6 +833,8 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
>                  *fmt++ = AV_PIX_FMT_YUVJ444P;
>              else
>                  *fmt++ = AV_PIX_FMT_YUV444P;
> +        } else if (CHROMA400(h)) {
> +            *fmt++ = AV_PIX_FMT_GRAY8;
>          } else if (CHROMA422(h)) {
>              if (h->avctx->color_range == AVCOL_RANGE_JPEG)
>                  *fmt++ = AV_PIX_FMT_YUVJ422P;
> diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h
> index 1d97232..7e9fc72 100644
> --- a/libavcodec/h264dec.h
> +++ b/libavcodec/h264dec.h
> @@ -95,6 +95,7 @@
>  #endif
>  
>  #define CHROMA(h)    ((h)->ps.sps->chroma_format_idc)
> +#define CHROMA400(h) ((h)->ps.sps->chroma_format_idc == 0)
>  #define CHROMA422(h) ((h)->ps.sps->chroma_format_idc == 2)
>  #define CHROMA444(h) ((h)->ps.sps->chroma_format_idc == 3)

Seems to work, but wait for someone more familiar with h264dec to review
and confirm it's ok.


More information about the ffmpeg-devel mailing list