diff --git a/c2_buffers/src/mfx_c2_bitstream_in.cpp b/c2_buffers/src/mfx_c2_bitstream_in.cpp index 3b5ec69d..eb5967d7 100755 --- a/c2_buffers/src/mfx_c2_bitstream_in.cpp +++ b/c2_buffers/src/mfx_c2_bitstream_in.cpp @@ -29,6 +29,8 @@ using namespace android; #undef MFX_DEBUG_MODULE_NAME #define MFX_DEBUG_MODULE_NAME "mfx_c2_bitstream_in" +constexpr c2_nsecs_t TIMEOUT_NS = MFX_SECOND_NS; + MfxC2BitstreamIn::MfxC2BitstreamIn(MfxC2FrameConstructorType fc_type) { MFX_DEBUG_TRACE_FUNC; @@ -90,6 +92,25 @@ c2_status_t MfxC2BitstreamIn::AppendFrame(const C2FrameData& buf_pack, c2_nsecs_ const mfxU8* data = nullptr; mfxU32 filled_len = 0; + std::unique_ptr encryptedBlock; + for (auto &infoBuffer: buf_pack.infoBuffers) { + if (infoBuffer.index().typeIndex() == kParamIndexEncryptedBuffer) { + const C2BufferData& buf_data = infoBuffer.data(); + encryptedBlock = std::make_unique(buf_data.linearBlocks().front()); + } + } + + const mfxU8* infobuffer = nullptr; + std::unique_ptr bs_read_view; + + if (encryptedBlock != nullptr) { + MapConstLinearBlock(*encryptedBlock, TIMEOUT_NS, &bs_read_view); + infobuffer = bs_read_view->data() + encryptedBlock->offset(); + MFX_DEBUG_TRACE_STREAM("ZHDEBUG: encryptedBlock: " << FormatHex(infobuffer, encryptedBlock->size())); + } else { + MFX_DEBUG_TRACE_STREAM("ZHDEBUG: encryptedBlock is null"); + } + do { if (!frame_view) { res = C2_BAD_VALUE; @@ -114,15 +135,30 @@ c2_status_t MfxC2BitstreamIn::AppendFrame(const C2FrameData& buf_pack, c2_nsecs_ data = read_view->data() + c_linear_block->offset(); filled_len = c_linear_block->size(); + MFX_DEBUG_TRACE_I64(filled_len); MFX_DEBUG_TRACE_STREAM("data: " << FormatHex(data, filled_len)); m_frameConstructor->SetEosMode(buf_pack.flags & C2FrameData::FLAG_END_OF_STREAM); + mfxStatus mfx_res; + HUCVideoBuffer *hucBuffer = NULL; + hucBuffer = (HUCVideoBuffer *) data; + if (hucBuffer->pr_magic == PROTECTED_DATA_BUFFER_MAGIC) { + MFX_DEBUG_TRACE_STREAM("ZHDEBUG: hucBuffer->pr_magic == PROTECTED_DATA_BUFFER_MAGIC"); + mfx_res = m_frameConstructor->Load_data(data, + filled_len, + infobuffer, + buf_pack.ordinal.timestamp.peeku(), // pass pts + buf_pack.flags & C2FrameData::FLAG_CODEC_CONFIG, + true); + } else { + MFX_DEBUG_TRACE_STREAM("ZHDEBUG: hucBuffer->pr_magic != PROTECTED_DATA_BUFFER_MAGIC"); + mfx_res = m_frameConstructor->Load(data, + filled_len, + buf_pack.ordinal.timestamp.peeku(), // pass pts + buf_pack.flags & C2FrameData::FLAG_CODEC_CONFIG, + true); + } - mfxStatus mfx_res = m_frameConstructor->Load(data, - filled_len, - buf_pack.ordinal.timestamp.peeku(), // pass pts - buf_pack.flags & C2FrameData::FLAG_CODEC_CONFIG, - true); res = MfxStatusToC2(mfx_res); if(C2_OK != res) break; diff --git a/c2_components/include/mfx_c2_decoder_component.h b/c2_components/include/mfx_c2_decoder_component.h index 3f6fc2b8..41055f0e 100755 --- 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,16 @@ 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 {}; + // Accessed from working thread or stop method when working thread is stopped. std::unique_ptr m_mfxDecoder; @@ -183,12 +197,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 +207,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 +216,6 @@ 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 @@ -246,6 +252,9 @@ class MfxC2DecoderComponent : public MfxC2Component unsigned int m_uOutputDelay = 8u; unsigned int m_uInputDelay = 0u; +protected: + bool m_secure; + #if MFX_DEBUG_DUMP_FRAME == MFX_DEBUG_YES int m_count = 0; std::mutex m_count_lock; 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..88541f14 --- /dev/null +++ b/c2_components/include/mfx_c2_secure_decoder_component.h @@ -0,0 +1,47 @@ +// 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_c2_setters.h" +#include + +class MfxC2SecureDecoderComponent : public MfxC2DecoderComponent +{ +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) + + +private: + /* -----------------------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..9f23f6dc 100755 --- a/c2_components/src/mfx_c2_components_registry.cpp +++ b/c2_components/src/mfx_c2_components_registry.cpp @@ -31,6 +31,7 @@ #else #include "mfx_c2_decoder_component.h" #include "mfx_c2_encoder_component.h" +#include "mfx_c2_secure_decoder_component.h" #endif using namespace android; @@ -65,6 +66,7 @@ MfxC2ComponentsRegistry::MfxC2ComponentsRegistry() #else MfxC2DecoderComponent::RegisterClass(*this); MfxC2EncoderComponent::RegisterClass(*this); + MfxC2SecureDecoderComponent::RegisterClass(*this); #endif } diff --git a/c2_components/src/mfx_c2_decoder_component.cpp b/c2_components/src/mfx_c2_decoder_component.cpp index db7ccfea..8d013bbc 100755 --- a/c2_components/src/mfx_c2_decoder_component.cpp +++ b/c2_components/src/mfx_c2_decoder_component.cpp @@ -46,6 +46,7 @@ constexpr uint64_t kMinInputBufferSize = 1 * WIDTH_1K * HEIGHT_1K; constexpr uint64_t kDefaultConsumerUsage = (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER); +constexpr uint64_t kProtectedUsage = C2MemoryUsage::READ_PROTECTED; // Android S declared VP8 profile #if PLATFORM_SDK_VERSION <= 30 // Android 11(R) @@ -169,7 +170,8 @@ MfxC2DecoderComponent::MfxC2DecoderComponent(const C2String name, const CreateCo m_bInitialized(false), m_uSyncedPointsCount(0), m_bSetHdrStatic(false), - m_surfaceNum(0) + m_surfaceNum(0), + m_secure(false) { MFX_DEBUG_TRACE_FUNC; const unsigned int SINGLE_STREAM_ID = 0u; @@ -222,6 +224,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 +280,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; @@ -883,6 +887,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; @@ -1028,9 +1040,11 @@ mfxStatus MfxC2DecoderComponent::ResetSettings() switch (m_decoderType) { case DECODER_H264: + case DECODER_H264_SECURE: m_mfxVideoParams.mfx.CodecId = MFX_CODEC_AVC; break; case DECODER_H265: + case DECODER_H265_SECURE: m_mfxVideoParams.mfx.CodecId = MFX_CODEC_HEVC; break; case DECODER_VP9: @@ -1107,6 +1121,10 @@ mfxStatus MfxC2DecoderComponent::InitDecoder(std::shared_ptr c2_all mfxU16 cropW = 0, cropH = 0; std::lock_guard lock(m_initDecoderMutex); + MFX_DEBUG_TRACE_I32(m_secure); + if (m_secure) + m_consumerUsage |= kProtectedUsage; + { MFX_DEBUG_TRACE_MSG("InitDecoder: DecodeHeader"); @@ -1971,7 +1989,7 @@ void MfxC2DecoderComponent::DoWork(std::unique_ptr&& work) const auto incoming_flags = work->input.flags; MFX_DEBUG_TRACE_STREAM("work: " << work.get() << "; index: " << incoming_frame_index.peeku() << - " flags: " << std::hex << incoming_flags); + " flags: " << std::hex << incoming_flags << " infoBuffers: " << work->input.infoBuffers.size()); bool expect_output = false; bool flushing = false; 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..157ec547 --- /dev/null +++ b/c2_components/src/mfx_c2_secure_decoder_component.cpp @@ -0,0 +1,69 @@ +// 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 "mfx_debug.h" +#include "mfx_msdk_debug.h" +#include "mfx_c2_debug.h" +#include "mfx_c2_components_registry.h" +#include "mfx_defaults.h" + +#undef MFX_DEBUG_MODULE_NAME +#define MFX_DEBUG_MODULE_NAME "mfx_c2_secure_decoder_component" + +constexpr c2_nsecs_t TIMEOUT_NS = MFX_SECOND_NS; + + +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; + m_secure = true; + + 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); +} + diff --git a/c2_utils/include/mfx_c2_defs.h b/c2_utils/include/mfx_c2_defs.h index 48809dad..dc8694c9 100755 --- a/c2_utils/include/mfx_c2_defs.h +++ b/c2_utils/include/mfx_c2_defs.h @@ -37,6 +37,8 @@ #define MFX_C2_DUMP_DIR "/data/local/tmp" #define MFX_C2_DUMP_OUTPUT_SUB_DIR "c2-output" +#define ENABLE_WIDEVINE + const c2_nsecs_t MFX_SECOND_NS = 1000000000; // 1e9 extern const size_t g_h264_profile_levels_count; 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..d501a91e --- /dev/null +++ b/c2_utils/include/mfx_c2_widevine_crypto_defs.h @@ -0,0 +1,55 @@ +// 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 + +#define PROTECTED_DATA_BUFFER_MAGIC (0UL | ('E' << 24) | ('B' << 16) | ('D' << 8) | 'P') +using IV = std::array; + +typedef unsigned int VAGenericID; +typedef VAGenericID VAContextID; + + +typedef enum OEMCryptoCipherMode { + OEMCrypto_CipherMode_CTR, + OEMCrypto_CipherMode_CBC, + OEMCrypto_CipherMode_MaxValue = OEMCrypto_CipherMode_CBC, +} OEMCryptoCipherMode; + +typedef struct { + size_t block_offset; + IV current_iv; + size_t data_length; + size_t clear_bytes; + size_t encrypted_bytes; + size_t pattern_clear; + size_t pattern_encrypted; +} packet_info; + +typedef struct { + uint32_t pr_magic; + uint32_t app_id; + size_t num_packet_data; + size_t sample_size; + OEMCryptoCipherMode cipher_mode; + uint8_t hw_key_data[16]; + packet_info* packet_data; +} HUCVideoBuffer; \ No newline at end of file diff --git a/c2_utils/include/mfx_defs.h b/c2_utils/include/mfx_defs.h index 42e48323..84175273 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 diff --git a/c2_utils/include/mfx_frame_constructor.h b/c2_utils/include/mfx_frame_constructor.h index 902d107b..d52bb7b4 100755 --- a/c2_utils/include/mfx_frame_constructor.h +++ b/c2_utils/include/mfx_frame_constructor.h @@ -21,9 +21,16 @@ #pragma once #include "mfx_defs.h" +#ifdef ENABLE_WIDEVINE +#include "mfx_c2_widevine_crypto_defs.h" +#include "mfx_c2_bs_utils.h" +#include "mfx_c2_avc_bitstream.h" +#include "mfx_c2_hevc_bitstream.h" +#endif #include #include #include +#include enum MfxC2FrameConstructorType { @@ -34,6 +41,10 @@ enum MfxC2FrameConstructorType MfxC2FC_VP9, MfxC2FC_MP2, MfxC2FC_AV1, + #ifdef ENABLE_WIDEVINE + MfxC2FC_SEC_AVC, + MfxC2FC_SEC_HEVC, + #endif }; enum MfxC2BitstreamState @@ -72,6 +83,8 @@ class IMfxC2FrameConstructor // get whether in reset state virtual bool IsInReset() = 0; + virtual mfxStatus Load_data(const mfxU8* data, mfxU32 size, const mfxU8* infobuffer, mfxU64 pts, bool header, bool complete_frame) = 0; + protected: struct StartCode { @@ -115,6 +128,8 @@ class MfxC2FrameConstructor : public IMfxC2FrameConstructor // get whether in reset state virtual bool IsInReset(); + virtual mfxStatus Load_data(const mfxU8* data, mfxU32 size, const mfxU8* infobuffer, mfxU64 pts, bool header, bool complete_frame); + protected: // functions virtual mfxStatus LoadHeader(const mfxU8* data, mfxU32 size, bool header); virtual mfxStatus Load_None(const mfxU8* data, mfxU32 size, mfxU64 pts, bool header, bool complete_frame); @@ -144,6 +159,13 @@ class MfxC2FrameConstructor : public IMfxC2FrameConstructor // data from input sample (case when buffering and copying is not needed) std::shared_ptr m_bstIn; + // bs buffer used for WV L1 + std::shared_ptr m_bstEnc; + // ext buffer vector + std::vector m_extBufs; + // MFX_EXTBUFF_ENCRYPTION_PARAM + mfxExtEncryptionParam m_decryptParams; + // EOS flag bool m_bEos; @@ -152,6 +174,10 @@ class MfxC2FrameConstructor : public IMfxC2FrameConstructor mfxU32 m_uBstBufCopyBytes; bool m_bInReset; + +public: + uint8_t m_keyblob[16]; + private: MFX_CLASS_NO_COPY(MfxC2FrameConstructor) }; @@ -170,6 +196,9 @@ class MfxC2AVCFrameConstructor : public MfxC2FrameConstructor protected: // functions virtual mfxStatus Load(const mfxU8* data, mfxU32 size, mfxU64 pts, bool header, bool complete_frame); + + virtual mfxStatus Load_data(const mfxU8* data, mfxU32 size, const mfxU8* infobuffer, mfxU64 pts, bool header, bool complete_frame); + virtual mfxStatus LoadHeader(const mfxU8* data, mfxU32 size, bool header); // save current SEI virtual mfxStatus SaveSEI(mfxBitstream * /*pSEI*/) {return MFX_ERR_NONE;} @@ -230,6 +259,104 @@ 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 Load(const mfxU8* data, mfxU32 size, mfxU64 pts, bool header, bool complete_frame); + virtual mfxEncryptedData* GetFreeEncryptedDataItem(void); + virtual mfxEncryptedData* BuildEncryptedDataList(void); + +protected: + static const mfxU32 SLICE_HEADER_BUFFER_SIZE = 128; + std::list m_encryptedDataList; + HUCVideoBuffer* m_hucBuffer = nullptr; + + // 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); + virtual mfxStatus Load_data(const mfxU8* data, mfxU32 size, const mfxU8* infobuffer, mfxU64 pts, bool header, bool complete_frame); + +protected: + virtual StartCode ReadStartCode(const mfxU8** position, mfxU32* size_left); + 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(); + +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); + +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/src/mfx_frame_constructor.cpp b/c2_utils/src/mfx_frame_constructor.cpp index 20595eb9..addee917 100755 --- a/c2_utils/src/mfx_frame_constructor.cpp +++ b/c2_utils/src/mfx_frame_constructor.cpp @@ -43,6 +43,9 @@ MfxC2FrameConstructor::MfxC2FrameConstructor(): m_bstBuf = std::make_shared(); m_bstIn = std::make_shared(); + m_bstEnc = std::make_shared(); + MFX_ZERO_MEMORY((*m_bstEnc)); + MFX_ZERO_MEMORY((*m_bstHeader)); MFX_ZERO_MEMORY((*m_bstBuf)); MFX_ZERO_MEMORY((*m_bstIn)); @@ -141,6 +144,12 @@ mfxStatus MfxC2FrameConstructor::LoadHeader(const mfxU8* data, mfxU32 size, bool return mfx_res; } +mfxStatus MfxC2FrameConstructor::Load_data(const mfxU8* data, mfxU32 size, const mfxU8* bs, mfxU64 pts, bool b_header, bool bComplete) +{ + MFX_DEBUG_TRACE_FUNC; + return MFX_ERR_NONE; +} + mfxStatus MfxC2FrameConstructor::Load_None(const mfxU8* data, mfxU32 size, mfxU64 pts, bool header, bool complete_frame) { MFX_DEBUG_TRACE_FUNC; @@ -371,6 +380,12 @@ MfxC2AVCFrameConstructor::~MfxC2AVCFrameConstructor() MFX_FREE(m_pps.Data); } +mfxStatus MfxC2AVCFrameConstructor::Load_data(const mfxU8* data, mfxU32 size, const mfxU8* bs, mfxU64 pts, bool b_header, bool bComplete) +{ + MFX_DEBUG_TRACE_FUNC; + return MFX_ERR_NONE; +} + mfxStatus MfxC2AVCFrameConstructor::SaveHeaders(std::shared_ptr sps, std::shared_ptr pps, bool is_reset) { MFX_DEBUG_TRACE_FUNC; @@ -752,16 +767,429 @@ 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::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; + + if (MFX_ERR_NONE == mfx_res) { + HUCVideoBuffer *hucBuffer = NULL; + hucBuffer = (HUCVideoBuffer *) data; + + 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; +} + +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 = MFX_ERR_NONE; + + mfx_res = MfxC2FrameConstructor::Load(data, size, pts, b_header, bCompleteFrame); + + MFX_DEBUG_TRACE__mfxStatus(mfx_res); + return mfx_res; +} + +mfxStatus MfxC2AVCSecureFrameConstructor::Load_data(const mfxU8* data, mfxU32 size, const mfxU8* bs, mfxU64 pts, bool b_header, bool bCompleteFrame) +{ + MFX_DEBUG_TRACE_FUNC; + + mfxStatus mfx_res = MfxC2SecureFrameConstructor::Load(data, size, pts, b_header, bCompleteFrame); + + if (MFX_ERR_NONE != mfx_res) return mfx_res; + + std::memcpy(m_keyblob, m_hucBuffer->hw_key_data, sizeof(m_hucBuffer->hw_key_data)); + + bool bFoundSps = false; + bool bFoundPps = false; + bool bFoundIDR = false; + bool bFoundRegularSlice = false; + char* baseAddress = reinterpret_cast(m_hucBuffer); + + // Save SPS/PPS if exists + if (MFX_ERR_NONE == mfx_res) + { + for(int i = 0; i < m_hucBuffer->num_packet_data; i++) + { + data = NULL; + size = 0; + packet_info* packet = reinterpret_cast(baseAddress + sizeof(HUCVideoBuffer) - 8 + (i * sizeof(packet_info))); + + if (packet->clear_bytes != 0) + { + data = bs + packet->block_offset; + size = packet->clear_bytes; + } + 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; + } + } + } + + // alloc enough space for m_bstEnc->Data + if (m_bstEnc->MaxLength < m_hucBuffer->sample_size) + { + m_bstEnc->Data = (mfxU8*)realloc(m_bstEnc->Data, m_hucBuffer->sample_size); + if (!m_bstEnc->Data) + return MFX_ERR_MEMORY_ALLOC; + m_bstEnc->MaxLength = m_hucBuffer->sample_size; + } + + // copy clear data to m_bstEnc->Data + packet_info* packet = reinterpret_cast(baseAddress + sizeof(HUCVideoBuffer) - 8); + + m_bstEnc->DataOffset = 0; + std::copy(bs, bs + packet->clear_bytes, m_bstEnc->Data); + m_bstEnc->DataLength = packet->clear_bytes; + + // copy encrypted data to m_bstEnc->EncryptedData->Data + if (bFoundIDR || bFoundRegularSlice) { + mfxEncryptedData *pEncryptedData = NULL; + pEncryptedData = (mfxEncryptedData*) calloc(1, sizeof(mfxEncryptedData)); + if (pEncryptedData) + { + pEncryptedData->Data = (mfxU8*)realloc(pEncryptedData->Data, packet->encrypted_bytes); + if (!pEncryptedData->Data) + return MFX_ERR_MEMORY_ALLOC; + std::copy(bs + packet->clear_bytes, bs + packet->clear_bytes + packet->encrypted_bytes, pEncryptedData->Data); + pEncryptedData->DataLength = packet->encrypted_bytes; + pEncryptedData->DataOffset = 0; + pEncryptedData->Next = NULL; + } + + m_bstEnc->EncryptedData = pEncryptedData; + } + m_bstEnc->TimeStamp = pts; + + return mfx_res; +} + + +std::shared_ptr MfxC2AVCSecureFrameConstructor::GetMfxBitstream() +{ + MFX_DEBUG_TRACE_FUNC; + + auto pBitstream = MfxC2FrameConstructor::GetMfxBitstream(); + + if (m_hucBuffer) + { + MFX_ZERO_MEMORY(m_decryptParams); + + m_decryptParams.Header.BufferId = MFX_EXTBUFF_ENCRYPTION_PARAM; + m_decryptParams.Header.BufferSz = sizeof(mfxExtEncryptionParam); + m_decryptParams.uiNumSegments = m_hucBuffer->num_packet_data; + if (m_hucBuffer->cipher_mode == OEMCrypto_CipherMode_CTR) { + m_decryptParams.encryption_type = VA_ENCRYPTION_TYPE_SUBSAMPLE_CTR; + } else { + m_decryptParams.encryption_type = VA_ENCRYPTION_TYPE_FULLSAMPLE_CBC; + } + m_decryptParams.pSegmentInfo = (EncryptionSegmentInfo*)malloc(m_hucBuffer->num_packet_data * sizeof(EncryptionSegmentInfo)); + + char* baseAddress = reinterpret_cast(m_hucBuffer); + for (int i = 0; i < m_hucBuffer->num_packet_data; i++) + { + packet_info* packet = reinterpret_cast(baseAddress + sizeof(HUCVideoBuffer) - 8 + (i * sizeof(packet_info))); + + m_decryptParams.pSegmentInfo[i].segment_start_offset = packet->block_offset + packet->clear_bytes; + m_decryptParams.pSegmentInfo[i].segment_length = packet->encrypted_bytes; + m_decryptParams.pSegmentInfo[i].init_byte_length = packet->block_offset; + + IV temp_iv = packet->current_iv; + std::memcpy(m_decryptParams.pSegmentInfo[i].aes_cbc_iv_or_ctr, temp_iv.data(), temp_iv.size()); + std::memset(m_decryptParams.pSegmentInfo[i].aes_cbc_iv_or_ctr + temp_iv.size(), 0, sizeof(m_decryptParams.pSegmentInfo[i].aes_cbc_iv_or_ctr) - temp_iv.size()); + } + + m_extBufs.clear(); + m_extBufs.push_back(reinterpret_cast(&m_decryptParams)); + m_bstEnc->ExtParam = &m_extBufs.back(); + + m_bstEnc->NumExtParam = 1; + m_bstEnc->DataFlag |= MFX_BITSTREAM_COMPLETE_FRAME; + + MFX_DEBUG_TRACE_I32(m_bstEnc->TimeStamp); + MFX_DEBUG_TRACE_I32(m_bstEnc->DataLength); + MFX_DEBUG_TRACE_I32(m_bstEnc->EncryptedData->DataLength); + + return m_bstEnc; + } + + MFX_DEBUG_TRACE_P(pBitstream.get()); + return pBitstream; +} + +IMfxC2FrameConstructor::StartCode MfxC2AVCSecureFrameConstructor::ReadStartCode(const mfxU8** position, mfxU32* size_left) +{ + MFX_DEBUG_TRACE_FUNC; + + return MfxC2AVCFrameConstructor::ReadStartCode(position, size_left); +} + + +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); +} + +#endif