From ecae1b96ac6eb0df508e158547c531c5697dd4c0 Mon Sep 17 00:00:00 2001 From: kkkuangzh Date: Thu, 4 Jul 2024 19:03:06 +0800 Subject: [PATCH] Base code for secure decoder plugin --- .../include/mfx_c2_decoder_component.h | 50 +- .../include/mfx_c2_secure_decoder_component.h | 84 + .../src/mfx_c2_components_registry.cpp | 8 + .../src/mfx_c2_decoder_component.cpp | 38 +- .../src/mfx_c2_secure_decoder_component.cpp | 743 +++++++ c2_store/data/media_codecs_intel_c2_video.xml | 25 + c2_store/data/mfx_c2_store.conf | 2 + c2_store/include/mfx_c2_store.h | 0 c2_utils/include/mfx_c2_avc_headers.h | 16 +- c2_utils/include/mfx_c2_utils.h | 7 +- .../include/mfx_c2_widevine_crypto_defs.h | 140 ++ c2_utils/include/mfx_c2_wrap_native_handle.h | 321 +++ c2_utils/include/mfx_debug.h | 2 +- c2_utils/include/mfx_defs.h | 7 +- c2_utils/include/mfx_dev.h | 2 + c2_utils/include/mfx_dev_va.h | 1 + c2_utils/include/mfx_frame_constructor.h | 131 +- c2_utils/include/mfx_va_allocator.h | 1 + c2_utils/include/mfx_va_private.h | 397 ++++ c2_utils/src/mfx_c2_utils.cpp | 84 +- c2_utils/src/mfx_dev_va.cpp | 50 + c2_utils/src/mfx_frame_constructor.cpp | 1811 ++++++++++++++++- c2_utils/src/mfx_va_allocator.cpp | 2 - 23 files changed, 3780 insertions(+), 142 deletions(-) mode change 100755 => 100644 c2_components/include/mfx_c2_decoder_component.h create mode 100644 c2_components/include/mfx_c2_secure_decoder_component.h create mode 100644 c2_components/src/mfx_c2_secure_decoder_component.cpp mode change 100644 => 100755 c2_store/data/media_codecs_intel_c2_video.xml mode change 100644 => 100755 c2_store/data/mfx_c2_store.conf mode change 100755 => 100644 c2_store/include/mfx_c2_store.h create mode 100644 c2_utils/include/mfx_c2_widevine_crypto_defs.h create mode 100644 c2_utils/include/mfx_c2_wrap_native_handle.h create mode 100644 c2_utils/include/mfx_va_private.h diff --git a/c2_components/include/mfx_c2_decoder_component.h b/c2_components/include/mfx_c2_decoder_component.h old mode 100755 new mode 100644 index 3f6fc2b8..95969ae4 --- a/c2_components/include/mfx_c2_decoder_component.h +++ b/c2_components/include/mfx_c2_decoder_component.h @@ -41,6 +41,10 @@ class MfxC2DecoderComponent : public MfxC2Component DECODER_VP8, DECODER_MPEG2, DECODER_AV1, +#ifdef ENABLE_WIDEVINE + DECODER_H264_SECURE, + DECODER_H265_SECURE +#endif }; enum class OperationState { @@ -103,7 +107,10 @@ class MfxC2DecoderComponent : public MfxC2Component c2_status_t Flush(std::list>* const flushedWork) override; -private: + // Work routines + c2_status_t ValidateWork(const std::unique_ptr& work); + +protected: c2_status_t UpdateC2Param(const mfxVideoParam* src, C2Param::Index index) const; void DoUpdateMfxParam(const std::vector ¶ms, @@ -137,11 +144,6 @@ class MfxC2DecoderComponent : public MfxC2Component mfxU16 GetAsyncDepth(); - // Work routines - c2_status_t ValidateWork(const std::unique_ptr& work); - - void DoWork(std::unique_ptr&& work); - void ReleaseReadViews(uint64_t incoming_frame_index); void EmptyReadViews(uint64_t timestamp, uint64_t frame_index); @@ -152,17 +154,19 @@ class MfxC2DecoderComponent : public MfxC2Component void FillEmptyWork(std::unique_ptr&& work, c2_status_t res); - void Drain(std::unique_ptr&& work); - // waits for the sync_point and update work with decoder output then - void WaitWork(MfxC2FrameOut&& frame_out, mfxSyncPoint sync_point); - - void PushPending(std::unique_ptr&& work); - void UpdateHdrStaticInfo(); void UpdateColorAspectsFromBitstream(const mfxExtVideoSignalInfo &signalInfo); -private: +protected: + void DoWork(std::unique_ptr&& work); + + void PushPending(std::unique_ptr&& work); + + void Drain(std::unique_ptr&& work); + // waits for the sync_point and update work with decoder output then + void WaitWork(MfxC2FrameOut&& frame_out, mfxSyncPoint sync_point); + DecoderType m_decoderType; std::unique_ptr m_device; @@ -173,6 +177,17 @@ class MfxC2DecoderComponent : public MfxC2Component MFXVideoSession m_mfxSession; #endif + std::atomic m_bEosReceived {}; + + MfxCmdQueue m_workingQueue; + MFX_TRACEABLE(m_workingQueue); + MfxCmdQueue m_waitingQueue; + MFX_TRACEABLE(m_waitingQueue); + + std::unique_ptr m_c2Bitstream; + mfxVideoParam m_mfxVideoParams {}; + +protected: // Accessed from working thread or stop method when working thread is stopped. std::unique_ptr m_mfxDecoder; @@ -183,12 +198,6 @@ class MfxC2DecoderComponent : public MfxC2Component OperationState m_OperationState { OperationState::INITIALIZATION }; - MfxCmdQueue m_workingQueue; - MFX_TRACEABLE(m_workingQueue); - MfxCmdQueue m_waitingQueue; - MFX_TRACEABLE(m_waitingQueue); - - mfxVideoParam m_mfxVideoParams {}; std::vector m_extBuffers; mfxExtVideoSignalInfo m_signalInfo; @@ -199,7 +208,6 @@ class MfxC2DecoderComponent : public MfxC2Component mfxU16 m_uMaxWidth {}; mfxU16 m_uMaxHeight {}; - std::atomic m_bEosReceived {}; // Members handling MFX_WRN_DEVICE_BUSY. // Active sync points got from DecodeFrameAsync for waiting on. std::atomic_uint m_uSyncedPointsCount; @@ -209,7 +217,7 @@ class MfxC2DecoderComponent : public MfxC2Component // Even atomic type needs to be mutex protected. std::mutex m_devBusyMutex; - std::unique_ptr m_c2Bitstream; + // Store raw pointers there as don't want to keep objects by shared_ptr std::map> m_surfaces; // all ever send to Decoder // Store all surfaces used for system memory diff --git a/c2_components/include/mfx_c2_secure_decoder_component.h b/c2_components/include/mfx_c2_secure_decoder_component.h new file mode 100644 index 00000000..8452d2e0 --- /dev/null +++ b/c2_components/include/mfx_c2_secure_decoder_component.h @@ -0,0 +1,84 @@ +// Copyright (c) 2017-2024 Intel Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "mfx_c2_component.h" +#include "mfx_c2_decoder_component.h" +#include "mfx_c2_components_registry.h" +#include "mfx_dev.h" +#include "mfx_cmd_queue.h" +#include "mfx_c2_frame_out.h" +#include "mfx_c2_bitstream_in.h" +#include "mfx_frame_pool_allocator.h" +#include "mfx_gralloc_instance.h" +#include "mfx_c2_setters.h" +#include + +class MfxC2SecureDecoderComponent : public MfxC2DecoderComponent +{ +public: + struct DecryptionTask + { + mfxU16 usStatusReportFeedbackNumber {0}; + VASurfaceID surfaceId {0}; + }; + +public: + MfxC2SecureDecoderComponent(const C2String name, const CreateConfig& config, + std::shared_ptr reflector, DecoderType decoder_type); + + virtual ~MfxC2SecureDecoderComponent(); + + static void RegisterClass(MfxC2ComponentsRegistry& registry); + + MFX_CLASS_NO_COPY(MfxC2SecureDecoderComponent) + +protected: + c2_status_t Init() override; + + c2_status_t Queue(std::list>* const items) override; + + c2_status_t DoStart() override; + + c2_status_t DoStop(bool abort) override; + + void Decrypt(std::unique_ptr&& work); + + void Dowork(std::unique_ptr&& work, DecryptionTask&& decryptionTask, mfxU32 feedbackNumber); + + bool CheckBitstream(); + + mfxStatus SubmitDecryptionTask(VAContextID contextId, + mfxU16 PESPacketCounter, + DecryptionTask& decryptionTask); + + mfxStatus WaitUtilDecryptionDone(DecryptionTask& decryptionTask, mfxU32 feedbackNumber); + +private: + MfxCmdQueue m_decryptionQueue; + MFX_TRACEABLE(m_decryptionQueue); + + mfxU32 m_decrytedFeedbackNumber = 0; + mfxU16 m_uDecrptingCount = 0; + /* -----------------------C2Parameters--------------------------- */ + std::shared_ptr m_secureMode; +}; + diff --git a/c2_components/src/mfx_c2_components_registry.cpp b/c2_components/src/mfx_c2_components_registry.cpp index d4a84367..770c4b88 100755 --- a/c2_components/src/mfx_c2_components_registry.cpp +++ b/c2_components/src/mfx_c2_components_registry.cpp @@ -33,6 +33,10 @@ #include "mfx_c2_encoder_component.h" #endif +#ifdef ENABLE_WIDEVINE +#include "mfx_c2_secure_decoder_component.h" +#endif + using namespace android; @@ -66,6 +70,10 @@ MfxC2ComponentsRegistry::MfxC2ComponentsRegistry() MfxC2DecoderComponent::RegisterClass(*this); MfxC2EncoderComponent::RegisterClass(*this); #endif + +#ifdef ENABLE_WIDEVINE + MfxC2SecureDecoderComponent::RegisterClass(*this); +#endif } MfxC2ComponentsRegistry& MfxC2ComponentsRegistry::getInstance() diff --git a/c2_components/src/mfx_c2_decoder_component.cpp b/c2_components/src/mfx_c2_decoder_component.cpp index 5dfcb4e6..007600a2 100755 --- a/c2_components/src/mfx_c2_decoder_component.cpp +++ b/c2_components/src/mfx_c2_decoder_component.cpp @@ -222,6 +222,7 @@ MfxC2DecoderComponent::MfxC2DecoderComponent(const C2String name, const CreateCo .build()); switch(m_decoderType) { + case DECODER_H264_SECURE: case DECODER_H264: { m_uOutputDelay = /*max_dpb_size*/16 + /*for async depth*/1 + /*for msdk unref in sync part*/1; @@ -277,6 +278,7 @@ MfxC2DecoderComponent::MfxC2DecoderComponent(const C2String name, const CreateCo .build()); break; } + case DECODER_H265_SECURE: case DECODER_H265: { m_uOutputDelay = /*max_dpb_size*/16 + /*for async depth*/1 + /*for msdk unref in sync part*/1; @@ -370,9 +372,8 @@ MfxC2DecoderComponent::MfxC2DecoderComponent(const C2String name, const CreateCo .oneOf({ PROFILE_VP9_0, PROFILE_VP9_1, - // TODO: support 10-bit HDR - // PROFILE_VP9_2, - // PROFILE_VP9_3, + PROFILE_VP9_2, + PROFILE_VP9_3, }), C2F(m_profileLevel, C2ProfileLevelStruct::level) .oneOf({ @@ -523,15 +524,9 @@ MfxC2DecoderComponent::MfxC2DecoderComponent(const C2String name, const CreateCo C2F(m_profileLevel, C2ProfileLevelStruct::level) .oneOf({ LEVEL_AV1_2, LEVEL_AV1_2_1, - LEVEL_AV1_2_2, LEVEL_AV1_2_3, + LEVEL_AV1_2_1, LEVEL_AV1_2_3, LEVEL_AV1_3, LEVEL_AV1_3_1, - LEVEL_AV1_3_2, LEVEL_AV1_3_3, - LEVEL_AV1_4, LEVEL_AV1_4_1, - LEVEL_AV1_4_2, LEVEL_AV1_4_3, - LEVEL_AV1_5, LEVEL_AV1_5_1, - LEVEL_AV1_5_2, LEVEL_AV1_5_3, - LEVEL_AV1_6, LEVEL_AV1_6_1, - LEVEL_AV1_6_2, LEVEL_AV1_6_3, + LEVEL_AV1_3_2, }),}) .withSetter(ProfileLevelSetter, m_size) .build()); @@ -882,6 +877,14 @@ void MfxC2DecoderComponent::InitFrameConstructor() case DECODER_AV1: fc_type = MfxC2FC_AV1; break; +#ifdef ENABLE_WIDEVINE + case DECODER_H264_SECURE: + fc_type = MfxC2FC_SEC_AVC; + break; + case DECODER_H265_SECURE: + fc_type = MfxC2FC_SEC_HEVC; + break; +#endif default: MFX_DEBUG_TRACE_MSG("unhandled codec type: BUG in plug-ins registration"); fc_type = MfxC2FC_None; @@ -1026,9 +1029,11 @@ mfxStatus MfxC2DecoderComponent::ResetSettings() switch (m_decoderType) { + case DECODER_H264_SECURE: case DECODER_H264: m_mfxVideoParams.mfx.CodecId = MFX_CODEC_AVC; break; + case DECODER_H265_SECURE: case DECODER_H265: m_mfxVideoParams.mfx.CodecId = MFX_CODEC_HEVC; break; @@ -1913,7 +1918,7 @@ void MfxC2DecoderComponent::EmptyReadViews(uint64_t timestamp, uint64_t frame_in auto it = m_duplicatedTimeStamp.begin(); for (; it != m_duplicatedTimeStamp.end(); it++) { - if (it->first < timestamp) { + if (it->first <= timestamp) { ReleaseReadViews(it->second); } } @@ -1968,15 +1973,6 @@ void MfxC2DecoderComponent::DoWork(std::unique_ptr&& work) } } return; - } else if (DECODER_AV1 == m_decoderType && m_c2Bitstream->IsInReset()) { - if (true == m_bInitialized) { - mfxStatus format_change_sts = HandleFormatChange(); - MFX_DEBUG_TRACE__mfxStatus(format_change_sts); - mfx_sts = format_change_sts; - if (MFX_ERR_NONE != mfx_sts) { - FreeDecoder(); - } - } } do { diff --git a/c2_components/src/mfx_c2_secure_decoder_component.cpp b/c2_components/src/mfx_c2_secure_decoder_component.cpp new file mode 100644 index 00000000..6ff7ac37 --- /dev/null +++ b/c2_components/src/mfx_c2_secure_decoder_component.cpp @@ -0,0 +1,743 @@ +// Copyright (c) 2017-2024 Intel Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "mfx_c2_secure_decoder_component.h" + +#include "mfx_defs.h" +#include "mfx_c2_utils.h" +#include "mfxstructures.h" +#include "mfxpcp.h" +#include + +#include "mfx_debug.h" +#include "mfx_msdk_debug.h" +#include "mfx_c2_debug.h" +#include "mfx_c2_components_registry.h" +#include "mfx_defaults.h" +#include "C2PlatformSupport.h" +#include + +#undef MFX_DEBUG_MODULE_NAME +#define MFX_DEBUG_MODULE_NAME "mfx_c2_secure_decoder_component" + +constexpr c2_nsecs_t TIMEOUT_NS = MFX_SECOND_NS; +constexpr mfxU16 DECRYPTION_BS_SIZE = 1024; +constexpr mfxU16 MAX_DECRYPTION_TASKS = 4; + +MfxC2SecureDecoderComponent::MfxC2SecureDecoderComponent(const C2String name, const CreateConfig& config, + std::shared_ptr reflector, DecoderType decoder_type) : + MfxC2DecoderComponent(name, config, std::move(reflector), decoder_type) +{ + MFX_DEBUG_TRACE_FUNC; + const unsigned int SINGLE_STREAM_ID = 0u; + + addParameter( + DefineParam(m_secureMode, C2_PARAMKEY_SECURE_MODE) + .withConstValue(new C2SecureModeTuning(C2Config::secure_mode_t::SM_READ_PROTECTED_WITH_ENCRYPTED)) + .build()); +} + +MfxC2SecureDecoderComponent::~MfxC2SecureDecoderComponent() +{ + MFX_DEBUG_TRACE_FUNC; + + MfxC2DecoderComponent::Release(); +} + +void MfxC2SecureDecoderComponent::RegisterClass(MfxC2ComponentsRegistry& registry) +{ + MFX_DEBUG_TRACE_FUNC; + + registry.RegisterMfxC2Component("c2.intel.avc.decoder.secure", + &MfxC2Component::Factory::Create); + + registry.RegisterMfxC2Component("c2.intel.hevc.decoder.secure", + &MfxC2Component::Factory::Create); +} + +c2_status_t MfxC2SecureDecoderComponent::Init() +{ + MFX_DEBUG_TRACE_FUNC; + + mfxStatus mfx_res = MFX_ERR_NONE; + c2_status_t c2_res = MfxC2DecoderComponent::Init(); + + if(C2_OK == c2_res) { + if (DECODER_H264_SECURE == m_decoderType) + mfx_res = m_device->CheckHUCSupport(VAProfileH264ConstrainedBaseline)? MFX_ERR_NONE:MFX_ERR_UNSUPPORTED; + else if (DECODER_H265_SECURE == m_decoderType) + mfx_res = m_device->CheckHUCSupport(VAProfileHEVCMain) ? MFX_ERR_NONE:MFX_ERR_UNSUPPORTED; + else + mfx_res = MFX_ERR_UNSUPPORTED; + } else { + return c2_res; + } + + return MfxStatusToC2(mfx_res); +} + +c2_status_t MfxC2SecureDecoderComponent::DoStart() +{ + MFX_DEBUG_TRACE_FUNC; + + c2_status_t c2_res = MfxC2DecoderComponent::DoStart(); + + if(C2_OK == c2_res) { + m_decryptionQueue.Start(); + } + + return C2_OK; +} + +c2_status_t MfxC2SecureDecoderComponent::DoStop(bool abort) +{ + MFX_DEBUG_TRACE_FUNC; + + c2_status_t c2_res = MfxC2DecoderComponent::DoStop(abort); + + if(C2_OK == c2_res) { + if (abort) { + m_decryptionQueue.Abort(); + } else { + m_decryptionQueue.Stop(); + } + } + + return C2_OK; +} + +c2_status_t MfxC2SecureDecoderComponent::Queue(std::list>* const items) +{ + MFX_DEBUG_TRACE_FUNC; + + for(auto& item : *items) { + c2_status_t sts = ValidateWork(item); + + if (C2_OK == sts) { + + if (m_bEosReceived) { // All works following eos treated as errors. + item->result = C2_BAD_VALUE; + // Do this in working thread to follow Drain completion. + m_workingQueue.Push( [work = std::move(item), this] () mutable { + PushPending(std::move(work)); + }); + } else { + bool eos = (item->input.flags & C2FrameData::FLAG_END_OF_STREAM); + bool empty = (item->input.buffers.size() == 0); + if (eos) { + m_bEosReceived = true; + } + MFX_DEBUG_TRACE_I32(eos); + MFX_DEBUG_TRACE_I32(empty); + if (eos && empty) { + m_workingQueue.Push( [work = std::move(item), this] () mutable { + Drain(std::move(work)); + }); + } else { + m_decryptionQueue.Push( [ work = std::move(item), this ] () mutable { + Decrypt(std::move(work)); + } ); + if (eos) { + m_workingQueue.Push( [this] () { Drain(nullptr); } ); + } + } + } + } else { + NotifyWorkDone(std::move(item), sts); + } + } + + return C2_OK; +} + +void MfxC2SecureDecoderComponent::Decrypt(std::unique_ptr&& work) +{ + MFX_DEBUG_TRACE_FUNC; + + c2_status_t res = C2_OK; + mfxStatus mfx_res = MFX_ERR_NONE; + + const auto incoming_frame_index = work->input.ordinal.frameIndex; + const auto incoming_flags = work->input.flags; + + MFX_DEBUG_TRACE_STREAM("work: " << work.get() << "; index: " << incoming_frame_index.peeku() << + " flags: " << std::hex << incoming_flags); + + do { + std::unique_ptr read_view; + res = m_c2Bitstream->AppendFrame(work->input, TIMEOUT_NS, &read_view); + if (C2_OK != res) break; + + if (!CheckBitstream()) break; + + // Get VAContextID + VAContextID contextId = VA_INVALID_ID; + MFXVideoCORE_GetHandle(m_mfxSession, static_cast(MFX_HANDLE_VA_CONTEXT_ID), (mfxHDL*)&contextId); + if (contextId == VA_INVALID_ID) { + mfx_res = MFX_ERR_INVALID_HANDLE; + break; + } + + DecryptionTask decryptionTask; + mfx_res = SubmitDecryptionTask(contextId, ++m_decrytedFeedbackNumber, decryptionTask); + if (MFX_ERR_MORE_DATA == mfx_res || MFX_WRN_DEVICE_BUSY == mfx_res) + m_decrytedFeedbackNumber--; + + m_workingQueue.Push( [&work, &decryptionTask, this] () { + Dowork(std::move(work), std::move(decryptionTask), this->m_decrytedFeedbackNumber); + } ); + } while(false); + +} + +void MfxC2SecureDecoderComponent::Dowork(std::unique_ptr&& work, DecryptionTask&& decryptionTask, mfxU32 feedbackNumber) +{ + MFX_DEBUG_TRACE_FUNC; + if (MFX_ERR_NONE != WaitUtilDecryptionDone(decryptionTask, feedbackNumber)) return; + + mfxExtCencParam decryptParams; + MFX_ZERO_MEMORY(decryptParams); + decryptParams.Header.BufferId = MFX_EXTBUFF_CENC_PARAM; + decryptParams.Header.BufferSz = sizeof(mfxExtCencParam); + decryptParams.StatusReportIndex = feedbackNumber; + + mfxExtBuffer* pExtBuf = &decryptParams.Header; + m_mfxVideoParams.ExtParam = &pExtBuf; + m_mfxVideoParams.NumExtParam = 1; + + if (m_bFlushing) { + m_flushedWorks.push_back(std::move(work)); + return; + } + + c2_status_t res = C2_OK; + mfxStatus mfx_sts = MFX_ERR_NONE; + + const auto incoming_frame_index = work->input.ordinal.frameIndex; + const auto incoming_flags = work->input.flags; + + MFX_DEBUG_TRACE_STREAM("work: " << work.get() << "; index: " << incoming_frame_index.peeku() << + " flags: " << std::hex << incoming_flags); + + bool expect_output = false; + bool flushing = false; + bool codecConfig = ((incoming_flags & C2FrameData::FLAG_CODEC_CONFIG) != 0); + // Av1 and VP9 don't need the bs which flag is config. + if (codecConfig && (DECODER_AV1 == m_decoderType || DECODER_VP9 == m_decoderType)) { + FillEmptyWork(std::move(work), C2_OK); + if (true == m_bInitialized) { + mfxStatus format_change_sts = HandleFormatChange(); + MFX_DEBUG_TRACE__mfxStatus(format_change_sts); + mfx_sts = format_change_sts; + if (MFX_ERR_NONE != mfx_sts) { + FreeDecoder(); + } + } + return; + } + + do { + std::unique_ptr read_view; + res = m_c2Bitstream->AppendFrame(work->input, TIMEOUT_NS, &read_view); + if (C2_OK != res) break; + + { + std::lock_guard lock(m_readViewMutex); + m_readViews.emplace(incoming_frame_index.peeku(), std::move(read_view)); + MFX_DEBUG_TRACE_I32(m_readViews.size()); + } + + if (work->input.buffers.size() == 0) break; + + PushPending(std::move(work)); + + if (!m_c2Allocator) { + res = GetCodec2BlockPool(m_outputPoolId, + shared_from_this(), &m_c2Allocator); + if (res != C2_OK) break; +#ifdef MFX_BUFFER_QUEUE + bool hasSurface = std::static_pointer_cast(m_c2Allocator)->outputSurfaceSet(); + m_mfxVideoParams.IOPattern = hasSurface ? MFX_IOPATTERN_OUT_VIDEO_MEMORY : MFX_IOPATTERN_OUT_SYSTEM_MEMORY; +#endif + if (m_mfxVideoParams.IOPattern == MFX_IOPATTERN_OUT_SYSTEM_MEMORY) { + m_allocator = nullptr; +#ifdef USE_ONEVPL + mfx_sts = MFXVideoCORE_SetFrameAllocator(m_mfxSession, nullptr); +#else + mfx_sts = m_mfxSession.SetFrameAllocator(nullptr); +#endif + m_bAllocatorSet = false; + ALOGI("System memory is being used for decoding!"); + + if (MFX_ERR_NONE != mfx_sts) break; + } + } + + // loop repeats DecodeFrame on the same frame + // if DecodeFrame returns error which is repairable, like resolution change + bool resolution_change = false; + do { + if (!m_bInitialized) { + mfx_sts = InitDecoder(m_c2Allocator); + if(MFX_ERR_NONE != mfx_sts) { + MFX_DEBUG_TRACE__mfxStatus(mfx_sts); + if (MFX_ERR_MORE_DATA == mfx_sts) { + mfx_sts = MFX_ERR_NONE; // not enough data for InitDecoder should not cause an error + } + res = MfxStatusToC2(mfx_sts); + break; + } + if (!m_bInitialized) { + MFX_DEBUG_TRACE_MSG("Cannot initialize mfx decoder"); + res = C2_BAD_VALUE; + break; + } + } + + if (!m_bSetHdrStatic) UpdateHdrStaticInfo(); + + mfxBitstream *bs = m_c2Bitstream->GetFrameConstructor()->GetMfxBitstream().get(); + MfxC2FrameOut frame_out; + do { + // check bitsream is empty + if (bs && bs->DataLength == 0) { + mfx_sts = MFX_ERR_MORE_DATA; + break; + } + + res = AllocateFrame(&frame_out); + if (C2_OK != res) break; + + mfx_sts = DecodeFrame(bs, std::move(frame_out), &flushing, &expect_output); + } while (mfx_sts == MFX_ERR_NONE || mfx_sts == MFX_ERR_MORE_SURFACE); + + if (MFX_ERR_MORE_DATA == mfx_sts) { + mfx_sts = MFX_ERR_NONE; // valid result of DecodeFrame + } + + resolution_change = (MFX_ERR_INCOMPATIBLE_VIDEO_PARAM == mfx_sts); + if (resolution_change) { + frame_out = MfxC2FrameOut(); // release the frame to be used in Drain + + Drain(nullptr); + + // Clear up all queue of works after drain except last work + // which caused resolution change and should be used again. + { + std::lock_guard lock(m_pendingWorksMutex); + auto it = m_pendingWorks.begin(); + while (it != m_pendingWorks.end()) { + if (it->first != incoming_frame_index) { + MFX_DEBUG_TRACE_STREAM("Work removed: " << NAMED(it->second->input.ordinal.frameIndex.peeku())); + NotifyWorkDone(std::move(it->second), C2_NOT_FOUND); + it = m_pendingWorks.erase(it); + } else { + ++it; + } + } + } + + mfxStatus format_change_sts = HandleFormatChange(); + MFX_DEBUG_TRACE__mfxStatus(format_change_sts); + mfx_sts = format_change_sts; + if (MFX_ERR_NONE != mfx_sts) { + FreeDecoder(); + } + } + + } while (resolution_change); // try again as it is a resolution change + + if (C2_OK != res) break; // if loop above was interrupted by C2 error + + if (MFX_ERR_NONE != mfx_sts) { + MFX_DEBUG_TRACE__mfxStatus(mfx_sts); + res = MfxStatusToC2(mfx_sts); + break; + } + + res = m_c2Bitstream->Unload(); + if (C2_OK != res) break; + + } while(false); // fake loop to have a cleanup point there + + bool incomplete_frame = + (incoming_flags & (C2FrameData::FLAG_INCOMPLETE | C2FrameData::FLAG_CODEC_CONFIG)) != 0; + + // sometimes the frame is split to several buffers with the same timestamp. + incomplete_frame |= IsPartialFrame(incoming_frame_index.peeku()); + + // notify listener in case of failure or empty output + if (C2_OK != res || !expect_output || incomplete_frame || flushing) { + if (!work) { + std::lock_guard lock(m_pendingWorksMutex); + auto it = m_pendingWorks.find(incoming_frame_index); + if (it != m_pendingWorks.end()) { + work = std::move(it->second); + m_pendingWorks.erase(it); + } else { + MFX_DEBUG_TRACE_STREAM("Not found C2Work, index = " << incoming_frame_index.peeku()); + // If not found, it might be removed by WaitWork. We don't need to return an error. + // FatalError(C2_CORRUPTED); + } + } + if (work) { + if (flushing) { + m_flushedWorks.push_back(std::move(work)); + } else { + FillEmptyWork(std::move(work), res); + } + } + } +} + +bool MfxC2SecureDecoderComponent::CheckBitstream() +{ + MFX_DEBUG_TRACE_FUNC; + + auto bs = m_c2Bitstream->GetFrameConstructor()->GetMfxBitstream(); + + if (!bs) return true; + + if ((bs->DataOffset + bs->DataLength) > bs->MaxLength) + return false; + + if (bs->EncryptedData) + { + mfxEncryptedData * encryptedData = bs->EncryptedData; + while (encryptedData) + { + if (!encryptedData->Data) + return false; + + if (!encryptedData->DataLength || ((encryptedData->DataOffset + encryptedData->DataLength) > encryptedData->MaxLength)) + return false; + + encryptedData = encryptedData->Next; + } + } + + return true; +} + +mfxStatus MfxC2SecureDecoderComponent::SubmitDecryptionTask(VAContextID contextId, + mfxU16 PESPacketCounter, + DecryptionTask& decryptionTask) +{ + MFX_DEBUG_TRACE_FUNC; + mfxStatus mfx_res = MFX_ERR_NONE; + + // Get VADisplay + VADisplay dpy = NULL; + if (MFX_ERR_NONE == mfx_res) + { + mfx_res = MFXVideoCORE_GetHandle(m_mfxSession, static_cast(MFX_HANDLE_VA_DISPLAY), (mfxHDL*)&dpy); + if (MFX_ERR_NONE == mfx_res) + { + if (!dpy) mfx_res = MFX_ERR_INVALID_HANDLE; + } + } + + if (VA_INVALID_ID == contextId) + mfx_res = MFX_ERR_NULL_PTR; + + auto m_pBitstream = m_c2Bitstream->GetFrameConstructor()->GetMfxBitstream(); + + HUCVideoBuffer* pHucBuffer = NULL; + if (MFX_ERR_NONE == mfx_res) + { + pHucBuffer = (HUCVideoBuffer*)(m_pBitstream->Data + m_pBitstream->DataOffset); + if (!pHucBuffer) + mfx_res = MFX_ERR_NULL_PTR; + } + + if (MFX_ERR_NONE == mfx_res) + { + if (pHucBuffer->drm_type == DRM_TYPE_CLASSIC_WV) + { + MFX_DEBUG_TRACE_MSG("DRM_TYPE_CLASSIC_WV"); + if (m_mfxVideoParams.Protected) + mfx_res = (m_mfxVideoParams.Protected == MFX_PROTECTION_CENC_WV_CLASSIC) ? mfx_res : MFX_ERR_UNDEFINED_BEHAVIOR; + else + m_mfxVideoParams.Protected = MFX_PROTECTION_CENC_WV_CLASSIC; + } + else if (pHucBuffer->drm_type == DRM_TYPE_MDRM) + { + MFX_DEBUG_TRACE_MSG("DRM_TYPE_MDRM"); + if (m_mfxVideoParams.Protected) + mfx_res = (m_mfxVideoParams.Protected == MFX_PROTECTION_CENC_WV_GOOGLE_DASH) ? mfx_res : MFX_ERR_UNDEFINED_BEHAVIOR; + else + m_mfxVideoParams.Protected = MFX_PROTECTION_CENC_WV_GOOGLE_DASH; + } + else + { + MFX_DEBUG_TRACE_MSG("Invalid DRM_TYPE"); + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + } + } + + if (MFX_ERR_NONE == mfx_res) + { + if (!m_pBitstream->EncryptedData) + { + MFX_DEBUG_TRACE_MSG("No EncryptedData"); + mfx_res = MFX_ERR_NULL_PTR; + } + } + + mfxU8* data = NULL; + mfxU32 dataSize = 0; + if (MFX_ERR_NONE == mfx_res) + { + data = m_pBitstream->EncryptedData->Data; + dataSize = m_pBitstream->EncryptedData->DataLength; + if (!data || !dataSize) + { + MFX_DEBUG_TRACE_MSG("Not enough EncryptedData->Data or EncryptedData->DataLength"); + MFX_DEBUG_TRACE_P(m_pBitstream->EncryptedData->Data); + MFX_DEBUG_TRACE_I32(m_pBitstream->EncryptedData->DataLength); + mfx_res = MFX_ERR_MORE_DATA; + } + } + + // Fill decryption params + VAEncryptionParameters PESInputParams; + MFX_ZERO_MEMORY(PESInputParams); + VAEncryptionSegmentInfo SegmentInfo[MAX_SUPPORTED_PACKETS]; + memset((mfxU8*)&(SegmentInfo[0]), 0, sizeof(VAEncryptionSegmentInfo)*MAX_SUPPORTED_PACKETS); + if (MFX_ERR_NONE == mfx_res) + { + if (m_mfxVideoParams.Protected == MFX_PROTECTION_CENC_WV_CLASSIC) + { + PESInputParams.encryption_type = VA_ENCRYPTION_TYPE_FULLSAMPLE_CBC; + } + else if (m_mfxVideoParams.Protected == MFX_PROTECTION_CENC_WV_GOOGLE_DASH) + { + PESInputParams.encryption_type = VA_ENCRYPTION_TYPE_SUBSAMPLE_CTR; + } + else + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + + PESInputParams.status_report_index = PESPacketCounter; + // PESInputParams.session_id = m_pBitstream->EncryptedData->AppId; + mfxU32 clearDataLength = 0; + for(int i = 0; i < pHucBuffer->uiNumPackets; i++) + { + if (pHucBuffer->sPacketData[i].clear) + { + clearDataLength += pHucBuffer->sPacketData[i].clearPacketSize; + } + else + { + SegmentInfo[PESInputParams.num_segments].segment_start_offset = pHucBuffer->sPacketData[i].sSegmentData.uiSegmentStartOffset - clearDataLength; + SegmentInfo[PESInputParams.num_segments].segment_length = pHucBuffer->sPacketData[i].sSegmentData.uiSegmentLength + clearDataLength; + SegmentInfo[PESInputParams.num_segments].partial_aes_block_size = pHucBuffer->sPacketData[i].sSegmentData.uiPartialAesBlockSizeInBytes; + SegmentInfo[PESInputParams.num_segments].init_byte_length = clearDataLength; + std::copy(std::begin(pHucBuffer->sPacketData[i].sSegmentData.uiAesIV), + std::end(pHucBuffer->sPacketData[i].sSegmentData.uiAesIV), + std::begin(SegmentInfo[PESInputParams.num_segments].aes_cbc_iv_or_ctr)); + + PESInputParams.num_segments++; + PESInputParams.segment_info = &(SegmentInfo[0]); + + clearDataLength = 0; + } + } + PESInputParams.size_of_length = 0;//pHucBuffer->ucSizeOfLength; //WA: 0 + } + + VAStatus va_res = VA_STATUS_SUCCESS; + VABufferID protectedSliceData = VA_INVALID_ID; + VABufferID protectedParams = VA_INVALID_ID; + mfxU8* buffer = NULL; + + // Submit bitstream for decryption + if (MFX_ERR_NONE == mfx_res) + { + va_res = vaCreateBuffer(dpy, + contextId, + VAProtectedSliceDataBufferType, + dataSize, + 1, + NULL, + &protectedSliceData); + MFX_DEBUG_TRACE_MSG("vaCreateBuffer"); + MFX_DEBUG_TRACE_I32(va_res); + mfx_res = va_to_mfx_status(va_res); + if (MFX_ERR_NONE != mfx_res) + { + MFX_DEBUG_TRACE_MSG("vaCreateBuffer() for protectedSliceData failed"); + } + + if (MFX_ERR_NONE == mfx_res) + { + va_res = vaMapBuffer(dpy, protectedSliceData, (void**)&buffer); + MFX_DEBUG_TRACE_MSG("vaMapBuffer"); + MFX_DEBUG_TRACE_I32(va_res); + mfx_res = va_to_mfx_status(va_res); + if (MFX_ERR_NONE != mfx_res) + { + MFX_DEBUG_TRACE_MSG("vaMapBuffer() for protectedSliceData failed"); + } + if (!buffer) + { + MFX_DEBUG_TRACE_MSG("vaMapBuffer() returned null buffer"); + mfx_res = MFX_ERR_MEMORY_ALLOC; + } + } + + if (MFX_ERR_NONE == mfx_res) + { + std::copy(data, data + dataSize, buffer); + vaUnmapBuffer(dpy, protectedSliceData); + MFX_DEBUG_TRACE_MSG("vaUnmapBuffer"); + } + } + + // Submit headers + if (MFX_ERR_NONE == mfx_res) + { + va_res = vaCreateBuffer(dpy, + contextId, + (VABufferType)VAEncryptionParameterBufferType, + sizeof(VAEncryptionParameters), + 1, + NULL, + &protectedParams); + MFX_DEBUG_TRACE_MSG("vaCreateBuffer"); + MFX_DEBUG_TRACE_I32(va_res); + mfx_res = va_to_mfx_status(va_res); + if (MFX_ERR_NONE != mfx_res) + { + MFX_DEBUG_TRACE_MSG("vaCreateBuffer() for protectedParams failed"); + } + + if (MFX_ERR_NONE == mfx_res) + { + va_res = vaMapBuffer(dpy, protectedParams, (void**)&buffer); + MFX_DEBUG_TRACE_MSG("vaMapBuffer"); + MFX_DEBUG_TRACE_I32(va_res); + mfx_res = va_to_mfx_status(va_res); + if (MFX_ERR_NONE != mfx_res) + { + MFX_DEBUG_TRACE_MSG("vaMapBuffer() for protectedParams failed"); + } + } + + if (MFX_ERR_NONE == mfx_res) + { + uint8_t *src = reinterpret_cast(&PESInputParams); + std::copy(src, src + sizeof(VAEncryptionParameters), buffer); + vaUnmapBuffer(dpy, protectedParams); + MFX_DEBUG_TRACE_MSG("vaUnmapBuffer"); + } + } + + if (MFX_ERR_NONE == mfx_res) + { + VABufferID buffers[2]; + buffers[0] = protectedSliceData; + buffers[1] = protectedParams; + + va_res = vaRenderPicture(dpy, contextId, &buffers[0], 2); + MFX_DEBUG_TRACE_MSG("vaRenderPicture"); + MFX_DEBUG_TRACE_I32(va_res); + mfx_res = va_to_mfx_status(va_res); + if (MFX_ERR_NONE != mfx_res) + { + MFX_DEBUG_TRACE_MSG("vaRenderPicture() failed"); + } + } + + if (MFX_ERR_NONE == mfx_res) + { + VADisplayContextP pDisplayContext = (VADisplayContextP)dpy; + VADriverContextP pDriverContext = pDisplayContext->pDriverContext; + + va_res = vaEndPicture(pDriverContext, contextId); + MFX_DEBUG_TRACE_MSG("vaEndPicture"); + MFX_DEBUG_TRACE_I32(va_res); + if (VA_STATUS_ERROR_SURFACE_BUSY == va_res) + { + mfx_res = MFX_WRN_DEVICE_BUSY; + MFX_DEBUG_TRACE_MSG("vaEndPicture() returns device busy status"); + } + else + { + mfx_res = va_to_mfx_status(va_res); + if (MFX_ERR_NONE != mfx_res) + { + MFX_DEBUG_TRACE_MSG("vaEndPicture() failed"); + } + } + } + + if ((MFX_ERR_NONE == mfx_res || MFX_WRN_DEVICE_BUSY == mfx_res) && (VA_INVALID_ID != protectedParams)) + { + va_res = vaDestroyBuffer(dpy, protectedParams); + MFX_DEBUG_TRACE_MSG("vaDestroyBuffer"); + MFX_DEBUG_TRACE_I32(va_res); + mfxStatus sts = va_to_mfx_status(va_res); + if (MFX_ERR_NONE != sts) + { + mfx_res = sts; + MFX_DEBUG_TRACE_MSG("vaDestroyBuffer() for protectedParams failed"); + } + } + + if (MFX_ERR_NONE == mfx_res) + { + decryptionTask.surfaceId = protectedSliceData; + decryptionTask.usStatusReportFeedbackNumber = m_decrytedFeedbackNumber; + } else { + MFX_DEBUG_TRACE_STREAM("SubmitDecryptionTask failed, mfx_res = " << mfx_res); + va_res = vaDestroyBuffer(dpy, protectedSliceData); + mfxStatus sts = va_to_mfx_status(va_res); + if (MFX_ERR_NONE != sts) + { + mfx_res = sts; + MFX_DEBUG_TRACE_MSG("vaDestroyBuffer() for protectedSliceData failed"); + } + } + + MFX_DEBUG_TRACE_I32(mfx_res); + return mfx_res; +} + +mfxStatus MfxC2SecureDecoderComponent::WaitUtilDecryptionDone(DecryptionTask& decryptionTask, mfxU32 feedbackNumber) +{ + MFX_DEBUG_TRACE_FUNC; + mfxStatus mfx_res = MFX_ERR_NONE; + + // Get VADisplay + VADisplay dpy = NULL; + MFXVideoCORE_GetHandle(m_mfxSession, static_cast(MFX_HANDLE_VA_DISPLAY), (mfxHDL*)&dpy); + + do { + if (!dpy) { + mfx_res = MFX_ERR_INVALID_HANDLE; + break; + } + auto va_res = vaSyncSurface(dpy, decryptionTask.surfaceId); + mfx_res = va_to_mfx_status(va_res); + } while (false); + + MFX_DEBUG_TRACE_I32(mfx_res); + return mfx_res; +} diff --git a/c2_store/data/media_codecs_intel_c2_video.xml b/c2_store/data/media_codecs_intel_c2_video.xml old mode 100644 new mode 100755 index b41d20af..a0a2de4c --- a/c2_store/data/media_codecs_intel_c2_video.xml +++ b/c2_store/data/media_codecs_intel_c2_video.xml @@ -88,6 +88,31 @@ and updated to vendor media codecs. + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/c2_store/data/mfx_c2_store.conf b/c2_store/data/mfx_c2_store.conf old mode 100644 new mode 100755 index 1576694c..925c1ba8 --- a/c2_store/data/mfx_c2_store.conf +++ b/c2_store/data/mfx_c2_store.conf @@ -7,3 +7,5 @@ c2.intel.vp9.decoder : libmfx_c2_components_hw.so c2.intel.vp8.decoder : libmfx_c2_components_hw.so c2.intel.mp2.decoder : libmfx_c2_components_hw.so c2.intel.av1.decoder : libmfx_c2_components_hw.so +c2.intel.avc.decoder.secure : libmfx_c2_components_hw.so +c2.intel.hevc.decoder.secure : libmfx_c2_components_hw.so diff --git a/c2_store/include/mfx_c2_store.h b/c2_store/include/mfx_c2_store.h old mode 100755 new mode 100644 diff --git a/c2_utils/include/mfx_c2_avc_headers.h b/c2_utils/include/mfx_c2_avc_headers.h index 51500b97..9b14435e 100644 --- a/c2_utils/include/mfx_c2_avc_headers.h +++ b/c2_utils/include/mfx_c2_avc_headers.h @@ -142,17 +142,17 @@ class AVCHeaders void Reset() { - m_SeqParams.Reset(); - m_SeqExParams.Reset(); - m_SeqParamsMvcExt.Reset(); - m_PicParams.Reset(); + m_seqParams.Reset(); + m_seqExParams.Reset(); + m_seqParamsMvcExt.Reset(); + m_picParams.Reset(); m_SEIParams.Reset(); } - HeaderSet m_SeqParams; - HeaderSet m_SeqExParams; - HeaderSet m_SeqParamsMvcExt; - HeaderSet m_PicParams; + HeaderSet m_seqParams; + HeaderSet m_seqExParams; + HeaderSet m_seqParamsMvcExt; + HeaderSet m_picParams; HeaderSet m_SEIParams; AVCNalExtension m_nalExtension; }; diff --git a/c2_utils/include/mfx_c2_utils.h b/c2_utils/include/mfx_c2_utils.h index 6acd2a9b..63236175 100755 --- a/c2_utils/include/mfx_c2_utils.h +++ b/c2_utils/include/mfx_c2_utils.h @@ -28,6 +28,8 @@ c2_status_t MfxStatusToC2(mfxStatus mfx_status); +mfxStatus va_to_mfx_status(VAStatus vaSts); + inline mfxU64 TimestampC2ToMfx(uint64_t timestamp) { return timestamp * 90000 / MFX_SECOND_NS; @@ -120,8 +122,6 @@ bool IsI420(const C2GraphicView &view); bool IsYV12(const C2GraphicView &view); -bool IsP010(const C2GraphicView &view); - void ParseGop(const std::shared_ptr gop, uint32_t &syncInterval, uint32_t &iInterval, uint32_t &maxBframes); @@ -221,9 +221,6 @@ template<>struct mfx_ext_buffer_id { template<>struct mfx_ext_buffer_id { enum {id = MFX_EXTBUFF_ENCODER_RESET_OPTION }; }; -template<>struct mfx_ext_buffer_id { - enum {id = MFX_EXTBUFF_CODING_OPTION3}; -}; template struct ExtParamAccessor diff --git a/c2_utils/include/mfx_c2_widevine_crypto_defs.h b/c2_utils/include/mfx_c2_widevine_crypto_defs.h new file mode 100644 index 00000000..46db064a --- /dev/null +++ b/c2_utils/include/mfx_c2_widevine_crypto_defs.h @@ -0,0 +1,140 @@ +// Copyright (c) 2017-2024 Intel Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#define SEC_VIDEO_BUFFER_SIZE (3*1024*1024) +#define WV_AES_IV_SIZE 16 +#define DRM_TYPE_CLASSIC_WV 0x0 +#define DRM_TYPE_MDRM 0x1 +#define PROTECTED_DATA_BUFFER_MAGIC (0UL | ('E' << 24) | ('B' << 16) | ('D' << 8) | 'P') + +#define INPORT_BUFFER_SIZE 1650000 +typedef struct { + uint32_t offset; + uint32_t size; +} sec_partition_t; +typedef struct { + sec_partition_t src; + sec_partition_t dest; + sec_partition_t metadata; + sec_partition_t headers; +} video_partition_t; +typedef struct { + uint8_t config[64]; + uint8_t config_len; + uint32_t config_frame_offset; + uint8_t key_id[16]; + uint32_t key_id_len; + uint8_t session_id; +} mdrm_meta; +typedef struct { + uint32_t size; + uint32_t base_offset; + video_partition_t partitions; + uint32_t frame_size; + uint32_t src_fill; + uint8_t pes_packet_count; + uint8_t clear; + mdrm_meta mdrm_info; + uint8_t drm_type; //0 -> Classic, 1 -> MDRM + uint8_t iv[WV_AES_IV_SIZE]; + + uint32_t first_sub_sample; //used by liboemcrypto + uint32_t configdata_multiple_sub_sample; //used by liboemcrypto + uint32_t sps_pps_sample; //used by liboemcrypto + uint32_t nf_stream; //used by liboemcrypto + uint32_t meta_offset; //used by liboemcrypto + uint32_t parsed_data_size = 0; + uint32_t m_PAVPAppID; + bool skipFailedFrame = false; + bool waitForIDR = false; + uint8_t m_config_nalu[1024]; + uint32_t m_config_nalu_len = 0; + uint8_t base[SEC_VIDEO_BUFFER_SIZE]; +} SECVideoBuffer; + +#define MAX_SUPPORTED_PACKETS 50 // Can be scaled based on the need +#define PAVP_APPID_INVALID 0xffff // OMX to validate against this AppID + +// Below structure is inline as per libVA doc and is applicable only for encrypted packets (both Classic as well as MDRM) +typedef struct { + uint32_t uiSegmentStartOffset; + uint32_t uiSegmentLength; + uint32_t uiPartialAesBlockSizeInBytes; + uint32_t uiInitByteLength; + uint8_t uiAesIV[WV_AES_IV_SIZE]; +} segment_info; +typedef struct { + bool clear; // true - clear, false - enc (in which case segmentinfo struct would be populated) + uint32_t clearPacketSize; // Applicable only for clear packet + uint32_t clearPacketOffset; // Populated only for clear packet, offset within SECVideoBuffer->base ptr. For encrypted packet refer to segment_info struct + uint8_t configData; // Currently: 0 - No Config data(actual clear frame), 1 - Config data (SPS/PPS), will be enum + segment_info sSegmentData; +} packet_info; +typedef struct { + uint32_t appID; // OMX to use this AppID + uint32_t frame_size; // Total frame length filled by Oemcrypto into base ptr, Should be <= INPORT_BUFFER_SIZE + uint8_t uiNumPackets; // Subsample for MDRM and PES packets for Classic, Should be <= MAX_SUPPORTED_PACKETS (i.e., 20) + packet_info sPacketData[MAX_SUPPORTED_PACKETS]; // Packet details for max supported packets + uint8_t drm_type; // 0 - Classic, 1 - MDRM + uint8_t ucSizeOfLength; // For MDRM purpose, This would be '0' as we use only start code based NALU (as discussed in our call). + uint32_t uiCurrSegPartialAesBlockSizeInBytes; // Internal Member to calc Partial Aes block size required in case of MDRM enc Nalus + uint32_t uiEncDataSize; // Internal Member to calc whole Aes blocks for IV updation in case of MDRM enc nalus + uint8_t base[INPORT_BUFFER_SIZE]; // Input buffer allocated by OMX, Oemcrypto fills it and shared it for processing +} HUCVideoBuffer; + + +typedef struct { + uint8_t iv[WV_AES_IV_SIZE]; + uint32_t mode; + uint32_t app_id; +} pr_pavp_info_t; +typedef struct __DRM_SubSamples { + uint32_t numClearBytes; + uint32_t numEncryptedBytes; +} DRM_SubSamples; +typedef struct { + uint32_t pr_magic; //PR_MAGIC + pr_pavp_info_t pavp_info; + uint32_t pavp_frame_data_size; + uint32_t nalu_info_data_size; + uint32_t num_nalus; + uint32_t isSPSPPSAvailable; + uint32_t total_data_size; + uint32_t total_encr_bytes; + uint32_t sps_length; + uint32_t pps_length; + size_t numSubSamples; + DRM_SubSamples pVideoSubSamples[16]; + uint8_t* pVideoDecryptContext; + uint64_t pr_iv; + uint8_t databuffer[INPORT_BUFFER_SIZE]; +} pr_metadata_buffer; + +typedef struct { + uint32_t magic; + uint32_t index; + union{ + HUCVideoBuffer hucBuffer; // Allocated in Oemcrypto based on #input buffers and shared to OMX + SECVideoBuffer secBuffer; // same + }; + pr_metadata_buffer pr_data; //This data struct is defined to hold whole pavp encrypted frame data. +} C2SecureBuffer; diff --git a/c2_utils/include/mfx_c2_wrap_native_handle.h b/c2_utils/include/mfx_c2_wrap_native_handle.h new file mode 100644 index 00000000..d602afff --- /dev/null +++ b/c2_utils/include/mfx_c2_wrap_native_handle.h @@ -0,0 +1,321 @@ +// Copyright (c) 2017-2024 Intel Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +template +class NativeHandle : protected native_handle +{ +public: + + using type = NativeHandle; + + constexpr static int numFds = NUM_FDS; + + constexpr static int numInts = NUM_INTS; + + constexpr static int arrayLength = numFds + numInts; + + static type* create() noexcept + { + type* handle = static_cast(native_handle_create(numFds, numInts)); + + if (handle != nullptr) + { + std::fill(handle->data, handle->data + arrayLength, 0); + } + + return handle; + } + // End of create() + + // Cast from a compatible native_handle_t. If types are not compatible, + // return nullptr. + // + static type* cast(native_handle_t* nh) + { + if (nh == nullptr) + { + return nullptr; + } + + if ( nh->version != sizeof(native_handle_t) + || nh->numFds != NUM_FDS || nh->numInts != NUM_INTS ) + { + return nullptr; + } + + return static_cast(nh); + } + // End of cast() + + native_handle_t* cast() + { + return static_cast(this); + } + + int close() noexcept + { + return native_handle_close(this); + } + + int destroy() noexcept + { + return native_handle_delete(this); + } + + static void destroy(type*& nh) + { + if (nh == nullptr) + { + return; + } + + nh->destroy(); + nh = nullptr; + } + // End of destroy() (static) + + int getVersion() const noexcept + { + return this->version; + } + + int* fd_begin() + { + return data; + } + + const int* fd_begin() const + { + return data; + } + + int* fd_end() + { + return data + numFds; + } + + const int* fd_end() const + { + return data + numFds; + } + + int* int_begin() + { + return fd_end(); + } + + const int* int_begin() const + { + return fd_end(); + } + + int* int_end() + { + return data + arrayLength; + } + + const int* int_end() const + { + return data + arrayLength; + } + +protected: + + NativeHandle() = default; + ~NativeHandle() = default; + +}; +// End of NativeHandle + +// Integer, which "PBNH", but no 0 terminator +constexpr uint32_t PROTECTED_BUFFER_HANDLE_MAGIC = (0UL | ('H' << 24) | ('N' << 16) | ('B' << 8) | 'P'); + +// ProtectedBufferHandlePayload +// +// Data that is stored as integers inside of native_handle_t::data +// +#pragma pack(push, 4) +struct ProtectedBufferHandlePayload +{ + // Magic value, used for debugging + uint32_t magic = PROTECTED_BUFFER_HANDLE_MAGIC; + + // Buffer ID (should be a random number) + uint32_t bufferId = 0; + + // Buffer pointer on C2 side + uint8_t* c2Buf = nullptr; + + // Buffer pointer on OEMCrypto side + uint8_t* oecBuf = nullptr; +}; +// End of ProtectedBufferHandlePayload +#pragma pack(pop) + +// A native_handle with 1 file descryptor and enough space to store ProtectedBufferHandlePayload. +// +using ProtectedBufferNativeHandle = NativeHandle<1, sizeof (ProtectedBufferHandlePayload) / sizeof(int)>; + +// ProtectedBufferHandle +// +class ProtectedBufferHandle : protected ProtectedBufferNativeHandle +{ +public: + + static ProtectedBufferHandle* create() + { + ProtectedBufferHandle* handle = static_cast(ProtectedBufferNativeHandle::create()); + + if (handle != nullptr) + { + handle->initMagic(); + } + + return handle; + } + // End of create() + + // Cast from a compatible native_handle_t. If types are not compatible, + // return nullptr. + // + static ProtectedBufferHandle* cast(native_handle_t* nh) + { + if (nh == nullptr) + { + return nullptr; + } + + ProtectedBufferNativeHandle* pbNative = ProtectedBufferNativeHandle::cast(nh); + if (pbNative == nullptr) + { + return nullptr; + } + + return static_cast(pbNative); + } + // End of cast() + + ProtectedBufferNativeHandle* cast() + { + return static_cast(this); + } + + const ProtectedBufferNativeHandle* cast() const + { + return static_cast(this); + } + + native_handle_t* native_handle_cast() + { + return static_cast(this); + } + + const native_handle_t* native_handle_cast() const + { + return static_cast(this); + } + + int close() noexcept + { + return ProtectedBufferNativeHandle::close(); + } + + int destroy() noexcept + { + return ProtectedBufferNativeHandle::destroy(); + } + + int getVersion() const + { + return ProtectedBufferNativeHandle::getVersion(); + } + + int getFd() const + { + return *fd_begin(); + } + + void setFd(int fd) + { + *fd_begin() = fd; + } + + bool isGoodMagic() const + { + return getPayload()->magic == PROTECTED_BUFFER_HANDLE_MAGIC; + } + + uint32_t getBufferId() const + { + return getPayload()->bufferId; + } + + void setBufferId(uint32_t bufferId) + { + getPayload()->bufferId = bufferId; + } + + uint8_t* getC2Buf() const + { + return getPayload()->c2Buf; + } + + void setC2Buf(uint8_t* c2Buf) + { + getPayload()->c2Buf = c2Buf; + } + + uint8_t* getOecBuf() const + { + return getPayload()->oecBuf; + } + + void setOecBuf(uint8_t* oecBuf) + { + getPayload()->oecBuf = oecBuf; + } + +protected: + + ProtectedBufferHandle() = default; + ~ProtectedBufferHandle() = default; + + ProtectedBufferHandlePayload* getPayload() + { + return reinterpret_cast(int_begin()); + } + + const ProtectedBufferHandlePayload* getPayload() const + { + return reinterpret_cast(int_begin()); + } + + void initMagic() + { + getPayload()->magic = PROTECTED_BUFFER_HANDLE_MAGIC; + } +}; +// End of ProtectedBufferHandle diff --git a/c2_utils/include/mfx_debug.h b/c2_utils/include/mfx_debug.h index c4ecda8e..13b3a48e 100755 --- a/c2_utils/include/mfx_debug.h +++ b/c2_utils/include/mfx_debug.h @@ -23,7 +23,7 @@ #define MFX_DEBUG_NO 0 #define MFX_DEBUG_YES 1 -#define MFX_DEBUG MFX_DEBUG_NO // enables DEBUG output +#define MFX_DEBUG MFX_DEBUG_YES // enables DEBUG output #define MFX_PERF MFX_DEBUG_NO // enables PERF output, doesn't depends on MFX_DEBUG #define MFX_ATRACE MFX_DEBUG_NO // enables systrace #define MFX_DEBUG_DUMP_FRAME MFX_DEBUG_NO // enables write frame to file diff --git a/c2_utils/include/mfx_defs.h b/c2_utils/include/mfx_defs.h index 42e48323..e7a5de75 100755 --- a/c2_utils/include/mfx_defs.h +++ b/c2_utils/include/mfx_defs.h @@ -46,6 +46,9 @@ #define USE_GRALLOC1 #endif // MFX_C2_USE_PRIME #endif // HAVE_GRALLOC4 + +#define ENABLE_WIDEVINE + #define DRV_I915 #include @@ -197,7 +200,7 @@ std::vector MakeVector(T&& item) mfxStatus InitMfxFrameSW( uint64_t timestamp, uint64_t frame_index, - uint8_t *data_Y, uint8_t *data_UV, + uint8_t *data, uint32_t width, uint32_t height, uint32_t stride, uint32_t fourcc, const mfxFrameInfo& info, mfxFrameSurface1* mfx_frame); mfxStatus InitMfxFrameHW( @@ -205,7 +208,7 @@ mfxStatus InitMfxFrameHW( mfxMemId mem_id, uint32_t width, uint32_t height, uint32_t fourcc, const mfxFrameInfo& info, mfxFrameSurface1* mfx_frame); -mfxStatus MFXLoadSurfaceSW(uint8_t *data_Y, uint8_t *data_UV, uint32_t stride, const mfxFrameInfo& input_info, mfxFrameSurface1* srf); +mfxStatus MFXLoadSurfaceSW(uint8_t *data, uint32_t stride, const mfxFrameInfo& input_info, mfxFrameSurface1* srf); uint32_t MFXGetSurfaceSize(uint32_t FourCC, uint32_t width, uint32_t height); uint32_t MFXGetFreeSurfaceIdx(mfxFrameSurface1 *SurfacesPool, uint32_t nPoolSize); diff --git a/c2_utils/include/mfx_dev.h b/c2_utils/include/mfx_dev.h index 8e6233e2..ad07b2d7 100755 --- a/c2_utils/include/mfx_dev.h +++ b/c2_utils/include/mfx_dev.h @@ -48,6 +48,8 @@ class MfxDev virtual std::shared_ptr GetFramePoolAllocator() = 0; + virtual bool CheckHUCSupport(VAProfile profile) = 0; + #ifdef USE_ONEVPL virtual mfxStatus InitMfxSession(mfxSession session) = 0; #else diff --git a/c2_utils/include/mfx_dev_va.h b/c2_utils/include/mfx_dev_va.h index f6553beb..f668d1aa 100755 --- a/c2_utils/include/mfx_dev_va.h +++ b/c2_utils/include/mfx_dev_va.h @@ -36,6 +36,7 @@ class MfxDevVa : public MfxDev public: VADisplay GetVaDisplay() { return m_vaDisplay; } + bool CheckHUCSupport(VAProfile profile); private: mfxStatus Init() override; diff --git a/c2_utils/include/mfx_frame_constructor.h b/c2_utils/include/mfx_frame_constructor.h index 902d107b..73d9b19d 100755 --- a/c2_utils/include/mfx_frame_constructor.h +++ b/c2_utils/include/mfx_frame_constructor.h @@ -21,6 +21,14 @@ #pragma once #include "mfx_defs.h" +#ifdef ENABLE_WIDEVINE +#include "mfx_c2_widevine_crypto_defs.h" +#include "mfx_c2_wrap_native_handle.h" +#include "mfx_va_private.h" +#include "mfx_c2_bs_utils.h" +#include "mfx_c2_avc_bitstream.h" +#include "mfx_c2_hevc_bitstream.h" +#endif #include #include #include @@ -34,6 +42,10 @@ enum MfxC2FrameConstructorType MfxC2FC_VP9, MfxC2FC_MP2, MfxC2FC_AV1, + #ifdef ENABLE_WIDEVINE + MfxC2FC_SEC_AVC, + MfxC2FC_SEC_HEVC, + #endif }; enum MfxC2BitstreamState @@ -69,8 +81,6 @@ class IMfxC2FrameConstructor virtual mfxPayload* GetSEI(mfxU32 /*type*/) = 0; // save current SPS/PPS virtual mfxStatus SaveHeaders(std::shared_ptr sps, std::shared_ptr pps, bool is_reset) = 0; - // get whether in reset state - virtual bool IsInReset() = 0; protected: struct StartCode @@ -112,8 +122,6 @@ class MfxC2FrameConstructor : public IMfxC2FrameConstructor (void)is_reset; return MFX_ERR_NONE; } - // get whether in reset state - virtual bool IsInReset(); protected: // functions virtual mfxStatus LoadHeader(const mfxU8* data, mfxU32 size, bool header); @@ -151,7 +159,6 @@ class MfxC2FrameConstructor : public IMfxC2FrameConstructor mfxU32 m_uBstBufReallocs; mfxU32 m_uBstBufCopyBytes; - bool m_bInReset; private: MFX_CLASS_NO_COPY(MfxC2FrameConstructor) }; @@ -175,7 +182,7 @@ class MfxC2AVCFrameConstructor : public MfxC2FrameConstructor virtual mfxStatus SaveSEI(mfxBitstream * /*pSEI*/) {return MFX_ERR_NONE;} virtual mfxStatus FindHeaders(const mfxU8* data, mfxU32 size, bool &found_sps, bool &found_pps, bool &found_sei); - virtual StartCode ReadStartCode(const mfxU8** position, mfxU32* size_left); + virtual StartCode ReadStartCode(const mfxU8** position, mfxU32& size_left); virtual bool isSPS(mfxI32 code) { return NAL_UT_AVC_SPS == code; } virtual bool isPPS(mfxI32 code) { return NAL_UT_AVC_PPS == code; } virtual bool isSEI(mfxI32 /*code*/) {return false;} @@ -207,7 +214,7 @@ class MfxC2HEVCFrameConstructor : public MfxC2AVCFrameConstructor const static mfxU32 SEI_CONTENT_LIGHT_LEVEL_INFO = 144; protected: // functions - virtual StartCode ReadStartCode(const mfxU8** position, mfxU32* size_left); + virtual StartCode ReadStartCode(const mfxU8** position, mfxU32& size_left); virtual bool isSPS(mfxI32 code) { return NAL_UT_HEVC_SPS == code; } virtual bool isPPS(mfxI32 code) { return NAL_UT_HEVC_PPS == code; } // save current SEI @@ -230,6 +237,116 @@ class MfxC2HEVCFrameConstructor : public MfxC2AVCFrameConstructor MFX_CLASS_NO_COPY(MfxC2HEVCFrameConstructor) }; +#ifdef ENABLE_WIDEVINE +class MfxC2SecureFrameConstructor +{ +public: + MfxC2SecureFrameConstructor(); + virtual ~MfxC2SecureFrameConstructor(); + + MFX_CLASS_NO_COPY(MfxC2SecureFrameConstructor) + +protected: + virtual mfxStatus Reset(void); + virtual mfxStatus ResetHeaders(void); + virtual mfxStatus ConstructFrame(VACencStatusBuf* cencStatus, mfxBitstream* bs); + virtual mfxStatus Load(const mfxU8* data, mfxU32 size, mfxU64 pts, bool header, bool complete_frame); + virtual mfxEncryptedData* GetFreeEncryptedDataItem(void); + virtual mfxEncryptedData* BuildEncryptedDataList(void); + virtual mfxStatus GetSliceHeader(mfxU8* data, mfxU32 size, mfxU8 **sliceHdr, mfxU32 &sliceHdrlength); + + virtual mfxStatus PackSliceHeader(OutputBitstream & obs, mfxU8* data, mfxU32 size) = 0; + virtual mfxStatus ParseHeaders() = 0; + +protected: + static const mfxU32 SLICE_HEADER_BUFFER_SIZE = 128; + std::list m_encryptedDataList; + HUCVideoBuffer m_hucBuffer; + + // Actual SPS/PPS/SEI headers + mfxBitstream m_SPS_PPS_SEI; + // tmp buffer for slice header packing + std::vector m_sliceHeader; + // m_ClearBst contains clear data - SPS, PPS, SEI, slice header + mfxBitstream m_ClearBst; +}; + +class MfxC2AVCSecureFrameConstructor : public MfxC2HEVCFrameConstructor, public MfxC2SecureFrameConstructor +{ +public: + MfxC2AVCSecureFrameConstructor(); + virtual ~MfxC2AVCSecureFrameConstructor(void); + MFX_CLASS_NO_COPY(MfxC2AVCSecureFrameConstructor) + + virtual mfxStatus Reset(void); + virtual mfxStatus Load(const mfxU8* data, mfxU32 size, mfxU64 pts, bool b_header, bool bCompleteFrame); + +protected: + virtual bool isSPS(mfxI32 code) {return MfxC2AVCFrameConstructor::isSPS(code);} + virtual bool isPPS(mfxI32 code) {return MfxC2AVCFrameConstructor::isPPS(code);} + virtual bool isIDR(mfxI32 code) {return NAL_UT_AVC_IDR_SLICE == code;} + virtual bool isRegularSlice(mfxI32 code) {return NAL_UT_AVC_SLICE == code;} + + std::shared_ptr GetMfxBitstream(); + + virtual mfxStatus ParseHeaders(); + virtual mfxStatus ParseNalUnit(mfxU8 * const data, mfxU32 NAlUnitSize); + virtual mfxStatus PackSliceHeader(OutputBitstream & obs, mfxU8* data, mfxU32 size); + + mfxU8* GetMemoryForSwapping(mfxU32 size); + +protected: + bool m_bNeedAttachSPSPPS; + + const static mfxU32 NAL_UT_AVC_SLICE = 1; + const static mfxU32 NAL_UT_AVC_IDR_SLICE = 5; + + AVCParser::AVCHeaders m_H264Headers; + std::vector m_swappingMemory; +}; + +/*------------------------------------------------------------------------------*/ + +class MfxC2HEVCSecureFrameConstructor : public MfxC2AVCSecureFrameConstructor +{ +public: + MfxC2HEVCSecureFrameConstructor(); + virtual ~MfxC2HEVCSecureFrameConstructor(void); + + MFX_CLASS_NO_COPY(MfxC2HEVCSecureFrameConstructor) +protected: + virtual StartCode ReadStartCode(const mfxU8** position, mfxU32& size_left); + virtual bool isSPS(mfxI32 code) {return MfxC2HEVCFrameConstructor::isSPS(code);} + virtual bool isPPS(mfxI32 code) {return MfxC2HEVCFrameConstructor::isPPS(code);} + virtual bool isIDR(mfxI32 code) {return (NAL_UT_HEVC_SLICE_IDR_W_RADL == code) || (NAL_UT_HEVC_SLICE_IDR_N_LP == code);} + virtual bool isRegularSlice(mfxI32 code); + + virtual mfxStatus ParseNalUnit(mfxU8 * const data, mfxU32 NAlUnitSize); + virtual mfxStatus PackSliceHeader(OutputBitstream & obs, mfxU8* data, mfxU32 size); + +protected: + const static mfxU32 NAL_UT_HEVC_SLICE_TRAIL_N = 0; + const static mfxU32 NAL_UT_HEVC_SLICE_TRAIL_R = 1; + const static mfxU32 NAL_UT_HEVC_SLICE_TSA_N = 2; + const static mfxU32 NAL_UT_HEVC_SLICE_TLA_R = 3; + const static mfxU32 NAL_UT_HEVC_SLICE_STSA_N = 4; + const static mfxU32 NAL_UT_HEVC_SLICE_STSA_R = 5; + const static mfxU32 NAL_UT_HEVC_SLICE_RADL_N = 6; + const static mfxU32 NAL_UT_HEVC_SLICE_RADL_R = 7; + const static mfxU32 NAL_UT_HEVC_SLICE_RASL_N = 8; + const static mfxU32 NAL_UT_HEVC_SLICE_RASL_R = 9; + const static mfxU32 NAL_UT_HEVC_SLICE_BLA_W_LP = 16; + const static mfxU32 NAL_UT_HEVC_SLICE_BLA_W_RADL = 17; + const static mfxU32 NAL_UT_HEVC_SLICE_BLA_N_LP = 18; + const static mfxU32 NAL_UT_HEVC_SLICE_IDR_W_RADL = 19; + const static mfxU32 NAL_UT_HEVC_SLICE_IDR_N_LP = 20; + const static mfxU32 NAL_UT_HEVC_SLICE_CRA = 21; + + HEVCParser::HEVCHeaders m_H265Headers; + int32_t previous_poc; +}; +#endif + class MfxC2FrameConstructorFactory { public: diff --git a/c2_utils/include/mfx_va_allocator.h b/c2_utils/include/mfx_va_allocator.h index f0c722e2..85264f7c 100755 --- a/c2_utils/include/mfx_va_allocator.h +++ b/c2_utils/include/mfx_va_allocator.h @@ -26,6 +26,7 @@ #include "mfx_allocator.h" #include "mfx_frame_converter.h" #include "mfx_gralloc_instance.h" +#include "mfx_c2_utils.h" #include #include diff --git a/c2_utils/include/mfx_va_private.h b/c2_utils/include/mfx_va_private.h new file mode 100644 index 00000000..ba7475f1 --- /dev/null +++ b/c2_utils/include/mfx_va_private.h @@ -0,0 +1,397 @@ +// Copyright (c) 2017-2024 Intel Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +/** +* \file va_cp_private.h +* \brief Content protection private API +* +* This file contains the \ref api_cp_private "Content Protection API". +*/ + +#pragma once + +#include +#include "va/va.h" + +/** + * \defgroup api_intel cp Content Protection API + * + * @{ + * + * The content protection API uses the same paradigm for codec. + * - Query for supported encryption attributes through VAConfigAttribEncryption. + * - create the specific configuration with the accepted encryption attributes got from the query. + * - Set up a codec pipeline; + + * The basic operation steps for cenc decode are: + * - Query for supported encryption attributes through VAConfigAttribEncryption. + * - Create configuration with one of encryption attributes got from the above step. + * - Create a video decode. + * - Pass the render buffers with the corresponding data to CENC decode, including: + * encrypted bitstream through VAProtectedSliceDataBufferType; + * encryption paramters through VAEncryptionParameters. + * - Make the end of CENC call via vaEndCenc + * - Get CENC result via vaQueryCenc. + * - Pass the render buffers with the corresponding data to decode, including: + * CENC status report number through VACencStatusParameterBufferType. + * DPB information through VAPictureParameterBuffer. + * - Make the end of decode call via vaEndPicture + */ + +/**\brief encryption parameters buffer for vendor content protection usage. + * The buffer corresponds to #VAEncryptionParameters for va/cp*/ +#define VAEncryptionParameterBufferType -2 +/**\brief CENC status paramter, used for vendor content protection only. + * The buffer corresponds to #VACencStatusParameters for va/cp*/ +#define VACencStatusParameterBufferType -3 + +/** attribute values for VAConfigAttribEncryption */ +#define VA_ENCRYPTION_TYPE_NONE 0x00000000 +#define VA_ENCRYPTION_TYPE_BASIC 0x00000001 +#define VA_ENCRYPTION_TYPE_CENC_CBC 0x00000002 +#define VA_ENCRYPTION_TYPE_CENC_CTR_LENGTH 0x00000004 +#define VA_ENCRYPTION_TYPE_CENC_CTR 0x00000008 +#define VA_ENCRYPTION_TYPE_CTR_128 0x00000010 + + +/** \brief values for the encryption return status. */ +typedef enum +{ + /** \brief Indicate encryption operation is successful.*/ + VA_ENCRYPTION_STATUS_SUCCESSFUL = 0, + /** \brief Indicate encryption operation is incomplete. */ + VA_ENCRYPTION_STATUS_INCOMPLETE, + /** \brief Indicate encryption operation is error.*/ + VA_ENCRYPTION_STATUS_ERROR, + /** \brief Indicate the buf in VACencStatusBuf is full. */ + VA_ENCRYPTION_STATUS_BUFFER_FULL, + /** \brief Indicate encryption operation is unsupport. */ + VA_ENCRYPTION_STATUS_UNSUPPORT +} VAEncryptionStatus; + +/** \brief cenc status parameters, corresonding to #VACencStatusParameterBufferType*/ +typedef struct _VACencStatusParameters +{ + /** \brief The status report index feedback. */ + uint32_t status_report_index_feedback; + /** \brief Reserved bytes for future use, must be zero */ + uint32_t va_reserved[VA_PADDING_MEDIUM]; +} VACencStatusParameters; +/** + * \brief Slice parameter for H.264 cenc decode in baseline, main & high profiles. + * + * This structure holds information for \c + * slice_layer_without_partitioning_rbsp() and nal_unit()of the slice + * as defined by the H.264 specification. + * + */ +typedef struct _VACencSliceParameterBufferH264 { + + /** \brief Parameters from \c nal_unit() of the slice.*/ + /**@{*/ + /** \brief Same as the H.264 bitstream syntax element. */ + uint8_t nal_ref_idc; + /** \brief Indicate if this is coded slice of an IDR picture. + * Corresponds to IdrPicFlag as the H.264 specification.*/ + uint8_t idr_pic_flag; + /**@}*/ + /** \brief Same as the H.264 bitstream syntax element. */ + uint8_t slice_type; + /** \brief Indicate if this is a field or frame picture. + * \c VA_FRAME_PICTURE, \c VA_TOP_FIELD, \c VA_BOTTOM_FIELD*/ + uint8_t field_frame_flag; + /** \brief Same as the H.264 bitstream syntax element. */ + uint32_t frame_number; + /** \brief Same as the H.264 bitstream syntax element. */ + uint32_t idr_pic_id; + /** \brief Same as the H.264 bitstream syntax element. */ + int32_t pic_order_cnt_lsb; + /** \brief Same as the H.264 bitstream syntax element. */ + int32_t delta_pic_order_cnt_bottom; + /** \brief Same as the H.264 bitstream syntax element. */ + int32_t delta_pic_order_cnt[2]; + /** + * \brief decoded reference picture marking. Information for \c + * dec_ref_pic_marking() as defined by the H.264 specification. + */ + /**@{*/ + union { + struct { + /** \brief Same as the H.264 bitstream syntax element. */ + uint32_t no_output_of_prior_pics_flag : 1; + /** \brief Same as the H.264 bitstream syntax element. */ + uint32_t long_term_reference_flag : 1; + /** \brief Same as the H.264 bitstream syntax element. */ + uint32_t adaptive_ref_pic_marking_mode_flag : 1; + /** \brief number of decode reference picture marking. */ + uint32_t dec_ref_pic_marking_count : 8;; + /** \brief Reserved for future use, must be zero */ + uint32_t reserved : 21; + } bits; + uint32_t value; + } ref_pic_fields; + /** \brief Same as the H.264 bitstream syntax element. */ + uint8_t memory_management_control_operation[32]; + /** \brief Same as the H.264 bitstream syntax element. */ + int32_t difference_of_pic_nums_minus1[32]; + /** \brief Same as the H.264 bitstream syntax element. */ + int32_t long_term_pic_num[32]; + /** \brief Same as the H.264 bitstream syntax element. */ + int32_t max_long_term_frame_idx_plus1[32]; + /** \brief Same as the H.264 bitstream syntax element. */ + int32_t long_term_frame_idx[32]; + /**@}*/ + /** \brief Pointer to the next #VACencSliceParameterBufferH264 element, + * or \c NULL if there is none.*/ + void *next; + /** \brief Reserved bytes for future use, must be zero */ + unsigned long va_reserved[VA_PADDING_MEDIUM]; +} VACencSliceParameterBufferH264; + +/** + * \brief Slice parameter for HEVC cenc decode in main & main 10 profiles. + * + * This structure holds information for \c + * slice_segment_header() and nal_unit_header() of the slice as + * defined by the HEVC specification. + * + */ +typedef struct _VACencSliceParameterBufferHEVC { + /** \brief Same as the HEVC bitstream syntax element. */ + uint8_t nal_unit_type; + /** \brief Corresponds to the HEVC bitstream syntax element. + * Same as nuh_temporal_id_plus1 - 1*/ + uint8_t nuh_temporal_id; + /** \brief Slice type. + * Corresponds to HEVC syntax element of the same name. */ + uint8_t slice_type; + /** \brief Same as the HEVC bitstream syntax element. */ + uint16_t slice_pic_order_cnt_lsb; + /** \brief Indicates EOS_NUT or EOB_NUT is detected in picture. */ + uint16_t has_eos_or_eob; + + union { + struct { + /** \brief Same as the HEVC bitstream syntax element */ + uint32_t no_output_of_prior_pics_flag : 1; + /** \brief Same as the HEVC bitstream syntax element */ + uint32_t pic_output_flag : 1; + /** \brief Same as the HEVC bitstream syntax element */ + uint32_t colour_plane_id : 2; + /** \brief Reserved for future use, must be zero */ + uint32_t reserved : 19; + } bits; + uint32_t value; + } slice_fields; + + /** \brief Parameters for driver reference frame set */ + /**@{*/ + + /** \brief number of entries as current before in short-term rps + * Corresponds to NumPocStCurrBefore as the HEVC specification. */ + uint8_t num_of_curr_before; + /** \brief number of entries as current after in short-term rps + * Corresponds to NumPocStCurrAfter as the HEVC specification. */ + uint8_t num_of_curr_after; + /** \brief number of entries as current total in short-term rps*/ + uint8_t num_of_curr_total; + /** \brief number of entries as foll in short-term rps + * Corresponds to NumPocStFoll as the HEVC specification.*/ + uint8_t num_of_foll_st; + /** \brief number of entries as current in long-term rps + * Corresponds to NumPocLtCurr as the HEVC specification. */ + uint8_t num_of_curr_lt; + /** \brief number of entries as foll in long-term rps + * Corresponds to NumPocLtFoll as the HEVC specification.*/ + uint8_t num_of_foll_lt; + /** \brief delta poc as short-term current before + * Corresponds to PocStCurrBefore as the HEVC specification. */ + int32_t delta_poc_curr_before[8]; + /** \brief delta poc as short-term current after + * Corresponds to PocStCurrAfter, as the HEVC specification.*/ + int32_t delta_poc_curr_after[8]; + /** \brief delta poc as short-term current total */ + int32_t delta_poc_curr_total[8]; + /** \brief delta poc as short-term foll + * Corresponds to PocStFoll as the HEVC specification.*/ + int32_t delta_poc_foll_st[16]; + /** \brief delta poc as long-term current + * Corresponds to PocLtCurr as the HEVC specification.*/ + int32_t delta_poc_curr_lt[8]; + /** \brief delta poc as long-term foll + * Corresponds to PocLtFoll, as the HEVC specification.*/ + int32_t delta_poc_foll_lt[16]; + /** \brief delta poc msb present flag + * Same as the HEVC bitstream syntax element. */ + uint8_t delta_poc_msb_present_flag[16]; + /** \brief long-term reference RPS is used for reference by current picture*/ + uint8_t is_lt_curr_total[8]; + /** \brief index of reference picture list. [0] is for P and B slice, [1] is for B slice*/ + uint8_t ref_list_idx[2][16]; + /**@}*/ + /** \brief Pointer to the next #VACencSliceParameterBufferHEVC element, + * or \c NULL if there is none.*/ + void *next; + /** \brief Reserved bytes for future use, must be zero */ + unsigned long va_reserved[VA_PADDING_MEDIUM]; +} VACencSliceParameterBufferHEVC; + +/** + * \brief uncompressed header for VP9 cenc decode + * + * This structure holds information for \c + * uncompressed_header() as defined by the VP9 specification. + * + */ +typedef struct _VACencSliceParameterBufferVP9 { + + union { + struct { + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t profile : 2; + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t show_existing_frame_flag : 1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t frame_to_show_map_idx : 3; + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t frame_type : 1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t show_frame : 1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t error_resilient_mode : 1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t intra_only : 1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t ten_or_twelve_bit : 1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t color_space : 3; + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t color_range : 1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t subsampling_x : 1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t subsampling_y : 1; + /** \brief Corresponds to ref_frame_idx[0] + * as the VP9 specification */ + uint32_t ref_frame_idx0 : 3; + /** \brief Corresponds to ref_frame_sign_bias[LAST_FRAME] + * as the VP9 specification */ + uint32_t ref_frame_sign_bias0 : 1; + /** \brief Corresponds to ref_frame_idx[1] + * as the VP9 specification */ + uint32_t ref_frame_idx1 : 3; + /** \brief Corresponds to ref_frame_sign_bias[GOLDEN_FRAME] + * as the VP9 specification */ + uint32_t ref_frame_sign_bias1 : 1; + /** \brief Corresponds to ref_frame_idx[2] + * as the VP9 specification */ + uint32_t ref_frame_idx2 : 3; + /** \brief Corresponds to ref_frame_sign_bias[ALTREF_FRAME] + * as the VP9 specification */ + uint32_t ref_frame_sign_bias2 : 1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t frame_parallel_decoding_mode : 1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint32_t render_and_frame_size_different : 1; + /** \brief Reserved for future use, must be zero */ + uint32_t reserved : 1; + } bits; + uint32_t value; + } header_fields; + /** \brief Same as the VP9 bitstream syntax element. */ + uint16_t frame_width_minus1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint16_t frame_height_minus1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint16_t render_width_minus1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint16_t render_height_minus1; + /** \brief Same as the VP9 bitstream syntax element. */ + uint8_t refresh_frame_flags; + /** \brief Parameters for super frame*/ + /**@{*/ + /** \brief Superframe index, from 0 to frames_in_superframe_minus_1. + * as the VP9 specification */ + uint8_t sf_index; + /** \brief Superframe size, corresponds to frame_sizes[ sf_index ] + * as the VP9 specification */ + uint32_t sf_frame_size; + /**@}*/ + /** \brief Pointer to the next #VACencSliceParameterBufferVP9 element, + * or \c NULL if there is none.*/ + void *next; + /** \brief Reserved bytes for future use, must be zero */ + unsigned long va_reserved[VA_PADDING_MEDIUM]; +} VACencSliceParameterBufferVP9; + +/** \brief Cenc Slice Buffer Type*/ +typedef enum { + /** \brief Parsed slice parameters \c VACencSliceParameterBuffer* */ + VaCencSliceBufParamter = 1, + /** \brief Raw slice header of bitstream*/ + VaCencSliceBufRaw = 2 +} VACencSliceBufType; + +/** \brief Buffer for CENC status reporting*/ +typedef struct _VACencStatusBuf +{ + /** \brief Encryption status. VA_ENCRYPTION_STATUS_SUCCESSFUL if + * hardware has returned detailed inforamtion, others mean the + * CENC result is invalid */ + VAEncryptionStatus status; + /* \brief feedback of status report index + * This value is the feedback of status_report_number of + * \ref VAEncryptionParameters to indicate the CENC workload*/ + uint32_t status_report_index_feedback; + /** \brief Buf size in bytes. 0 means buf is invalid*/ + uint32_t buf_size; + /** \brief Buffer formatted as raw data from bitstream for sequence parameter, + * picture parameter, SEI parameters. Or \c NULL means buf is invalid.*/ + void *buf; + /** \brief Slice buffer type, see \c VACencSliceBufTypex */ + VACencSliceBufType slice_buf_type; + /** \brief Slice buffer size in bytes. 0 means slice_buf is invalid*/ + uint32_t slice_buf_size; + /** \brief Slice buffer, parsed slice header information. Or \c NULL + * means slice_buf is invalid.*/ + void *slice_buf; + /** \brief Reserved bytes for future use, must be zero */ + unsigned long va_reserved[VA_PADDING_MEDIUM]; +} VACencStatusBuf; + +typedef struct _mfxAES128CipherCounter{ + mfxU64 IV; + mfxU64 Count; +} mfxAES128CipherCounter; + + +typedef struct _mfxEncryptedData{ + mfxEncryptedData *Next; + mfxHDL reserved1; + mfxU8 *Data; + mfxU32 DataOffset; /* offset, in bytes, from beginning of buffer to first byte of encrypted data*/ + mfxU32 DataLength; /* size of plain data in bytes */ + mfxU32 MaxLength; /*allocated buffer size in bytes*/ + mfxAES128CipherCounter CipherCounter; + mfxU32 AppId; + mfxU32 reserved2[7]; +} mfxEncryptedData; + +/**@}*/ diff --git a/c2_utils/src/mfx_c2_utils.cpp b/c2_utils/src/mfx_c2_utils.cpp index 4f236a07..f8b191e8 100755 --- a/c2_utils/src/mfx_c2_utils.cpp +++ b/c2_utils/src/mfx_c2_utils.cpp @@ -74,6 +74,57 @@ c2_status_t MfxStatusToC2(mfxStatus mfx_status) } } +mfxStatus va_to_mfx_status(VAStatus vaSts) +{ + switch (vaSts) + { + case VA_STATUS_SUCCESS: + { + return MFX_ERR_NONE; + } + case VA_STATUS_ERROR_OPERATION_FAILED: + { + return MFX_ERR_ABORTED; + } + case VA_STATUS_ERROR_DECODING_ERROR: + case VA_STATUS_ERROR_ENCODING_ERROR: + { + return MFX_ERR_DEVICE_FAILED; + } + case VA_STATUS_ERROR_ALLOCATION_FAILED: + { + return MFX_ERR_MEMORY_ALLOC; + } + case VA_STATUS_ERROR_INVALID_DISPLAY: + case VA_STATUS_ERROR_INVALID_CONFIG: + case VA_STATUS_ERROR_INVALID_CONTEXT: + case VA_STATUS_ERROR_INVALID_SURFACE: + case VA_STATUS_ERROR_INVALID_BUFFER: + case VA_STATUS_ERROR_INVALID_IMAGE: + case VA_STATUS_ERROR_INVALID_SUBPICTURE: + case VA_STATUS_ERROR_INVALID_PARAMETER: + case VA_STATUS_ERROR_INVALID_IMAGE_FORMAT: + { + return MFX_ERR_INVALID_HANDLE; + } + case VA_STATUS_ERROR_ATTR_NOT_SUPPORTED: + case VA_STATUS_ERROR_UNSUPPORTED_PROFILE: + case VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT: + case VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT: + case VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE: + case VA_STATUS_ERROR_FLAG_NOT_SUPPORTED: + case VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED: + case VA_STATUS_ERROR_UNIMPLEMENTED: + { + return MFX_ERR_UNSUPPORTED; + } + default: + { + return MFX_ERR_UNKNOWN; + } + } +} + c2_status_t GetC2ConstGraphicBlock( const C2FrameData& buf_pack, std::unique_ptr* c_graph_block) { @@ -514,7 +565,7 @@ int MfxFourCCToGralloc(mfxU32 fourcc, bool using_video_memory) case MFX_FOURCC_NV12: return using_video_memory ? HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL : HAL_PIXEL_FORMAT_NV12; case MFX_FOURCC_P010: - return using_video_memory ? HAL_PIXEL_FORMAT_P010_INTEL : HAL_PIXEL_FORMAT_YCBCR_P010; + return HAL_PIXEL_FORMAT_P010_INTEL; default: return 0; } @@ -759,37 +810,6 @@ bool IsYV12(const C2GraphicView &view) { && layout.planes[layout.PLANE_V].offset == 0); } -bool IsP010(const C2GraphicView &view) { - const C2PlanarLayout &layout = view.layout(); - return (layout.numPlanes == 3 - && layout.type == C2PlanarLayout::TYPE_YUV - && layout.planes[layout.PLANE_Y].channel == C2PlaneInfo::CHANNEL_Y - && layout.planes[layout.PLANE_Y].allocatedDepth == 16 - && layout.planes[layout.PLANE_Y].bitDepth == 10 - && layout.planes[layout.PLANE_Y].rightShift == 6 - && layout.planes[layout.PLANE_Y].colSampling == 1 - && layout.planes[layout.PLANE_Y].rowSampling == 1 - && layout.planes[layout.PLANE_U].channel == C2PlaneInfo::CHANNEL_CB - && layout.planes[layout.PLANE_U].allocatedDepth == 16 - && layout.planes[layout.PLANE_U].bitDepth == 10 - && layout.planes[layout.PLANE_U].rightShift == 6 - && layout.planes[layout.PLANE_U].colSampling == 2 - && layout.planes[layout.PLANE_U].rowSampling == 2 - && layout.planes[layout.PLANE_V].channel == C2PlaneInfo::CHANNEL_CR - && layout.planes[layout.PLANE_V].allocatedDepth == 16 - && layout.planes[layout.PLANE_V].bitDepth == 10 - && layout.planes[layout.PLANE_V].rightShift == 6 - && layout.planes[layout.PLANE_V].colSampling == 2 - && layout.planes[layout.PLANE_V].rowSampling == 2 - && layout.rootPlanes == 2 - && layout.planes[layout.PLANE_U].colInc == 4 - && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_U - && layout.planes[layout.PLANE_U].offset == 0 - && layout.planes[layout.PLANE_V].colInc == 4 - && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_U - && layout.planes[layout.PLANE_V].offset == 2); -} - void ParseGop( const std::shared_ptr gop, uint32_t &syncInterval, uint32_t &iInterval, uint32_t &maxBframes) { diff --git a/c2_utils/src/mfx_dev_va.cpp b/c2_utils/src/mfx_dev_va.cpp index 2d52fca4..c620a30e 100755 --- a/c2_utils/src/mfx_dev_va.cpp +++ b/c2_utils/src/mfx_dev_va.cpp @@ -29,6 +29,10 @@ #include +#ifdef ENABLE_WIDEVINE +#include "mfx_va_private.h" +#endif + #undef MFX_DEBUG_MODULE_NAME #define MFX_DEBUG_MODULE_NAME "mfx_dev_va" @@ -215,4 +219,50 @@ std::shared_ptr MfxDevVa::GetFramePoolAllocator() return m_usage == Usage::Decoder ? m_vaPoolAllocator : nullptr; } +bool MfxDevVa::CheckHUCSupport(VAProfile profile) +{ + MFX_DEBUG_TRACE_FUNC; + + return true; + + mfxStatus mfx_res = MFX_ERR_NONE; + VAStatus va_res = VA_STATUS_SUCCESS; + + if (!m_vaDisplay) mfx_res = MFX_ERR_INVALID_HANDLE; + + VAEntrypoint entrypoint = VAEntrypointVLD; + VAConfigAttrib attrib[1]; + attrib[0].type = VAConfigAttribEncryption; + + if (mfx_res == MFX_ERR_NONE) + { + va_res = vaGetConfigAttributes(m_vaDisplay, profile, entrypoint, &attrib[0], sizeof(attrib)/sizeof(attrib[0])); + mfx_res = ((VA_STATUS_SUCCESS == va_res) ? MFX_ERR_NONE: MFX_ERR_UNKNOWN); + } + + if (mfx_res == MFX_ERR_NONE) + { + if (!(attrib[0].value & VA_ATTRIB_NOT_SUPPORTED) && + (attrib[0].value != VA_ENCRYPTION_TYPE_NONE) && + (((VAProfileH264ConstrainedBaseline == profile) && + (attrib[0].value & VA_ENCRYPTION_TYPE_CENC_CBC) && + (attrib[0].value & VA_ENCRYPTION_TYPE_CENC_CTR_LENGTH) && + (attrib[0].value & VA_ENCRYPTION_TYPE_CENC_CTR)) || + ((VAProfileHEVCMain == profile) && + (attrib[0].value & VA_ENCRYPTION_TYPE_CENC_CTR_LENGTH) && + (attrib[0].value & VA_ENCRYPTION_TYPE_CENC_CTR)) /* || + ((m_pRegData->m_type == MfxOmx_vp9vd_secure) && + (attrib[0].value & VA_ENCRYPTION_TYPE_CENC_CTR_LENGTH))*/)) + { + MFX_DEBUG_TRACE_MSG("HUC decryption is supported"); + return true; + } + } + + MFX_DEBUG_TRACE_MSG("HUC decryption is not supported"); + MFX_DEBUG_TRACE_I32(mfx_res); + return false; +} + + #endif // #ifdef LIBVA_SUPPORT diff --git a/c2_utils/src/mfx_frame_constructor.cpp b/c2_utils/src/mfx_frame_constructor.cpp index 1e184165..09f5418f 100755 --- a/c2_utils/src/mfx_frame_constructor.cpp +++ b/c2_utils/src/mfx_frame_constructor.cpp @@ -34,8 +34,7 @@ MfxC2FrameConstructor::MfxC2FrameConstructor(): m_profile(MFX_PROFILE_UNKNOWN), m_bEos(false), m_uBstBufReallocs(0), - m_uBstBufCopyBytes(0), - m_bInReset(false) + m_uBstBufCopyBytes(0) { MFX_DEBUG_TRACE_FUNC; @@ -199,10 +198,6 @@ mfxStatus MfxC2FrameConstructor::Unload() MFX_DEBUG_TRACE_FUNC; mfxStatus mfx_res = MFX_ERR_NONE; - if(m_bInReset) { - m_bInReset = false; - } - mfx_res = BstBufSync(); MFX_DEBUG_TRACE__mfxStatus(mfx_res); @@ -215,8 +210,6 @@ mfxStatus MfxC2FrameConstructor::Reset() MFX_DEBUG_TRACE_FUNC; mfxStatus mfx_res = MFX_ERR_NONE; - m_bInReset = true; - // saving allocating information about internal buffer mfxU8* data = m_bstBuf->Data; mfxU32 allocated_length = m_bstBuf->MaxLength; @@ -241,11 +234,6 @@ mfxStatus MfxC2FrameConstructor::Reset() return mfx_res; } -bool MfxC2FrameConstructor::IsInReset() -{ - return m_bInReset; -} - mfxStatus MfxC2FrameConstructor::BstBufRealloc(mfxU32 add_size) { MFX_DEBUG_TRACE_FUNC; @@ -414,7 +402,7 @@ mfxStatus MfxC2AVCFrameConstructor::FindHeaders(const mfxU8* data, mfxU32 size, StartCode start_code; mfxU32 length; for (; size > 3;) { - start_code = ReadStartCode(&data, &size); + start_code = ReadStartCode(&data, size); if (isSPS(start_code.type)) { std::shared_ptr sps = std::make_shared(); if (!sps) return MFX_ERR_MEMORY_ALLOC; @@ -423,7 +411,7 @@ mfxStatus MfxC2AVCFrameConstructor::FindHeaders(const mfxU8* data, mfxU32 size, sps->Data = (mfxU8*)data - start_code.size; length = size + start_code.size; - start_code = ReadStartCode(&data, &size); + start_code = ReadStartCode(&data, size); if (-1 != start_code.type) length -= size + start_code.size; sps->DataLength = length; @@ -440,7 +428,7 @@ mfxStatus MfxC2AVCFrameConstructor::FindHeaders(const mfxU8* data, mfxU32 size, pps->Data = (mfxU8*)data - start_code.size; length = size + start_code.size; - start_code = ReadStartCode(&data, &size); + start_code = ReadStartCode(&data, size); if (-1 != start_code.type) length -= size + start_code.size; pps->DataLength = length; @@ -458,7 +446,7 @@ mfxStatus MfxC2AVCFrameConstructor::FindHeaders(const mfxU8* data, mfxU32 size, MFX_ZERO_MEMORY(sei); sei.Data = (mfxU8*)data - start_code.size; sei.DataLength = size + start_code.size; - start_code = ReadStartCode(&data, &size); + start_code = ReadStartCode(&data, size); if (-1 != start_code.type) sei.DataLength -= size + start_code.size; MFX_DEBUG_TRACE_STREAM("Found SEI size " << sei.DataLength); @@ -531,7 +519,7 @@ mfxStatus MfxC2AVCFrameConstructor::LoadHeader(const mfxU8* data, mfxU32 size, b return mfx_res; } -IMfxC2FrameConstructor::StartCode MfxC2AVCFrameConstructor::ReadStartCode(const mfxU8** position, mfxU32* size_left) +IMfxC2FrameConstructor::StartCode MfxC2AVCFrameConstructor::ReadStartCode(const mfxU8** position, mfxU32& size_left) { MFX_DEBUG_TRACE_FUNC; @@ -540,7 +528,7 @@ IMfxC2FrameConstructor::StartCode MfxC2AVCFrameConstructor::ReadStartCode(const static const mfxU8 nal_unit_type_bits = 0x1f; mfxI32 i = 0; - for (; i < (mfxI32)*size_left - 2; ) { + for (; i < (mfxI32)size_left - 2; ) { if ((*position)[1]) { *position += 2; i += 2; @@ -551,7 +539,7 @@ IMfxC2FrameConstructor::StartCode MfxC2AVCFrameConstructor::ReadStartCode(const if (!(*position)[0]) zero_count++; mfxU32 j; - for (j = 1; j < (mfxU32)*size_left - i; j++) { + for (j = 1; j < (mfxU32)size_left - i; j++) { if ((*position)[j]) break; } @@ -560,17 +548,17 @@ IMfxC2FrameConstructor::StartCode MfxC2AVCFrameConstructor::ReadStartCode(const *position += j; i += j; - if (i >= (mfxI32)*size_left) break; + if (i >= (mfxI32)size_left) break; if (zero_count >= 2 && (*position)[0] == 1) { start_code.size = MFX_MIN(zero_count + 1, 4); - *size_left -= i + 1; + size_left -= i + 1; (*position)++; // remove 0x01 symbol - if (*size_left >= 1) { + if (size_left >= 1) { start_code.type = (*position)[0] & nal_unit_type_bits; } else { *position -= start_code.size; - *size_left += start_code.size; + size_left += start_code.size; start_code.size = 0; } return start_code; @@ -579,7 +567,7 @@ IMfxC2FrameConstructor::StartCode MfxC2AVCFrameConstructor::ReadStartCode(const } if (!zero_count) { - for (mfxU32 k = 0; k < *size_left - i; k++, (*position)++) { + for (mfxU32 k = 0; k < size_left - i; k++, (*position)++) { if ((*position)[0]) { zero_count = 0; continue; @@ -590,7 +578,7 @@ IMfxC2FrameConstructor::StartCode MfxC2AVCFrameConstructor::ReadStartCode(const zero_count = MFX_MIN(zero_count, 3); *position -= zero_count; - *size_left = zero_count; + size_left = zero_count; return start_code; } @@ -616,7 +604,7 @@ MfxC2HEVCFrameConstructor::~MfxC2HEVCFrameConstructor() MFX_DEBUG_TRACE_FUNC; } -IMfxC2FrameConstructor::StartCode MfxC2HEVCFrameConstructor::ReadStartCode(const mfxU8** position, mfxU32* size_left) +IMfxC2FrameConstructor::StartCode MfxC2HEVCFrameConstructor::ReadStartCode(const mfxU8** position, mfxU32& size_left) { MFX_DEBUG_TRACE_FUNC; @@ -626,7 +614,7 @@ IMfxC2FrameConstructor::StartCode MfxC2HEVCFrameConstructor::ReadStartCode(const static const mfxU8 NAL_UNITTYPE_SHIFT_H265 = 1; mfxI32 i = 0; - for (; i < (mfxI32)*size_left - 2; ) { + for (; i < (mfxI32)size_left - 2; ) { if ((*position)[1]) { *position += 2; i += 2; @@ -637,7 +625,7 @@ IMfxC2FrameConstructor::StartCode MfxC2HEVCFrameConstructor::ReadStartCode(const if (!(*position)[0]) zero_count++; mfxU32 j; - for (j = 1; j < (mfxU32)*size_left - i; j++) { + for (j = 1; j < (mfxU32)size_left - i; j++) { if ((*position)[j]) break; } @@ -646,17 +634,17 @@ IMfxC2FrameConstructor::StartCode MfxC2HEVCFrameConstructor::ReadStartCode(const *position += j; i += j; - if (i >= (mfxI32)*size_left) break; + if (i >= (mfxI32)size_left) break; if (zero_count >= 2 && (*position)[0] == 1) { start_code.size = MFX_MIN(zero_count + 1, 4); - *size_left -= i + 1; + size_left -= i + 1; (*position)++; // remove 0x01 symbol - if (*size_left >= 1) { + if (size_left >= 1) { start_code.type = ((*position)[0] & NAL_UNITTYPE_BITS_H265) >> NAL_UNITTYPE_SHIFT_H265; } else { *position -= start_code.size; - *size_left += start_code.size; + size_left += start_code.size; start_code.size = 0; } return start_code; @@ -665,7 +653,7 @@ IMfxC2FrameConstructor::StartCode MfxC2HEVCFrameConstructor::ReadStartCode(const } if (!zero_count) { - for (mfxU32 k = 0; k < *size_left - i; k++, (*position)++) { + for (mfxU32 k = 0; k < size_left - i; k++, (*position)++) { if ((*position)[0]) { zero_count = 0; continue; @@ -676,7 +664,7 @@ IMfxC2FrameConstructor::StartCode MfxC2HEVCFrameConstructor::ReadStartCode(const zero_count = MFX_MIN(zero_count, 3); *position -= zero_count; - *size_left = zero_count; + size_left = zero_count; return start_code; } @@ -753,16 +741,1753 @@ std::shared_ptr MfxC2FrameConstructorFactory::CreateFram MFX_DEBUG_TRACE_FUNC; std::shared_ptr fc; - if (MfxC2FC_AVC == fc_type) { - fc = std::make_shared(); - return fc; - } else if (MfxC2FC_HEVC == fc_type) { + switch (fc_type) + { + case MfxC2FC_AVC: + fc = std::make_shared(); + break; + case MfxC2FC_HEVC: fc = std::make_shared(); - return fc; + break; +#ifdef ENABLE_WIDEVINE + case MfxC2FC_SEC_AVC: + fc = std::make_shared(); + break; + case MfxC2FC_SEC_HEVC: + fc = std::make_shared(); + break; +#endif + + default: + break; + } - } else { - fc = std::make_shared(); - return fc; + return fc; +} + +#ifdef ENABLE_WIDEVINE + +MfxC2SecureFrameConstructor::MfxC2SecureFrameConstructor() +{ + MFX_DEBUG_TRACE_FUNC; + + MFX_ZERO_MEMORY(m_hucBuffer); + + MFX_ZERO_MEMORY(m_SPS_PPS_SEI); + MFX_ZERO_MEMORY(m_ClearBst); + + m_sliceHeader.resize(SLICE_HEADER_BUFFER_SIZE); +} + +MfxC2SecureFrameConstructor::~MfxC2SecureFrameConstructor() +{ + MFX_DEBUG_TRACE_FUNC; +} + +mfxStatus MfxC2SecureFrameConstructor::Reset(void) +{ + MFX_DEBUG_TRACE_FUNC; + for (std::list::iterator it = m_encryptedDataList.begin(); it != m_encryptedDataList.end(); ++it) + { + (*it)->DataLength = 0; + } + + MFX_ZERO_MEMORY(m_hucBuffer); + + ResetHeaders(); + + return MFX_ERR_NONE; +} + +mfxStatus MfxC2SecureFrameConstructor::ResetHeaders(void) +{ + MFX_DEBUG_TRACE_FUNC; + mfxStatus mfx_res = MFX_ERR_NONE; + + memset(m_SPS_PPS_SEI.Data, 0, m_SPS_PPS_SEI.DataLength); + m_SPS_PPS_SEI.DataLength = 0; + + MFX_DEBUG_TRACE_I32(mfx_res); + return mfx_res; +} + +mfxStatus MfxC2SecureFrameConstructor::ConstructFrame(VACencStatusBuf* cencStatus, mfxBitstream* bs) +{ + MFX_DEBUG_TRACE_FUNC; + mfxStatus mfx_res = MFX_ERR_NONE; + + m_ClearBst.DataLength = 0; + m_ClearBst.DataOffset = 0; + + bool updateHeaders = !(m_SPS_PPS_SEI.DataLength == cencStatus->buf_size && + m_SPS_PPS_SEI.Data && + !memcmp(m_SPS_PPS_SEI.Data, cencStatus->buf, m_SPS_PPS_SEI.DataLength)); + + // Update saved SPS/PPS/SEI headers and attach to m_ClearBst when the new headers come + if (updateHeaders) + { + if (m_SPS_PPS_SEI.MaxLength < cencStatus->buf_size) + { + m_SPS_PPS_SEI.Data = (mfxU8*)realloc(m_SPS_PPS_SEI.Data, cencStatus->buf_size); + if (m_SPS_PPS_SEI.Data) + m_SPS_PPS_SEI.MaxLength = cencStatus->buf_size; + else + mfx_res = MFX_ERR_MEMORY_ALLOC; + } + if (MFX_ERR_NONE == mfx_res) + { + std::copy((mfxU8*)cencStatus->buf, (mfxU8*)cencStatus->buf + cencStatus->buf_size, m_SPS_PPS_SEI.Data); + m_SPS_PPS_SEI.DataLength = cencStatus->buf_size; + + mfx_res = ParseHeaders(); + } + if (MFX_ERR_NONE == mfx_res) + { + if (m_ClearBst.MaxLength < m_SPS_PPS_SEI.DataLength) + { + m_ClearBst.Data = (mfxU8*)realloc(m_ClearBst.Data, m_SPS_PPS_SEI.DataLength); + if (m_ClearBst.Data) + m_ClearBst.MaxLength = m_SPS_PPS_SEI.DataLength; + else + mfx_res = MFX_ERR_MEMORY_ALLOC; + } + } + if (MFX_ERR_NONE == mfx_res) + { + std::copy(m_SPS_PPS_SEI.Data, m_SPS_PPS_SEI.Data + m_SPS_PPS_SEI.DataLength, m_ClearBst.Data); + m_ClearBst.DataLength = m_SPS_PPS_SEI.DataLength; + } + } + + // Reconstruct Slice Header as a bitstream and attach to m_ClearBst + if (MFX_ERR_NONE == mfx_res) + { + if (cencStatus->slice_buf_type != VACencSliceBufType::VaCencSliceBufParamter) + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + + mfxU8* pPackedSliceHdr = NULL; + mfxU32 packedSliceHdrLength = 0; + if (MFX_ERR_NONE == mfx_res) + { + mfx_res = GetSliceHeader((mfxU8*)cencStatus->slice_buf, + cencStatus->slice_buf_size, + &pPackedSliceHdr, + packedSliceHdrLength); + } + if (MFX_ERR_NONE == mfx_res && (!pPackedSliceHdr || !packedSliceHdrLength)) + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + + if (MFX_ERR_NONE == mfx_res) + { + mfxU32 neededMaxLength = m_ClearBst.DataLength + packedSliceHdrLength; + if (m_ClearBst.MaxLength < neededMaxLength) + { + m_ClearBst.Data = (mfxU8*)realloc(m_ClearBst.Data, neededMaxLength); + if (m_ClearBst.Data) + m_ClearBst.MaxLength = neededMaxLength; + else + mfx_res = MFX_ERR_MEMORY_ALLOC; + } + } + if (MFX_ERR_NONE == mfx_res) + { + mfxU8* endOfData = m_ClearBst.Data + m_ClearBst.DataLength; + std::copy(pPackedSliceHdr, pPackedSliceHdr + packedSliceHdrLength, endOfData); + m_ClearBst.DataLength += packedSliceHdrLength; + } + } + + if (MFX_ERR_NONE == mfx_res) + { + MFX_DEBUG_TRACE__mfxBitstream(m_ClearBst); + *bs = m_ClearBst; + } + + MFX_DEBUG_TRACE_I32(mfx_res); + return mfx_res; +} + +mfxStatus MfxC2SecureFrameConstructor::Load(const mfxU8* data, mfxU32 size, mfxU64 pts, bool header, bool complete_frame) +{ + MFX_DEBUG_TRACE_FUNC; + (void)pts; + (void)header; + + mfxStatus mfx_res = MFX_ERR_NONE; + + if (!data || !size) + { + MFX_DEBUG_TRACE_P(data); + MFX_DEBUG_TRACE_I32(size); + mfx_res = MFX_ERR_NULL_PTR; + } + + if (!complete_frame) + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + + C2SecureBuffer *secureBuffer = NULL; + if (MFX_ERR_NONE == mfx_res) + { + ProtectedBufferHandle *pbh = (ProtectedBufferHandle *) data; + MFX_DEBUG_TRACE_P(pbh); + if (pbh == NULL || !pbh->isGoodMagic()) + { + MFX_DEBUG_TRACE_MSG("Wrong magic (Protected Buffer Handle) value"); + mfx_res = MFX_ERR_NULL_PTR; + } + else + { + secureBuffer = (C2SecureBuffer *) pbh->getC2Buf(); + MFX_DEBUG_TRACE_P(secureBuffer); + if (!secureBuffer) + { + MFX_DEBUG_TRACE_MSG("secure buffer handle is NULL"); + mfx_res = MFX_ERR_NULL_PTR; + } + } + } + + if (MFX_ERR_NONE == mfx_res) + { + HUCVideoBuffer *hucBuffer = NULL; + hucBuffer = &(secureBuffer->hucBuffer); + if (!hucBuffer) + { + MFX_DEBUG_TRACE_P(hucBuffer); + mfx_res = MFX_ERR_NULL_PTR; + } + else m_hucBuffer = *hucBuffer; + } + + MFX_DEBUG_TRACE_I32(mfx_res); + return mfx_res; +} + +mfxEncryptedData* MfxC2SecureFrameConstructor::GetFreeEncryptedDataItem(void) +{ + MFX_DEBUG_TRACE_FUNC; + mfxEncryptedData* pEncryptedData = NULL; + for (std::list::iterator it = m_encryptedDataList.begin(); it != m_encryptedDataList.end(); ++it) + { + if (0 == (*it)->DataLength) + { + MFX_DEBUG_TRACE_MSG("Found free mfxEncryptedData item"); + pEncryptedData = *it; + m_encryptedDataList.splice(m_encryptedDataList.end(), m_encryptedDataList, it); // move an item to the end of the list + break; + } + } + if (NULL == pEncryptedData) + { + pEncryptedData = (mfxEncryptedData*) calloc(1, sizeof(mfxEncryptedData)); + if (pEncryptedData) + { + m_encryptedDataList.push_back(pEncryptedData); + MFX_DEBUG_TRACE_MSG("Created new mfxEncryptedData item"); + } + } + + MFX_DEBUG_TRACE_P(pEncryptedData); + return pEncryptedData; +} + +mfxEncryptedData* MfxC2SecureFrameConstructor::BuildEncryptedDataList(void) +{ + MFX_DEBUG_TRACE_FUNC; + + mfxEncryptedData* first = NULL; + std::list::iterator it; + for (it = m_encryptedDataList.begin(); it != m_encryptedDataList.end(); ++it) + { + if ((*it)->DataLength) + { + first = *it; + break; + } + } + if (it != m_encryptedDataList.end()) + { + std::list::iterator next = it; + next++; + for (; next != m_encryptedDataList.end(); ++it, ++next) + { + if ((*next)->DataLength) + { + (*it)->Next = *next; + } + } + } + + MFX_DEBUG_TRACE_P(first); + return first; +} + +mfxStatus MfxC2SecureFrameConstructor::GetSliceHeader(mfxU8* data, mfxU32 size, mfxU8 **sliceHdr, mfxU32 &sliceHdrlength) +{ + MFX_DEBUG_TRACE_FUNC; + mfxStatus mfx_res = MFX_ERR_NONE; + + memset(&m_sliceHeader[0], 0, sizeof(mfxU8) * m_sliceHeader.size()); + mfxU8 *sliceBufferBegin = &(*m_sliceHeader.begin()); + mfxU8 *sliceBufferEnd = &(*m_sliceHeader.end()); + + OutputBitstream obs(sliceBufferBegin, sliceBufferEnd, false); + + if (MFX_ERR_NONE == mfx_res) + { + mfx_res = PackSliceHeader(obs, data, size); + } + + if (MFX_ERR_NONE == mfx_res) + { + if (sliceHdr) + *sliceHdr = sliceBufferBegin; + sliceHdrlength = (obs.GetNumBits() + 7) / 8; + } + + MFX_DEBUG_TRACE_P(*sliceHdr); + MFX_DEBUG_TRACE_I32(sliceHdrlength); + MFX_DEBUG_TRACE_I32(mfx_res); + return mfx_res; +} + +MfxC2AVCSecureFrameConstructor::MfxC2AVCSecureFrameConstructor() : + MfxC2HEVCFrameConstructor(), MfxC2SecureFrameConstructor() +{ + MFX_DEBUG_TRACE_FUNC; + + m_bNeedAttachSPSPPS = false; +} + +MfxC2AVCSecureFrameConstructor::~MfxC2AVCSecureFrameConstructor(void) +{ + MFX_DEBUG_TRACE_FUNC; +} + +mfxStatus MfxC2AVCSecureFrameConstructor::Reset(void) +{ + MFX_DEBUG_TRACE_FUNC; + + m_bNeedAttachSPSPPS = false; + + mfxStatus mfx_res = MfxC2SecureFrameConstructor::Reset(); + + return (MFX_ERR_NONE == mfx_res) ? MfxC2FrameConstructor::Reset() : mfx_res; +} + +mfxStatus MfxC2AVCSecureFrameConstructor::Load(const mfxU8* data, mfxU32 size, mfxU64 pts, bool b_header, bool bCompleteFrame) +{ + MFX_DEBUG_TRACE_FUNC; + + mfxStatus mfx_res = MfxC2SecureFrameConstructor::Load(data, size, pts, b_header, bCompleteFrame); + + bool bFoundSps = false; + bool bFoundPps = false; + bool bFoundIDR = false; + bool bFoundRegularSlice = false; + + // Save SPS/PPS if exists + if (MFX_ERR_NONE == mfx_res) + { + for(int i = 0; i < m_hucBuffer.uiNumPackets;i++) + { + data = NULL; + size = 0; + if (m_hucBuffer.sPacketData[i].clear) + { + data = m_hucBuffer.base + m_hucBuffer.sPacketData[i].clearPacketOffset; + size = m_hucBuffer.sPacketData[i].clearPacketSize; + } + else + { + continue; // All start codes are located in clear packeds, so we don't need to check encrypted packets + } + StartCode startCode; + mfxU32 length; + for (; size > 3;) + { + startCode = ReadStartCode(&data, size); + if (isSPS(startCode.type)) + { + auto sps = std::make_shared(); + sps->Data = const_cast(data) - startCode.size; + + length = size + startCode.type; + startCode = ReadStartCode(&data, size); + if (-1 != startCode.type) + length -= size + startCode.size; + sps->DataLength = length; + MFX_DEBUG_TRACE_MSG("Found SPS, length ="); + MFX_DEBUG_TRACE_I32(length); + mfx_res = SaveHeaders(sps, NULL, false); + if (MFX_ERR_NONE != mfx_res) return mfx_res; + bFoundSps = true; + } + if (isPPS(startCode.type)) + { + auto pps = std::make_shared(); + pps->Data = const_cast(data) - startCode.size; + + length = size + startCode.size; + startCode = ReadStartCode(&data, size); + if (-1 != startCode.type) + length -= size + startCode.size; + pps->DataLength = length; + MFX_DEBUG_TRACE_MSG("Found PPS, length ="); + MFX_DEBUG_TRACE_I32(length); + mfx_res = SaveHeaders(NULL, pps, false); + if (MFX_ERR_NONE != mfx_res) return mfx_res; + bFoundPps = true; + } + if (isIDR(startCode.type)) + { + MFX_DEBUG_TRACE_MSG("Found IDR"); + bFoundIDR = true; + break; + } + if (isRegularSlice(startCode.type)) + { + MFX_DEBUG_TRACE_MSG("Found regular slice"); + bFoundRegularSlice = true; + break; + } + if (-1 == startCode.type) break; + } + } + } + + if (MFX_ERR_NONE == mfx_res) + { + // Handle IDR or regular frame. Otherwise skip the buffer + if (bFoundIDR || bFoundRegularSlice) + { + mfxU32 srcOffset = 0; + if (m_hucBuffer.sPacketData[0].clear) + srcOffset = m_hucBuffer.sPacketData[0].clearPacketOffset; + else + srcOffset = m_hucBuffer.sPacketData[0].sSegmentData.uiSegmentStartOffset; + + // Add new packed with SPS/PPS at the beginning of the list if it's needed + if (m_bNeedAttachSPSPPS && (!bFoundSps || !bFoundPps)) + { + if (m_hucBuffer.uiNumPackets >= MAX_SUPPORTED_PACKETS) + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + else + { + MFX_DEBUG_TRACE_MSG("Modify m_hucBuffer to add SPS and/or PPS"); + + // Create and fill new clear packet + packet_info newPacket; + MFX_ZERO_MEMORY(newPacket); + newPacket.clear = 1; + if (!bFoundSps) + newPacket.clearPacketSize += m_sps.DataLength; + if (!bFoundPps) + newPacket.clearPacketSize += m_pps.DataLength; + + for (int i=m_hucBuffer.uiNumPackets; i>0; i--) + { + m_hucBuffer.sPacketData[i] = m_hucBuffer.sPacketData[i-1]; + if (m_hucBuffer.sPacketData[i].clear) + { + m_hucBuffer.sPacketData[i].clearPacketOffset -= srcOffset; + m_hucBuffer.sPacketData[i].clearPacketOffset += newPacket.clearPacketSize; + } + else + { + m_hucBuffer.sPacketData[i].sSegmentData.uiSegmentStartOffset -= srcOffset; + m_hucBuffer.sPacketData[i].sSegmentData.uiSegmentStartOffset += newPacket.clearPacketSize; + } + } + + m_hucBuffer.sPacketData[0] = newPacket; + m_hucBuffer.uiNumPackets++; + m_hucBuffer.frame_size += m_hucBuffer.sPacketData[0].clearPacketSize; + } + } + + // Handle hucBuffer + if (MFX_ERR_NONE == mfx_res) + { + if (m_bstBuf->DataLength) + { + mfx_res = BstBufRealloc(sizeof(HUCVideoBuffer)); + if (MFX_ERR_NONE == mfx_res) + { + uint8_t *src = reinterpret_cast(&m_hucBuffer); + std::copy(src, src + sizeof(HUCVideoBuffer), m_bstBuf->Data + m_bstBuf->DataOffset + m_bstBuf->DataLength); + m_bstBuf->DataLength += sizeof(HUCVideoBuffer); + m_uBstBufCopyBytes += sizeof(HUCVideoBuffer); + } + } + + if (MFX_ERR_NONE == mfx_res) + { + if (m_bstBuf->DataLength) m_bstCurrent = m_bstBuf; + else + { + m_bstIn->Data = (mfxU8*)&m_hucBuffer; + m_bstIn->DataOffset = 0; + m_bstIn->DataLength = sizeof(HUCVideoBuffer); + m_bstIn->MaxLength = sizeof(HUCVideoBuffer); + m_bstIn->DataFlag |= MFX_BITSTREAM_COMPLETE_FRAME; + m_bstCurrent = m_bstIn; + } + m_bstCurrent->TimeStamp = pts; + } + else m_bstCurrent = NULL; + } + + // Handle bitstream + mfxEncryptedData *pEncryptedData = NULL; + if (MFX_ERR_NONE == mfx_res) + { + pEncryptedData = GetFreeEncryptedDataItem(); + if (!pEncryptedData) + mfx_res = MFX_ERR_MEMORY_ALLOC; + + if (MFX_ERR_NONE == mfx_res) + { + if (pEncryptedData->MaxLength < m_hucBuffer.frame_size) + { + pEncryptedData->Data = (mfxU8*)realloc(pEncryptedData->Data, m_hucBuffer.frame_size); + if (pEncryptedData->Data) + pEncryptedData->MaxLength = m_hucBuffer.frame_size; + else + mfx_res = MFX_ERR_MEMORY_ALLOC; + } + } + + if (MFX_ERR_NONE == mfx_res) + { + pEncryptedData->Next = NULL; + + mfxU32 dstOffset = 0; + if (m_bNeedAttachSPSPPS && !bFoundSps) + { + std::copy(m_sps.Data, m_sps.Data + m_sps.DataLength, pEncryptedData->Data + dstOffset); + dstOffset += m_sps.DataLength; + } + if (m_bNeedAttachSPSPPS && !bFoundPps) + { + std::copy(m_pps.Data, m_pps.Data + m_pps.DataLength, pEncryptedData->Data + dstOffset); + dstOffset += m_pps.DataLength; + } + + std::copy(m_hucBuffer.base + srcOffset, m_hucBuffer.base + m_hucBuffer.frame_size - dstOffset, pEncryptedData->Data + dstOffset); + pEncryptedData->DataLength = m_hucBuffer.frame_size; + pEncryptedData->DataOffset = 0; + } + } + + /*if (MFX_ERR_NONE == mfx_res) + { + MFX_DEBUG_TRACE_P(m_hucBuffer.pLibInstance); + MFX_DEBUG_TRACE_P(m_hucBuffer.base); + MFX_DEBUG_TRACE_I32(m_hucBuffer.frame_size); + MFX_DEBUG_TRACE_I32(m_hucBuffer.uiNumPackets); + for (int i=0; iData) + { + char buffer[128]; + int bstSize = pEncryptedData->DataLength > 128 ? 128 : pEncryptedData->DataLength; + for (int i=0; i<(bstSize+15)/16; i++) + { + memset(buffer, 0, 128); + int rest = bstSize - i*16; + for (int j=0; j<((rest<16) ? rest:16); j++) + { + mfxU8 sign = *(pEncryptedData->Data + i*16 + j); + sprintf(buffer + j*3, "%x%x ", sign/16, sign%16); + } + MFX_DEBUG_TRACE_MSG(buffer); + } + } + }*/ + + // Handle AppId if it's required + if (MFX_ERR_NONE == mfx_res) + { + MFX_DEBUG_TRACE_MSG("Copy AppId from hucBuffer"); + pEncryptedData->AppId = m_hucBuffer.appID; + MFX_DEBUG_TRACE_I32(pEncryptedData->AppId); + + if (pEncryptedData->AppId == PAVP_APPID_INVALID) + { + MFX_DEBUG_TRACE_MSG("Invalid PAVP AppID value"); + mfx_res = MFX_WRN_OUT_OF_RANGE; + } + } + + m_bNeedAttachSPSPPS = false; + } + else + { + if (bFoundSps || bFoundPps) + m_bNeedAttachSPSPPS = true; + MFX_DEBUG_TRACE_MSG("Not enough data, skip buffer"); + } } + + MFX_DEBUG_TRACE_I32(mfx_res); + return mfx_res; } + +std::shared_ptr MfxC2AVCSecureFrameConstructor::GetMfxBitstream() +{ + MFX_DEBUG_TRACE_FUNC; + + auto pBitstream = MfxC2FrameConstructor::GetMfxBitstream(); + if (pBitstream) + { + pBitstream->EncryptedData = BuildEncryptedDataList(); + pBitstream->DataFlag |= MFX_BITSTREAM_COMPLETE_FRAME; + } + + MFX_DEBUG_TRACE_P(pBitstream.get()); + return pBitstream; +} + +mfxStatus MfxC2AVCSecureFrameConstructor::ParseHeaders() +{ + MFX_DEBUG_TRACE_FUNC; + mfxStatus mfx_res = MFX_ERR_NONE; + + const mfxU8* data = m_SPS_PPS_SEI.Data; + mfxU32 size = m_SPS_PPS_SEI.DataLength; + + StartCode startCode; + startCode = ReadStartCode(&data, size); + + while (true) + { + if (isSPS(startCode.type) || isPPS(startCode.type)) + { + mfxU8* const nalu_ptr = const_cast(data); + mfxU32 length = size; // skip start code + + startCode = ReadStartCode(&data, size); + MFX_DEBUG_TRACE_U32(startCode.type); + if (-1 != startCode.type) + length -= size + startCode.size; + + mfx_res = ParseNalUnit(nalu_ptr, length); + if (MFX_ERR_NONE != mfx_res) break; + } + else + { + startCode = ReadStartCode(&data, size); + MFX_DEBUG_TRACE_U32(startCode.type); + } + if (-1 == startCode.type) break; + if (size <= 3) break; + } + + MFX_DEBUG_TRACE_I32(mfx_res); + return mfx_res; +} + +mfxStatus MfxC2AVCSecureFrameConstructor::ParseNalUnit(mfxU8 * const data, mfxU32 NAlUnitSize) +{ + MFX_DEBUG_TRACE_FUNC; + mfxStatus mfx_res = MFX_ERR_NONE; + + using namespace AVCParser; + + mfxU32 swappingSize = NAlUnitSize; + mfxU8 *swappingMemory = GetMemoryForSwapping(swappingSize); + + if (swappingMemory) + BytesSwapper::SwapMemory(swappingMemory, swappingSize, data, NAlUnitSize); + else + mfx_res = MFX_ERR_MEMORY_ALLOC; + + if (MFX_ERR_NONE == mfx_res) + { + AVCHeadersBitstream bitStream; + MFX_DEBUG_TRACE_MSG("Calling bitStream.Reset()"); + bitStream.Reset(swappingMemory, swappingSize); + + NAL_Unit_Type nalUnitType = NAL_UT_UNSPECIFIED; + mfxU8 nalStorageIDC; + + MFX_DEBUG_TRACE_MSG("Calling bitStream.GetNALUnitType()"); + bitStream.GetNALUnitType(nalUnitType, nalStorageIDC); + + if (NAL_UT_SPS == nalUnitType) + { + MFX_DEBUG_TRACE_MSG("Found SPS"); + m_H264Headers.Reset(); + + AVCSeqParamSet sps; + mfx_res = bitStream.GetSequenceParamSet(&sps); + if (MFX_ERR_NONE == mfx_res) + { + m_H264Headers.m_seqParams.AddHeader(&sps); + m_H264Headers.m_seqParams.SetCurrentID(sps.GetID()); + } + else + { + MFX_DEBUG_TRACE_MSG("ERROR: Invalid SPS"); + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + } + } + else if (NAL_UT_PPS == nalUnitType) + { + MFX_DEBUG_TRACE_MSG("Found PPS"); + AVCPicParamSet pps; + // set illegal id + pps.pic_parameter_set_id = MAX_NUM_PIC_PARAM_SETS; + + // Get id + mfx_res = bitStream.GetPictureParamSetPart1(&pps); + if (MFX_ERR_NONE == mfx_res) + { + AVCSeqParamSet *pRefsps = m_H264Headers.m_seqParams.GetHeader(pps.seq_parameter_set_id); + // Get rest of pic param set + mfx_res = bitStream.GetPictureParamSetPart2(&pps, pRefsps); + if (MFX_ERR_NONE == mfx_res) + { + m_H264Headers.m_picParams.AddHeader(&pps); + m_H264Headers.m_picParams.SetCurrentID(pps.GetID()); + } + else + { + MFX_DEBUG_TRACE_MSG("ERROR: Invalid PPS"); + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + } + } + else + { + MFX_DEBUG_TRACE_MSG("ERROR: Invalid PPS"); + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + } + } + else if (NAL_UT_SEI == nalUnitType) + { + MFX_DEBUG_TRACE_MSG("Found SEI"); + mfx_res = MFX_ERR_NONE; + } + else + { + MFX_DEBUG_TRACE_MSG("Found unknown NAL unit"); + MFX_DEBUG_TRACE_U32(nalUnitType); + mfx_res = MFX_ERR_UNSUPPORTED; + } + } + + MFX_DEBUG_TRACE_I32(mfx_res); + return mfx_res; +} + +mfxStatus MfxC2AVCSecureFrameConstructor::PackSliceHeader(OutputBitstream & obs, mfxU8* data, mfxU32 size) +{ + MFX_DEBUG_TRACE_FUNC; + mfxStatus mfx_res = MFX_ERR_NONE; + + using namespace AVCParser; + + AVCSeqParamSet *sps = NULL; + AVCPicParamSet *pps = NULL; + VACencSliceParameterBufferH264 sliceParams{}; + + pps = m_H264Headers.m_picParams.GetCurrentHeader(); + if (NULL == pps) + { + MFX_DEBUG_TRACE_MSG("ERROR: PPS not found"); + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + } + + if (MFX_ERR_NONE == mfx_res) + { + sps = m_H264Headers.m_seqParams.GetCurrentHeader(); + if (NULL == sps) + { + MFX_DEBUG_TRACE_MSG("ERROR: SPS not found"); + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + } + } + if (MFX_ERR_NONE == mfx_res) + { + if (size != sizeof(VACencSliceParameterBufferH264)) + { + MFX_DEBUG_TRACE_MSG("ERROR: incorrect slice_buf_size"); + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + } + } + if (MFX_ERR_NONE == mfx_res) + { + sliceParams = *(reinterpret_cast(data)); + + MFX_DEBUG_TRACE_I32(sliceParams.nal_ref_idc); + MFX_DEBUG_TRACE_I32(sliceParams.idr_pic_flag); + MFX_DEBUG_TRACE_I32(sliceParams.slice_type); + MFX_DEBUG_TRACE_I32(sliceParams.field_frame_flag); + MFX_DEBUG_TRACE_I32(sliceParams.frame_number); + MFX_DEBUG_TRACE_I32(sliceParams.idr_pic_id); + MFX_DEBUG_TRACE_I32(sliceParams.pic_order_cnt_lsb); + MFX_DEBUG_TRACE_I32(sliceParams.delta_pic_order_cnt_bottom); + MFX_DEBUG_TRACE_I32(sliceParams.delta_pic_order_cnt[0]); + MFX_DEBUG_TRACE_I32(sliceParams.delta_pic_order_cnt[1]); + MFX_DEBUG_TRACE_I32(sliceParams.ref_pic_fields.bits.no_output_of_prior_pics_flag); + MFX_DEBUG_TRACE_I32(sliceParams.ref_pic_fields.bits.long_term_reference_flag); + MFX_DEBUG_TRACE_I32(sliceParams.ref_pic_fields.bits.adaptive_ref_pic_marking_mode_flag); + MFX_DEBUG_TRACE_I32(sliceParams.ref_pic_fields.bits.dec_ref_pic_marking_count); + + mfxU32 idrPicFlag = sliceParams.idr_pic_flag; + mfxU32 nalRefIdc = sliceParams.nal_ref_idc; + mfxU32 nalUnitType = sliceParams.idr_pic_flag ? NAL_UT_IDR_SLICE : NAL_UT_SLICE; + mfxU32 fieldPicFlag = (sliceParams.field_frame_flag == VA_TOP_FIELD) || (sliceParams.field_frame_flag == VA_BOTTOM_FIELD); + mfxU32 bottomFieldFlag = (sliceParams.field_frame_flag == VA_BOTTOM_FIELD); + mfxU32 firstMbInSlice = 0; + mfxU32 sliceType = sliceParams.slice_type; + mfxU32 directSpatialMvPredFlag = 0; + mfxU32 cabacInitIdc = 0; + mfxU32 slice_qp_delta = 0; + mfxU32 numRefIdxL0Active = pps->num_ref_idx_l0_active; + mfxU32 numRefIdxL1Active = pps->num_ref_idx_l1_active; + + mfxU8 startcode[3] = { 0, 0, 1 }; + obs.PutRawBytes(startcode, startcode + sizeof startcode); + obs.PutBit(0); + obs.PutBits(nalRefIdc, 2); + obs.PutBits(nalUnitType, 5); + + obs.PutUe(firstMbInSlice); + obs.PutUe(sliceType + 5); + obs.PutUe(pps->pic_parameter_set_id); + obs.PutBits(sliceParams.frame_number, sps->log2_max_frame_num); + if (!sps->frame_mbs_only_flag) + { + obs.PutBit(fieldPicFlag); + if (fieldPicFlag) + obs.PutBit(bottomFieldFlag); + } + if (idrPicFlag) + { + obs.PutUe(sliceParams.idr_pic_id); + } + if (sps->pic_order_cnt_type == 0) + { + obs.PutBits(sliceParams.pic_order_cnt_lsb, sps->log2_max_pic_order_cnt_lsb); + if (pps->pic_order_present_flag && !fieldPicFlag) + obs.PutSe(sliceParams.delta_pic_order_cnt_bottom); + } + if (sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag) + { + obs.PutSe(sliceParams.delta_pic_order_cnt[0]); + if (pps->pic_order_present_flag && !fieldPicFlag) + obs.PutSe(sliceParams.delta_pic_order_cnt[1]); + } + if (sliceType == BPREDSLICE) + { + obs.PutBit(directSpatialMvPredFlag); + } + if (sliceType != INTRASLICE) + { + numRefIdxL0Active = 1; //IPP_MAX(1, task.m_list0[fieldId].Size()); + numRefIdxL1Active = 1; //IPP_MAX(1, task.m_list1[fieldId].Size()); + mfxU32 numRefIdxActiveOverrideFlag = + (numRefIdxL0Active != pps->num_ref_idx_l0_active - 1) || + (numRefIdxL1Active != pps->num_ref_idx_l1_active && sliceType == BPREDSLICE); + + obs.PutBit(numRefIdxActiveOverrideFlag); + if (numRefIdxActiveOverrideFlag) + { + obs.PutUe(numRefIdxL0Active - 1); + if (sliceType == BPREDSLICE) + obs.PutUe(numRefIdxL1Active - 1); + } + } + if (sliceType != INTRASLICE) + obs.PutBit(0); // ref_pic_list_modification_flag_l0 + if (sliceType == BPREDSLICE) + obs.PutBit(0); // ref_pic_list_modification_flag_l1 + + // prediction weight table + if ( (pps->weighted_pred_flag && + ((PREDSLICE == sliceType) || (S_PREDSLICE == sliceType))) || + ((pps->weighted_bipred_idc == 1) && (BPREDSLICE == sliceType))) + { + mfxU32 luma_log2_weight_denom = 0; + obs.PutUe(luma_log2_weight_denom); + if (sps->chroma_format_idc != 0) + { + mfxU32 chroma_log2_weight_denom = 0; + obs.PutUe(chroma_log2_weight_denom); + } + for (mfxU32 refindex = 0; refindex < numRefIdxL0Active; refindex++) + { + mfxU8 luma_weight_flag = 0; + obs.PutBit(luma_weight_flag); + + if (sps->chroma_format_idc != 0) + { + mfxU8 chroma_weight_flag = 0; + obs.PutBit(chroma_weight_flag); + } + } + if (BPREDSLICE == sliceType) + { + for (mfxU32 refindex = 0; refindex < numRefIdxL1Active; refindex++) + { + mfxU8 luma_weight_flag = 0; + obs.PutBit(luma_weight_flag); + + if (sps->chroma_format_idc != 0) + { + mfxU8 chroma_weight_flag = 0; + obs.PutBit(chroma_weight_flag); + } + } + } + } + + if (nalRefIdc) + { + // WriteDecRefPicMarking + if (idrPicFlag) + { + obs.PutBit(sliceParams.ref_pic_fields.bits.no_output_of_prior_pics_flag); + obs.PutBit(sliceParams.ref_pic_fields.bits.long_term_reference_flag); + } + else + { + obs.PutBit(sliceParams.ref_pic_fields.bits.adaptive_ref_pic_marking_mode_flag); + if (sliceParams.ref_pic_fields.bits.adaptive_ref_pic_marking_mode_flag) + { + mfxU32 num_entries = 0; + for (mfxU32 i = 0; i < MAX_NUM_REF_FRAMES; i++) + { + if (sliceParams.memory_management_control_operation[i]) + { + MFX_DEBUG_TRACE_I32(sliceParams.memory_management_control_operation[i]); + obs.PutUe(sliceParams.memory_management_control_operation[i]); + + switch (sliceParams.memory_management_control_operation[i]) + { + case 1: + MFX_DEBUG_TRACE_I32(sliceParams.difference_of_pic_nums_minus1[i]); + obs.PutUe(sliceParams.difference_of_pic_nums_minus1[i]); + break; + case 2: + MFX_DEBUG_TRACE_I32(sliceParams.long_term_pic_num[i]); + obs.PutUe(sliceParams.long_term_pic_num[i]); + break; + case 3: + MFX_DEBUG_TRACE_I32(sliceParams.difference_of_pic_nums_minus1[i]); + MFX_DEBUG_TRACE_I32(sliceParams.long_term_frame_idx[i]); + obs.PutUe(sliceParams.difference_of_pic_nums_minus1[i]); + obs.PutUe(sliceParams.long_term_frame_idx[i]); + break; + case 4: + MFX_DEBUG_TRACE_I32(sliceParams.max_long_term_frame_idx_plus1[i]); + obs.PutUe(sliceParams.max_long_term_frame_idx_plus1[i]); + break; + case 5: + // Mark all as unused for reference + break; + case 6: + MFX_DEBUG_TRACE_I32(sliceParams.long_term_frame_idx[i]); + obs.PutUe(sliceParams.long_term_frame_idx[i]); + break; + default: + // invalid mmco command in bitstream + MFX_DEBUG_TRACE_MSG("ERROR: invalid MMCO value"); + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + } + if (MFX_ERR_NONE != mfx_res) + break; + num_entries++; + } + } + if (sliceParams.ref_pic_fields.bits.dec_ref_pic_marking_count != num_entries) + { + MFX_DEBUG_TRACE_MSG("ERROR: invalid MMCO number"); + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + } + + obs.PutUe(0); //MMCO_END + } + } + } + + if (pps->entropy_coding_mode && sliceType != INTRASLICE) + { + obs.PutUe(cabacInitIdc); + } + obs.PutSe(slice_qp_delta); + + if (pps->deblocking_filter_variables_present_flag) + { + mfxU32 disableDeblockingFilterIdc = 0; + mfxI32 sliceAlphaC0OffsetDiv2 = 0; + mfxI32 sliceBetaOffsetDiv2 = 0; + + obs.PutUe(disableDeblockingFilterIdc); + if (disableDeblockingFilterIdc != 1) + { + obs.PutSe(sliceAlphaC0OffsetDiv2); + obs.PutSe(sliceBetaOffsetDiv2); + } + } + } + + MFX_DEBUG_TRACE_I32(mfx_res); + return mfx_res; +} + +mfxU8* MfxC2AVCSecureFrameConstructor::GetMemoryForSwapping(mfxU32 size) +{ + MFX_DEBUG_TRACE_FUNC; + try + { + if (m_swappingMemory.size() <= size + 8) + m_swappingMemory.resize(size + 8); + } + catch (...) + { + return NULL; + } + + return &(m_swappingMemory[0]); +} + + +MfxC2HEVCSecureFrameConstructor::MfxC2HEVCSecureFrameConstructor(): + MfxC2AVCSecureFrameConstructor(), previous_poc(0) +{ + MFX_DEBUG_TRACE_FUNC; +} + +MfxC2HEVCSecureFrameConstructor::~MfxC2HEVCSecureFrameConstructor(void) +{ + MFX_DEBUG_TRACE_FUNC; +} + +IMfxC2FrameConstructor::StartCode MfxC2HEVCSecureFrameConstructor::ReadStartCode(const mfxU8** position, mfxU32& size_left) +{ + MFX_DEBUG_TRACE_FUNC; + + return MfxC2HEVCFrameConstructor::ReadStartCode(position, size_left); +} + +bool MfxC2HEVCSecureFrameConstructor::isRegularSlice(mfxI32 code) +{ + MFX_DEBUG_TRACE_FUNC; + + return (NAL_UT_HEVC_SLICE_TRAIL_N == code) || + (NAL_UT_HEVC_SLICE_TRAIL_R == code) || + (NAL_UT_HEVC_SLICE_TSA_N == code) || + (NAL_UT_HEVC_SLICE_TLA_R == code) || + (NAL_UT_HEVC_SLICE_STSA_N == code) || + (NAL_UT_HEVC_SLICE_STSA_R == code) || + (NAL_UT_HEVC_SLICE_RADL_N == code) || + (NAL_UT_HEVC_SLICE_RADL_R == code) || + (NAL_UT_HEVC_SLICE_RASL_N == code) || + (NAL_UT_HEVC_SLICE_RASL_R == code) || + (NAL_UT_HEVC_SLICE_BLA_W_LP == code) || + (NAL_UT_HEVC_SLICE_BLA_W_RADL == code) || + (NAL_UT_HEVC_SLICE_BLA_N_LP == code) || + (NAL_UT_HEVC_SLICE_CRA == code); +} + +mfxStatus MfxC2HEVCSecureFrameConstructor::ParseNalUnit(mfxU8 * const data, mfxU32 NAlUnitSize) +{ + MFX_DEBUG_TRACE_FUNC; + mfxStatus mfx_res = MFX_ERR_NONE; + + using namespace HEVCParser; + + mfxU32 swappingSize = NAlUnitSize; + mfxU8 *swappingMemory = GetMemoryForSwapping(swappingSize); + + if (swappingMemory) + BytesSwapper::SwapMemory(swappingMemory, swappingSize, data, NAlUnitSize); + else + mfx_res = MFX_ERR_MEMORY_ALLOC; + + if (MFX_ERR_NONE == mfx_res) + { + HEVCHeadersBitstream bitStream; + MFX_DEBUG_TRACE_MSG("Calling bitStream.Reset()"); + bitStream.Reset(swappingMemory, swappingSize); + + NalUnitType nalUnitType = NAL_UT_INVALID; + mfxU32 nuh_temporal_id; + + MFX_DEBUG_TRACE_MSG("Calling bitStream.GetNALUnitType()"); + bitStream.GetNALUnitType(nalUnitType, nuh_temporal_id); + + if (NAL_UT_SPS == nalUnitType) + { + MFX_DEBUG_TRACE_MSG("Found SPS"); + m_H265Headers.Reset(); + + H265SeqParamSet sps; + mfx_res = bitStream.GetSequenceParamSet(&sps); + if (MFX_ERR_NONE == mfx_res) + { + m_H265Headers.m_seqParams.AddHeader(&sps); + m_H265Headers.m_seqParams.SetCurrentID(sps.GetID()); + } + else + { + MFX_DEBUG_TRACE_MSG("ERROR: Invalid SPS"); + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + } + } + else if (NAL_UT_PPS == nalUnitType) + { + MFX_DEBUG_TRACE_MSG("Found PPS"); + H265PicParamSet pps; + // set illegal id + pps.pps_pic_parameter_set_id = MAX_NUM_PIC_PARAM_SETS_H265; + + // Get id + mfx_res = bitStream.GetPictureParamSetPart1(&pps); + if (MFX_ERR_NONE == mfx_res) + { + H265SeqParamSet *pRefsps = m_H265Headers.m_seqParams.GetHeader(pps.pps_seq_parameter_set_id); + // Get rest of pic param set + mfx_res = bitStream.GetPictureParamSetFull(&pps, pRefsps); + if (MFX_ERR_NONE == mfx_res) + { + m_H265Headers.m_picParams.AddHeader(&pps); + m_H265Headers.m_picParams.SetCurrentID(pps.GetID()); + } + else + { + MFX_DEBUG_TRACE_MSG("ERROR: Invalid PPS"); + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + } + } + else + { + MFX_DEBUG_TRACE_MSG("ERROR: Invalid PPS"); + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + } + } + else if (NAL_UT_SEI == nalUnitType) + { + MFX_DEBUG_TRACE_MSG("Found SEI"); + mfx_res = MFX_ERR_NONE; + } + else + { + MFX_DEBUG_TRACE_MSG("Found unknown NAL unit"); + MFX_DEBUG_TRACE_U32(nalUnitType); + mfx_res = MFX_ERR_UNSUPPORTED; + } + } + + MFX_DEBUG_TRACE_I32(mfx_res); + return mfx_res; +} + +inline mfxU32 CeilLog2 (mfxU32 x) { mfxU32 l = 0; while(x > (1U<(data)); + + MFX_DEBUG_TRACE_I32(sliceParams.nal_unit_type); + MFX_DEBUG_TRACE_I32(sliceParams.nuh_temporal_id); + MFX_DEBUG_TRACE_I32(sliceParams.slice_type); + MFX_DEBUG_TRACE_I32(sliceParams.slice_pic_order_cnt_lsb); + MFX_DEBUG_TRACE_I32(sliceParams.has_eos_or_eob); + MFX_DEBUG_TRACE_I32(sliceParams.slice_fields.bits.no_output_of_prior_pics_flag); + MFX_DEBUG_TRACE_I32(sliceParams.slice_fields.bits.pic_output_flag); + MFX_DEBUG_TRACE_I32(sliceParams.slice_fields.bits.colour_plane_id); + MFX_DEBUG_TRACE_I32(sliceParams.num_of_curr_before); + MFX_DEBUG_TRACE_I32(sliceParams.num_of_curr_after); + MFX_DEBUG_TRACE_I32(sliceParams.num_of_curr_total); + MFX_DEBUG_TRACE_I32(sliceParams.num_of_foll_st); + MFX_DEBUG_TRACE_I32(sliceParams.num_of_curr_lt); + MFX_DEBUG_TRACE_I32(sliceParams.num_of_foll_lt); + + int32_t current_poc = 0; + uint32_t index_total = 0; + uint8_t ref_set_idx_curr_before[MAX_NUM_REF_PICS_CUR] = {}; + uint8_t ref_set_idx_curr_after[MAX_NUM_REF_PICS_CUR] = {}; + uint8_t ref_set_idx_curr_lt[MAX_NUM_REF_PICS_CUR] = {}; + + uint8_t startcode[3] = { 0, 0, 1 }; + obs.PutRawBytes(startcode, startcode + sizeof startcode); + obs.PutBit(0); + obs.PutBits(sliceParams.nal_unit_type, 6); + obs.PutBits(0, 6); // nuh_layer_id + obs.PutBits(sliceParams.nuh_temporal_id + 1, 3); + + obs.PutBit(0); // first_slice_segment_in_pic_flag + if (sliceParams.nal_unit_type >= NAL_UT_CODED_SLICE_BLA_W_LP && sliceParams.nal_unit_type <= NAL_RSV_IRAP_VCL23) + { + obs.PutBit(sliceParams.slice_fields.bits.no_output_of_prior_pics_flag); + } + + obs.PutUe(pps->pps_pic_parameter_set_id); + + if (true) // first_slice_segment_in_pic_flag == 0 + { + if (pps->dependent_slice_segments_enabled_flag) + { + obs.PutBit(0); // dependent_slice_segment_flag + } + uint32_t PicSizeInCtbsY = CeilDiv(sps->pic_width_in_luma_samples, sps->MaxCUSize) * CeilDiv(sps->pic_height_in_luma_samples, sps->MaxCUSize); + int32_t slice_address_len = CeilLog2(PicSizeInCtbsY); + + obs.PutBits(0, // slice_segment_address + slice_address_len); + } + + if (true) // dependent_slice_segment_flag == 0 + { + if (pps->num_extra_slice_header_bits) + obs.PutBits(0, pps->num_extra_slice_header_bits); + + obs.PutUe(sliceParams.slice_type); + + if (pps->output_flag_present_flag) + obs.PutBit(sliceParams.slice_fields.bits.pic_output_flag); + + if (sps->separate_colour_plane_flag == 1) + obs.PutBits(sliceParams.slice_fields.bits.colour_plane_id, 2); + + if (sliceParams.nal_unit_type != NAL_UT_CODED_SLICE_IDR_W_RADL && + sliceParams.nal_unit_type != NAL_UT_CODED_SLICE_IDR_N_LP) + { + obs.PutBits(sliceParams.slice_pic_order_cnt_lsb, sps->log2_max_pic_order_cnt_lsb); + + // decode poc + int32_t cur_poc_lsb = sliceParams.slice_pic_order_cnt_lsb; + int32_t max_poc_lsb = 1 << (sps->log2_max_pic_order_cnt_lsb); + int32_t pre_poc_lsb = previous_poc & (max_poc_lsb - 1); + int32_t pre_poc_msb = previous_poc - pre_poc_lsb; + int32_t cur_poc_msb = 0; + + if ((cur_poc_lsb < pre_poc_lsb) && ((pre_poc_lsb - cur_poc_lsb) >= (max_poc_lsb / 2))) + { + cur_poc_msb = pre_poc_msb + max_poc_lsb; + } + else if ((cur_poc_lsb > pre_poc_lsb) && ((cur_poc_lsb - pre_poc_lsb) > (max_poc_lsb / 2))) + { + cur_poc_msb = pre_poc_msb - max_poc_lsb; + } + else + { + cur_poc_msb = pre_poc_msb; + } + + if ((NAL_UT_CODED_SLICE_BLA_W_LP == sliceParams.nal_unit_type) || + (NAL_UT_CODED_SLICE_BLA_W_RADL == sliceParams.nal_unit_type) || + (NAL_UT_CODED_SLICE_BLA_N_LP == sliceParams.nal_unit_type) ) + { + cur_poc_msb = 0; + } + + current_poc = cur_poc_lsb + cur_poc_msb; + MFX_DEBUG_TRACE_I32(current_poc); + + // short_term_rps + obs.PutBit(0); // short_term_ref_pic_set_sps_flag + if (true) // short_term_ref_pic_set_sps_flag == 0 + { + if (sps->getRPSList()->getNumberOfReferencePictureSets() > 0) + { + obs.PutBit(0); // rps->inter_ref_pic_set_prediction_flag + } + + uint32_t num_negative_pics = 0; + uint32_t num_positive_pics = 0; + uint32_t i; + for(i = 0; i < sliceParams.num_of_curr_before; i++) + { + num_negative_pics++; + } + for(i = 0; i < sliceParams.num_of_curr_after; i++) + { + num_positive_pics++; + } + for(i = 0; i < sliceParams.num_of_foll_st; i++) + { + if (sliceParams.delta_poc_foll_st[i] < 0) + num_negative_pics++; + else + num_positive_pics++; + } + + obs.PutUe(num_negative_pics); + obs.PutUe(num_positive_pics); + + int32_t prev = 0; + int32_t poc; + uint8_t used_by_curr_pic_flag; + uint32_t index_foll = 0; + uint32_t delta_poc_s0_minus1; + for(i = 0; i < num_negative_pics; i++) + { + if (i < sliceParams.num_of_curr_before) + { + used_by_curr_pic_flag = 1; + poc = sliceParams.delta_poc_curr_before[i]; + ref_set_idx_curr_before[i] = index_total; + index_total++; + } + else + { + used_by_curr_pic_flag = 0; + poc = sliceParams.delta_poc_foll_st[index_foll]; + index_foll++; + } + + delta_poc_s0_minus1 = prev - poc - 1; + prev = poc; + obs.PutUe(delta_poc_s0_minus1); + obs.PutBit(used_by_curr_pic_flag); + } + + prev = 0; + uint32_t delta_poc_s1_minus1; + for(i = 0; i < num_positive_pics; i++) + { + if (i < sliceParams.num_of_curr_after) + { + used_by_curr_pic_flag = 1; + poc = sliceParams.delta_poc_curr_after[i]; + ref_set_idx_curr_after[i] = index_total; + index_total++; + } + else + { + used_by_curr_pic_flag = 0; + poc = sliceParams.delta_poc_foll_st[index_foll]; + index_foll++; + } + + delta_poc_s1_minus1 = poc - prev - 1; + prev = poc; + obs.PutUe(delta_poc_s1_minus1); + obs.PutBit(used_by_curr_pic_flag); + } + } + else if (sps->num_short_term_ref_pic_sets > 1) + { + int32_t len = CeilLog2(sps->num_short_term_ref_pic_sets); + + obs.PutBits(0, // short_term_ref_pic_set_idx + len); + } + + // long_term_ref_frames + if (sps->long_term_ref_pics_present_flag) + { + if (sps->num_long_term_ref_pics_sps > 0) + { + obs.PutUe(0); // num_long_term_sps + } + obs.PutUe(sliceParams.num_of_curr_lt + sliceParams.num_of_foll_lt); + + uint32_t index_foll_lt = 0; + uint8_t used_flag_lt = 0; + int32_t poc_lsb_lt = 0; + int32_t poc_lsb_bit_mask = 0; + uint32_t i = 0; + for(i = 0; i < sliceParams.num_of_curr_lt + sliceParams.num_of_foll_lt; i++) + { + if (i < sliceParams.num_of_curr_lt) + { + used_flag_lt = 1; + } + else + { + used_flag_lt = 0; + } + if (sliceParams.delta_poc_msb_present_flag[i]) + { + if (used_flag_lt) + { + poc_lsb_lt = sliceParams.delta_poc_curr_lt[i] + sliceParams.slice_pic_order_cnt_lsb; + ref_set_idx_curr_lt[i] = index_total; + index_total++; + } + else + { + poc_lsb_lt = sliceParams.delta_poc_foll_lt[index_foll_lt] + sliceParams.slice_pic_order_cnt_lsb; + index_foll_lt++; + } + } + else + { + if (used_flag_lt) + { + poc_lsb_lt = sliceParams.delta_poc_curr_lt[i] + current_poc; + ref_set_idx_curr_lt[i] = index_total; + index_total++; + } + else + { + poc_lsb_lt = sliceParams.delta_poc_foll_lt[index_foll_lt] + current_poc; + index_foll_lt++; + } + + poc_lsb_bit_mask = (1 << sps->log2_max_pic_order_cnt_lsb) - 1; + poc_lsb_lt = poc_lsb_lt & poc_lsb_bit_mask; + } + + obs.PutBits(poc_lsb_lt, sps->log2_max_pic_order_cnt_lsb); + obs.PutBit(used_flag_lt); + obs.PutBit(sliceParams.delta_poc_msb_present_flag[i]); + if (sliceParams.delta_poc_msb_present_flag[i]) + { + obs.PutUe(0); // delta_poc_msb_cycle_lt + } + } + } + if (sps->sps_temporal_mvp_enabled_flag) + obs.PutBit(0); // slice_temporal_mvp_enabled_flag + } + else + { + current_poc = 0; + previous_poc = 0; + } + if (sps->sample_adaptive_offset_enabled_flag) + { + obs.PutBit(0); // slice_sao_luma_flag + obs.PutBit(0); // slice_sao_chroma_flag + } + if (sliceParams.slice_type == P_SLICE || sliceParams.slice_type == B_SLICE) + { + uint8_t num_ref_idx[2] = {MAX_NUM_REF_PICS, MAX_NUM_REF_PICS}; + while((!sliceParams.ref_list_idx[0][num_ref_idx[0] - 1]) && (num_ref_idx[0] > 1)) + { + num_ref_idx[0]--; + } + while((!sliceParams.ref_list_idx[1][num_ref_idx[1] - 1]) && (num_ref_idx[1] > 1)) + { + num_ref_idx[1]--; + } + + if (num_ref_idx[0] == pps->num_ref_idx_l0_default_active && + num_ref_idx[1] == pps->num_ref_idx_l1_default_active) + { + obs.PutBit(0); // num_ref_idx_active_override_flag + } + else + { + obs.PutBit(1); // num_ref_idx_active_override_flag + + obs.PutUe(num_ref_idx[0] - 1); + if (sliceParams.slice_type == B_SLICE) + obs.PutUe(num_ref_idx[1] - 1); + } + + if ((pps->lists_modification_present_flag) && (sliceParams.num_of_curr_total > 1)) + { + // init_ref_lists + uint8_t i, j; + uint8_t num_ref_list_temp0, num_ref_list_temp1; + uint8_t ref_list_idx_rps[2][MAX_NUM_REF_PICS_CUR]; + uint8_t ref_list_idx[2][MAX_NUM_REF_PICS]; + + num_ref_list_temp0 = num_ref_idx[0]; + if (num_ref_list_temp0 < sliceParams.num_of_curr_total) + { + num_ref_list_temp0 = sliceParams.num_of_curr_total; + } + + j = 0; + for(i = 0; i < num_ref_list_temp0; i++) + { + if (i < MAX_NUM_REF_PICS_CUR) + { + ref_list_idx_rps[0][i] = j; + } + ref_list_idx[0][i] = j; + j++; + + if (j == sliceParams.num_of_curr_total) + { + j = 0; + } + } + + if (B_SLICE == sliceParams.slice_type) + { + num_ref_list_temp1 = num_ref_idx[1]; + if ( num_ref_list_temp1 < sliceParams.num_of_curr_total ) + { + num_ref_list_temp1 = sliceParams.num_of_curr_total; + } + + j = 0; + while (j < num_ref_list_temp1) + { + for(i = 0; (i < sliceParams.num_of_curr_after) && (j < num_ref_list_temp1); i++) + { + if (j < MAX_NUM_REF_PICS_CUR) + { + ref_list_idx_rps[1][j] = ref_set_idx_curr_after[i]; + } + ref_list_idx[1][j] = ref_set_idx_curr_after[i]; + j++; + } + for(i = 0; (i < sliceParams.num_of_curr_before) && (j < num_ref_list_temp1); i++) + { + if (j < MAX_NUM_REF_PICS_CUR) + { + ref_list_idx_rps[1][j] = ref_set_idx_curr_before[i]; + } + ref_list_idx[1][j] = ref_set_idx_curr_before[i]; + j++; + } + for(i = 0; (i < sliceParams.num_of_curr_lt) && (j < num_ref_list_temp1); i++) + { + if (j < MAX_NUM_REF_PICS_CUR) + { + ref_list_idx_rps[1][j] = ref_set_idx_curr_lt[i]; + } + ref_list_idx[1][j] = ref_set_idx_curr_lt[i]; + j++; + } + + if (j == 0) + { + break; + } + } + } + + // ref_lists_modification + uint8_t bits_num = CeilLog2(sliceParams.num_of_curr_total); + if (memcmp(sliceParams.ref_list_idx[0], ref_list_idx[0], MAX_NUM_REF_PICS)) + { + obs.PutBit(1); // slice_ref_pic_list_modification_flag_l0 + for(i = 0; i < num_ref_idx[0]; i++) + { + uint32_t code = 0; + bool found = false; + for(j = 0; (j < num_ref_list_temp0) && (j < MAX_NUM_REF_PICS_CUR); j++) + { + if (sliceParams.ref_list_idx[0][i] == ref_list_idx_rps[0][j]) + { + code = j; + found = true; + break; + } + } + if (!found) + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + + obs.PutBits(code, bits_num); + } + } + else + { + obs.PutBit(0); // slice_ref_pic_list_modification_flag_l0 + } + if (B_SLICE == sliceParams.slice_type) + { + if (memcmp(sliceParams.ref_list_idx[1], ref_list_idx[1], MAX_NUM_REF_PICS)) + { + obs.PutBit(1); // slice_ref_pic_list_modification_flag_l1 + for(i = 0; i < num_ref_idx[1]; i++) + { + uint32_t code = 0; + bool found = false; + for(j = 0; (j < num_ref_list_temp1) && (j < MAX_NUM_REF_PICS_CUR); j++) + { + if (sliceParams.ref_list_idx[1][i] == ref_list_idx_rps[1][j]) + { + code = j; + found = true; + break; + } + } + if (!found) + mfx_res = MFX_ERR_UNDEFINED_BEHAVIOR; + + obs.PutBits(code, bits_num); + } + } + else + { + obs.PutBit(0); // slice_ref_pic_list_modification_flag_l1 + } + } + } + + if (sliceParams.slice_type == B_SLICE) + obs.PutBit(0); // mvd_l1_zero_flag + if (pps->cabac_init_present_flag) + obs.PutBit(0); // cabac_init_flag + + if (false) // slice_temporal_mvp_enabled_flag + { + if (sliceParams.slice_type == B_SLICE) + obs.PutBit(0); // collocated_from_l0_flag + + mfxI32 collocated_from_l0_flag = 0; // collocated_from_l0_flag + if (sliceParams.slice_type != B_SLICE) + collocated_from_l0_flag = 1; // inferred + + if (( collocated_from_l0_flag && num_ref_idx[0] > 1) || + (!collocated_from_l0_flag && num_ref_idx[1] > 1)) + obs.PutUe(0); // collocated_ref_idx + } + + // pred_weight_table + if ((pps->weighted_pred_flag && sliceParams.slice_type == P_SLICE) || + (pps->weighted_bipred_flag && sliceParams.slice_type == B_SLICE)) + { + uint8_t i; + uint8_t num_of_lists = (sliceParams.slice_type == B_SLICE ) ? (2) : (1); + + obs.PutUe(0); // luma_log2_weight_denom + if (sps->ChromaArrayType) + { + obs.PutSe(0); // delta_chroma_log2_weight_denom + } + + for(uint8_t list_num = 0; list_num < num_of_lists; list_num++ ) + { + for(i = 0; i < num_ref_idx[list_num]; i++) + { + obs.PutBit(0); // luma_weight_lX_flag + } + if (sps->ChromaArrayType) + { + for(i = 0 ; i < num_ref_idx[list_num] ; i++) + { + obs.PutBit(0); // chroma_weight_lX_flag + } + } + } + } + + obs.PutUe(0); // five_minus_max_num_merge_cand + } + + obs.PutSe(0); // slice_qp_delta + if (pps->pps_slice_chroma_qp_offsets_present_flag) + { + obs.PutSe(0); // slice_cb_qp_offset + obs.PutSe(0); // slice_cr_qp_offset + } + if (pps->pps_slice_act_qp_offsets_present_flag) + { + obs.PutSe(0); // slice_act_y_qp_offset + obs.PutSe(0); // slice_act_cb_qp_offset + obs.PutSe(0); // slice_act_cr_qp_offset + } + if (pps->chroma_qp_offset_list_enabled_flag) + { + obs.PutBit(0); // cu_chroma_qp_offset_enabled_flag + } + if (pps->deblocking_filter_control_present_flag) + { + if (pps->deblocking_filter_override_enabled_flag) + { + obs.PutBit(0); // deblocking_filter_override_flag + } + if (false) // deblocking_filter_override_flag + { + obs.PutBit(0); // slice_deblocking_filter_disabled_flag + if (true) // !slice_deblocking_filter_disabled_flag + { + obs.PutSe(0); // slice_beta_offset_div2 + obs.PutSe(0); // slice_tc_offset_div2 + } + } + } + if (pps->pps_loop_filter_across_slices_enabled_flag && + (false || // slice_sao_luma_flag + false || // slice_sao_chroma_flag + true)) // !slice_deblocking_filter_disabled_flag + { + obs.PutBit(0); // slice_loop_filter_across_slices_enabled_flag + } + } // !dependent_slice_segment_flag + + if (pps->tiles_enabled_flag || pps->entropy_coding_sync_enabled_flag) + { + obs.PutUe(0); // num_entry_point_offsets + } + if (pps->slice_segment_header_extension_present_flag) + { + obs.PutUe(0); // slice_header_extension_length + } + + obs.PutBit(1); + + if (sliceParams.nuh_temporal_id == 0) + { + if (((sliceParams.nal_unit_type <= NAL_RSV_VCL_R15) && ((sliceParams.nal_unit_type %2) !=0 )) || + ((sliceParams.nal_unit_type > NAL_UT_CODED_SLICE_BLA_W_LP) && (sliceParams.nal_unit_type <= NAL_RSV_IRAP_VCL23))) + { + if ((sliceParams.nal_unit_type != NAL_UT_CODED_SLICE_RADL_R) && + (sliceParams.nal_unit_type != NAL_UT_CODED_SLICE_RASL_R)) + { + previous_poc = current_poc; + } + } + } + } + + MFX_DEBUG_TRACE_I32(mfx_res); + return mfx_res; +} + +#endif diff --git a/c2_utils/src/mfx_va_allocator.cpp b/c2_utils/src/mfx_va_allocator.cpp index 74689709..522851b1 100755 --- a/c2_utils/src/mfx_va_allocator.cpp +++ b/c2_utils/src/mfx_va_allocator.cpp @@ -31,8 +31,6 @@ #undef MFX_DEBUG_MODULE_NAME #define MFX_DEBUG_MODULE_NAME "mfx_va_allocator" -#define va_to_mfx_status(sts) ((VA_STATUS_SUCCESS == sts) ? MFX_ERR_NONE : MFX_ERR_UNKNOWN) - #define IS_PRIME_VALID(prime) ((prime >= 0) ? true : false) #define DRM_FORMAT_MOD_VENDOR_NONE 0