diff --git a/decoder/ihevcd_api.c b/decoder/ihevcd_api.c index 7ac25f8..59342c0 100644 --- a/decoder/ihevcd_api.c +++ b/decoder/ihevcd_api.c @@ -2466,6 +2466,8 @@ WORD32 ihevcd_create(iv_obj_t *ps_codec_obj, ps_create_ip->u4_enable_yuv_formats = 1 << CHROMA_FMT_IDC_YUV420; } ps_codec->u4_enable_yuv_formats = ps_create_ip->u4_enable_yuv_formats; + ps_codec->u4_enable_hbd = ps_create_ip->u4_enable_hbd; + ret = ihevcd_init(ps_codec); TRACE_INIT(NULL); diff --git a/decoder/ihevcd_cxa.h b/decoder/ihevcd_cxa.h index 4d7df58..12a02fa 100644 --- a/decoder/ihevcd_cxa.h +++ b/decoder/ihevcd_cxa.h @@ -201,6 +201,18 @@ typedef struct { * NOTE: If this field is set to 0, YUV 4:2:0 will be enabled by default. */ UWORD32 u4_enable_yuv_formats; + + /** + * Flag specifying whether the decoder is allowed to support 10-bit decoding. + * + * Values and corresponding behavior: + * 0: Disable 10-bit decoding (only 8-bit decoding is supported) + * 1: Enable 10-bit decoding + * + * NOTE: When this field is set to 0, an error will be returned if + * bit_depth_luma_minus8 or bit_depth_chroma_minus8 are non-zero in SPS. + */ + UWORD32 u4_enable_hbd; }ihevcd_cxa_create_ip_t; diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c index 6bb3600..6e1a906 100644 --- a/decoder/ihevcd_parse_headers.c +++ b/decoder/ihevcd_parse_headers.c @@ -1709,6 +1709,11 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec) UEV_PARSE("bit_depth_luma_minus8", value, ps_bitstrm); + if ((0 == ps_codec->u4_enable_hbd) && (0 != value)) + { + ps_codec->s_parse.i4_error_code = IHEVCD_UNSUPPORTED_BIT_DEPTH; + return IHEVCD_UNSUPPORTED_BIT_DEPTH; + } // Limit the support to max bit depth of 10-bit if (value > 2) return IHEVCD_UNSUPPORTED_BIT_DEPTH; @@ -1722,6 +1727,11 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec) ps_sps->i1_bit_depth_luma_minus8 = value; UEV_PARSE("bit_depth_chroma_minus8", value, ps_bitstrm); + if ((0 == ps_codec->u4_enable_hbd) && (0 != value)) + { + ps_codec->s_parse.i4_error_code = IHEVCD_UNSUPPORTED_BIT_DEPTH; + return IHEVCD_UNSUPPORTED_BIT_DEPTH; + } // Limit the support to max bit depth of 10-bit if (value > 2) return IHEVCD_UNSUPPORTED_BIT_DEPTH; diff --git a/decoder/ihevcd_structs.h b/decoder/ihevcd_structs.h index 1ec8076..bbbf581 100644 --- a/decoder/ihevcd_structs.h +++ b/decoder/ihevcd_structs.h @@ -2082,6 +2082,11 @@ struct _codec_t */ UWORD32 u4_enable_yuv_formats; + /** + * Controls whether the decoder is allowed to support 10-bit decoding + */ + UWORD32 u4_enable_hbd; + /** * Pointer to hold TU data for a set of CTBs or a picture */ diff --git a/examples/decoder/main.c b/examples/decoder/main.c index f496af7..98d8cdf 100644 --- a/examples/decoder/main.c +++ b/examples/decoder/main.c @@ -231,6 +231,9 @@ typedef struct /* Enable YUV formats */ UWORD32 u4_enable_yuv_formats; + /* Enable High Bit Depth (10-bit) */ + UWORD32 u4_enable_hbd; + /* Active threads present*/ UWORD32 i4_active_threads; @@ -286,6 +289,7 @@ typedef enum PICLEN_FILE, ENABLE_YUV_FORMAT, + ENABLE_HBD, KEEP_THREADS_ACTIVE, }ARGUMENT_T; @@ -353,7 +357,9 @@ static const argument_t argument_mapping[] = { "--", "--soc", SOC, "Set SOC. Supported values GENERIC, HISI_37X \n" }, { "--", "--enable_yuv_format", ENABLE_YUV_FORMAT, - "Enable specific YUV formats" }, + "Enable specific YUV formats\n" }, + { "--", "--enable_hbd", ENABLE_HBD, + "Enable High Bit Depth (10-bit) decoding\n" }, {"--", "--keep_threads_active", KEEP_THREADS_ACTIVE, "Keep threads active"}, }; @@ -1346,6 +1352,10 @@ void parse_argument(vid_dec_ctx_t *ps_app_ctx, CHAR *argument, CHAR *value) sscanf(value, "%d", &ps_app_ctx->u4_enable_yuv_formats); break; + case ENABLE_HBD: + sscanf(value, "%d", &ps_app_ctx->u4_enable_hbd); + break; + case KEEP_THREADS_ACTIVE: sscanf(value, "%d", &ps_app_ctx->i4_active_threads); break; @@ -1895,6 +1905,7 @@ int main(WORD32 argc, CHAR *argv[]) s_app_ctx.u4_piclen_flag = 0; s_app_ctx.u4_frame_info_enable = 0; s_app_ctx.i4_active_threads = 1; + s_app_ctx.u4_enable_hbd = 1; s_app_ctx.fps = DEFAULT_FPS; file_pos = 0; total_bytes_comsumed = 0; @@ -2174,6 +2185,7 @@ int main(WORD32 argc, CHAR *argv[]) s_create_op.s_ivd_create_op_t.u4_size = sizeof(ihevcd_cxa_create_op_t); s_create_ip.u4_enable_frame_info = s_app_ctx.u4_frame_info_enable; s_create_ip.u4_enable_yuv_formats = s_app_ctx.u4_enable_yuv_formats; + s_create_ip.u4_enable_hbd = s_app_ctx.u4_enable_hbd; s_create_ip.u4_keep_threads_active = s_app_ctx.i4_active_threads; diff --git a/fuzzer/hevc_dec_fuzzer.cpp b/fuzzer/hevc_dec_fuzzer.cpp index 4cee442..5aadf78 100644 --- a/fuzzer/hevc_dec_fuzzer.cpp +++ b/fuzzer/hevc_dec_fuzzer.cpp @@ -119,6 +119,7 @@ void Codec::createCodec(FuzzedDataProvider &fdp) { create_ip.s_ivd_create_ip_t.pf_aligned_free = iv_aligned_free; create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL; create_ip.u4_enable_yuv_formats = 0b1111; // Enable 400, 420, 422 and 444 + create_ip.u4_enable_hbd = 1; create_ip.s_ivd_create_ip_t.u4_size = sizeof(ihevcd_cxa_create_ip_t); create_op.s_ivd_create_op_t.u4_size = sizeof(ihevcd_cxa_create_op_t); diff --git a/tests/decoder/DecHelper.cpp b/tests/decoder/DecHelper.cpp index 30638dc..7f04220 100644 --- a/tests/decoder/DecHelper.cpp +++ b/tests/decoder/DecHelper.cpp @@ -136,6 +136,7 @@ std::unique_ptr DecHelper::Builder::build() { helper->mInputFilePath = mInputFilePath; helper->mOutputFilePath = mOutputFilePath; helper->mRefMd5Path = mRefMd5Path; + helper->mEnableHbd = mEnableHbd; // Load and parse expected reference MD5s if the path is provided if (mRefMd5Path.has_value()) { @@ -214,6 +215,7 @@ bool DecHelper::initDecoder() { createIp.u4_enable_frame_info = 0; createIp.u4_enable_yuv_formats = 15; // Supports all chroma formats + createIp.u4_enable_hbd = mEnableHbd; createIp.u4_keep_threads_active = 1; IV_API_CALL_STATUS_T ret = diff --git a/tests/decoder/DecHelper.h b/tests/decoder/DecHelper.h index d7b9aac..e2a9287 100644 --- a/tests/decoder/DecHelper.h +++ b/tests/decoder/DecHelper.h @@ -62,6 +62,10 @@ class DecHelper { mRefMd5Path = path; return *this; } + Builder& setEnableHbd(bool enableHbd) { + mEnableHbd = enableHbd; + return *this; + } // Validates parameters and returns an initialized DecHelper instance std::unique_ptr build(); @@ -73,6 +77,7 @@ class DecHelper { std::optional mInputFilePath; std::optional mOutputFilePath; std::optional mRefMd5Path; + bool mEnableHbd = true; friend class DecHelper; }; @@ -116,6 +121,7 @@ class DecHelper { std::optional mOutputFilePath; std::optional mRefMd5Path; std::vector mRefMd5s; + bool mEnableHbd = true; BitsFile mBitsFile; RawFile mOutFile; diff --git a/tests/decoder/DecTests.cpp b/tests/decoder/DecTests.cpp index 84dacee..6b3e00e 100644 --- a/tests/decoder/DecTests.cpp +++ b/tests/decoder/DecTests.cpp @@ -74,6 +74,30 @@ TEST_P(DecTestFixture, DecodeVerify) { << "Decoding failed for input: " << inputPath; } +TEST(DecTest, Decode10bDisabledHbdError) { + const std::vector> k10bStreams = { + {"bbb_10b_176x144_yuv400.hevc", Format::yuv400p}, + {"bbb_10b_176x144_yuv420.hevc", Format::yuv420p}, + {"bbb_10b_176x144_yuv422.hevc", Format::yuv422p}, + {"bbb_10b_176x144_yuv444.hevc", Format::yuv444p}, + }; + for (const auto& [inputFile, format] : k10bStreams) { + std::string inputPath = getFullPath(inputFile); + auto builder = DecHelper::Builder() + .setInputFilePath(inputPath) + .setFormat(format) + .setEnableHbd(false); + + std::unique_ptr helper = builder.build(); + ASSERT_NE(helper, nullptr) + << "Failed to build DecHelper for input: " << inputPath; + EXPECT_FALSE(helper->decodeFile()) + << "Decoder should return an error when decoding 10-bit clip with " + "u4_enable_hbd set to 0 for: " + << inputPath; + } +} + static const std::vector kDecodeStreams = { {"bbb_176x144_yuv400.hevc", Format::yuv400p, "bbb_176x144_yuv400_md5.txt"}, {"bbb_176x144_yuv420.hevc", Format::yuv420p, "bbb_176x144_yuv420_md5.txt"},