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

Carl Eugen Hoyos ceffmpeg at gmail.com
Wed Aug 8 00:40:08 EEST 2018


2018-08-07 22:26 GMT+02:00, James Almer <jamrial at gmail.com>:
> 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.

Yes, removed.

>>                      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

Also removed.

>>                      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.

Done.

>>                  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.

Will do.

New patch attached, Carl Eugen
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-lavc-h264-Output-AV_PIX_FMT_GRAY-for-monochrome-inpu.patch
Type: text/x-patch
Size: 38627 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20180807/54fd6580/attachment.bin>


More information about the ffmpeg-devel mailing list