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 <ceffm...@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. _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel