Skip to content

Commit

Permalink
base for hucbuffer dev
Browse files Browse the repository at this point in the history
  • Loading branch information
kkkuangzh committed Sep 20, 2024
1 parent 46e7219 commit 5402a5e
Show file tree
Hide file tree
Showing 7 changed files with 1,017 additions and 13 deletions.
45 changes: 40 additions & 5 deletions c2_buffers/src/mfx_c2_bitstream_in.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -116,13 +118,46 @@ c2_status_t MfxC2BitstreamIn::AppendFrame(const C2FrameData& buf_pack, c2_nsecs_

MFX_DEBUG_TRACE_STREAM("data: " << FormatHex(data, filled_len));

std::unique_ptr<C2ConstLinearBlock> encryptedBlock;
for (auto &infoBuffer: buf_pack.infoBuffers) {
if (infoBuffer.index().typeIndex() == kParamIndexEncryptedBuffer) {
const C2BufferData& buf_data = infoBuffer.data();
encryptedBlock = std::make_unique<C2ConstLinearBlock>(buf_data.linearBlocks().front());
}
}

mfxU8* infobuffer = 0;
if (encryptedBlock != nullptr) {
std::unique_ptr<C2ReadView> bs_read_view;
MapConstLinearBlock(*encryptedBlock, TIMEOUT_NS, &bs_read_view);
const mfxU8* infobuffer = bs_read_view->data() + encryptedBlock->offset();
MFX_DEBUG_TRACE_STREAM("ZHDEBUG: DoWork() encryptedBlock: " << FormatHex(data, encryptedBlock->size()));
} else {
MFX_DEBUG_TRACE_STREAM("ZHDEBUG: DoWork() encryptedBlock is null");
}

m_frameConstructor->SetEosMode(buf_pack.flags & C2FrameData::FLAG_END_OF_STREAM);

mfxStatus 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;
if (MFX_ERR_NONE == mfx_res) {
HUCVideoBuffer *hucBuffer = NULL;
hucBuffer = (HUCVideoBuffer *) data;
if (hucBuffer->pr_magic == PROTECTED_BUFFER_HANDLE_MAGIC) {
// auto secureConstructor = std::dynamic_pointer_cast<MfxC2AVCSecureFrameConstructor>(m_frameConstructor);
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_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;

Expand Down
49 changes: 49 additions & 0 deletions c2_components/include/mfx_c2_secure_decoder_component.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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 <cutils/properties.h>

class MfxC2SecureDecoderComponent : public MfxC2DecoderComponent
{
public:
MfxC2SecureDecoderComponent(const C2String name, const CreateConfig& config,
std::shared_ptr<C2ReflectorHelper> reflector, DecoderType decoder_type);

virtual ~MfxC2SecureDecoderComponent();

static void RegisterClass(MfxC2ComponentsRegistry& registry);

MFX_CLASS_NO_COPY(MfxC2SecureDecoderComponent)

protected:
void DoWork(std::unique_ptr<C2Work>&& work);

private:
/* -----------------------C2Parameters--------------------------- */
std::shared_ptr<C2SecureModeTuning> m_secureMode;
};

270 changes: 270 additions & 0 deletions c2_components/src/mfx_c2_secure_decoder_component.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
// 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"
#include "C2PlatformSupport.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<C2ReflectorHelper> reflector, DecoderType decoder_type) :
MfxC2DecoderComponent(name, config, std::move(reflector), decoder_type)
{
MFX_DEBUG_TRACE_FUNC;

const unsigned int SINGLE_STREAM_ID = 0u;

// ALOGD("ZHDEBUG: No SM_READ_PROTECTED_WITH_ENCRYPTED in initialization");

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<MfxC2SecureDecoderComponent, DecoderType>::Create<DECODER_H264_SECURE>);

registry.RegisterMfxC2Component("c2.intel.hevc.decoder.secure",
&MfxC2Component::Factory<MfxC2SecureDecoderComponent, DecoderType>::Create<DECODER_H265_SECURE>);
}

void MfxC2SecureDecoderComponent::DoWork(std::unique_ptr<C2Work>&& work)
{
MFX_DEBUG_TRACE_FUNC;

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;
} 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 {
std::unique_ptr<C2ReadView> read_view;
res = m_c2Bitstream->AppendFrame(work->input, TIMEOUT_NS, &read_view);
if (C2_OK != res) break;

{
std::lock_guard<std::mutex> 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<MfxC2BufferQueueBlockPool>(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<std::mutex> 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<std::mutex> 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);
}
}
}
}
2 changes: 2 additions & 0 deletions c2_utils/include/mfx_c2_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 5402a5e

Please sign in to comment.