/* * Copyright (C) 2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "openssl/crypto.h" #include "openssl/sha.h" #include "syncdecoder_sample.h" #include "nlohmann/json.hpp" using namespace OHOS; using namespace OHOS::Media; using namespace std; using namespace nlohmann; namespace { constexpr int64_t NANOS_IN_SECOND = 1000000000L; constexpr int64_t NANOS_IN_MICRO = 1000L; constexpr uint32_t START_CODE_SIZE = 4; constexpr uint8_t START_CODE[START_CODE_SIZE] = {0, 0, 0, 1}; VDecSyncSample *g_decSample = nullptr; } // namespace class ConsumerListenerBuffer : public IBufferConsumerListener { public: ConsumerListenerBuffer(sptr cs, std::string_view name) : cs(cs) { outFile_ = std::make_unique(); outFile_->open(name.data(), std::ios::out | std::ios::binary); }; ~ConsumerListenerBuffer() { if (outFile_ != nullptr) { outFile_->close(); } } void OnBufferAvailable() override { sptr buffer; int32_t flushFence; cs->AcquireBuffer(buffer, flushFence, timestamp, damage); cs->ReleaseBuffer(buffer, -1); } private: int64_t timestamp = 0; Rect damage = {}; sptr cs {nullptr}; std::unique_ptr outFile_; }; VDecSyncSample::~VDecSyncSample() { for (int i = 0; i < maxSurfNum; i++) { if (nativeWindow[i]) { OH_NativeWindow_DestroyNativeWindow(nativeWindow[i]); nativeWindow[i] = nullptr; } } Stop(); Release(); } int64_t VDecSyncSample::GetSystemTimeUs() { struct timespec now; (void)clock_gettime(CLOCK_BOOTTIME, &now); int64_t nanoTime = static_cast(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec; return nanoTime / NANOS_IN_MICRO; } int32_t VDecSyncSample::ConfigureVideoDecoder() { OH_AVFormat *format = OH_AVFormat_Create(); if (format == nullptr) { cout << "Fatal: Failed to create format" << endl; return AV_ERR_UNKNOWN; } if (maxInputSize > 0) { (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_MAX_INPUT_SIZE, maxInputSize); } originalWidth = defaultWidth; originalHeight = defaultHeight; (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, defaultWidth); (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, defaultHeight); (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, defualtPixelFormat); (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, defaultFrameRate); if (useHDRSource) { (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, DEFAULT_PROFILE); } else { (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, DEFAULT_PROFILE); } if (transferFlag) { (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_DECODER_OUTPUT_COLOR_SPACE, OH_COLORSPACE_BT709_LIMIT); } if (nV21Flag) { (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_NV21); } if (enableVRR) { (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_DECODER_OUTPUT_ENABLE_VRR, 1); } if (enableLowLatency) { (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENABLE_LOW_LATENCY, 1); } (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_ENABLE_SYNC_MODE, enbleSyncMode); (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_DECODER_BLANK_FRAME_ON_SHUTDOWN, enbleBlankFrame); int ret = OH_VideoDecoder_Configure(vdec_, format); OH_AVFormat_Destroy(format); return ret; } void VDecSyncSample::CreateSurface() { cs[0] = Surface::CreateSurfaceAsConsumer(); if (cs[0] == nullptr) { cout << "Create the surface consummer fail" << endl; return; } GSError err = cs[0]->SetDefaultUsage(BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_VIDEO_DECODER | BUFFER_USAGE_CPU_READ); if (err == GSERROR_OK) { cout << "set consumer usage succ" << endl; } else { cout << "set consumer usage failed" << endl; } sptr listener = new ConsumerListenerBuffer(cs[0], outDir); cs[0]->RegisterConsumerListener(listener); auto p = cs[0]->GetProducer(); ps[0] = Surface::CreateSurfaceAsProducer(p); nativeWindow[0] = CreateNativeWindowFromSurface(&ps[0]); if (autoSwitchSurface) { cs[1] = Surface::CreateSurfaceAsConsumer(); sptr listener2 = new ConsumerListenerBuffer(cs[1], outDir2); cs[1]->RegisterConsumerListener(listener2); auto p2 = cs[1]->GetProducer(); ps[1] = Surface::CreateSurfaceAsProducer(p2); nativeWindow[1] = CreateNativeWindowFromSurface(&ps[1]); } } int32_t VDecSyncSample::CreateVideoDecoder(string codeName) { vdec_ = OH_VideoDecoder_CreateByName(codeName.c_str()); g_decSample = this; return vdec_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK; } int32_t VDecSyncSample::SyncInputFuncFuzz(const uint8_t *data, size_t size) { uint32_t index; if (!isRunning_.load()) { return AV_ERR_NO_MEMORY; } cout << "OH_VideoDecoder_QueryInputBuffer start" << endl; if (OH_VideoDecoder_QueryInputBuffer(vdec_, &index, syncInputWaitTime) != AV_ERR_OK) { cout << "OH_VideoDecoder_QueryInputBuffer fail" << endl; return AV_ERR_NO_MEMORY; } cout << "OH_VideoDecoder_QueryInputBuffer succ" << endl; OH_AVBuffer *buffer = OH_VideoDecoder_GetInputBuffer(vdec_, index); if (buffer == nullptr) { cout << "OH_VideoDecoder_GetInputBuffer fail" << endl; errCount = errCount + 1; return AV_ERR_NO_MEMORY; } int32_t bufferSize = OH_AVBuffer_GetCapacity(buffer); uint8_t *bufferAddr = OH_AVBuffer_GetAddr(buffer); if (size > bufferSize - START_CODE_SIZE) { OH_VideoDecoder_PushInputBuffer(vdec_, index); return AV_ERR_NO_MEMORY; } if (memcpy_s(bufferAddr, bufferSize, START_CODE, START_CODE_SIZE) != EOK) { OH_VideoDecoder_PushInputBuffer(vdec_, index); return AV_ERR_NO_MEMORY; } if (memcpy_s(bufferAddr + START_CODE_SIZE, bufferSize - START_CODE_SIZE, data, size) != EOK) { OH_VideoDecoder_PushInputBuffer(vdec_, index); cout << "Fatal: memcpy fail" << endl; return AV_ERR_NO_MEMORY; } OH_AVCodecBufferAttr attr; attr.pts = GetSystemTimeUs(); attr.size = size; attr.offset = 0; attr.flags = AVCODEC_BUFFER_FLAGS_NONE; OH_AVBuffer_SetBufferAttr(buffer, &attr); OH_AVErrCode ret = OH_VideoDecoder_PushInputBuffer(vdec_, index); return ret; } int32_t VDecSyncSample::SyncOutputFuncFuzz() { uint32_t index = 0; cout << "OH_VideoDecoder_QueryOutputBuffer start" << endl; int32_t ret = OH_VideoDecoder_QueryOutputBuffer(vdec_, &index, syncOutputWaitTime); if (ret != AV_ERR_OK) { cout << "OH_VideoDecoder_QueryOutputBuffer fail" << endl; return AV_ERR_UNKNOWN; } cout << "OH_VideoDecoder_QueryOutputBuffer succ" << endl; OH_AVBuffer *buffer = OH_VideoDecoder_GetOutputBuffer(vdec_, index); if (buffer == nullptr) { cout << "OH_VideoDecoder_QueryOutputBuffer fail" << endl; return AV_ERR_UNKNOWN; } if (sfOutput) { if (isRenderAttime) { ret = OH_VideoDecoder_RenderOutputBufferAtTime(vdec_, index, renderTimestampNs); } else { ret = OH_VideoDecoder_RenderOutputBuffer(vdec_, index); } } else { ret = OH_VideoDecoder_FreeOutputBuffer(vdec_, index); } if (ret != AV_ERR_OK) { Flush(); Start(); } return AV_ERR_OK; } int32_t VDecSyncSample::Flush() { isFlushing_.store(true); isRunning_.store(false); int32_t ret = OH_VideoDecoder_Flush(vdec_); isFlushing_.store(false); return ret; } int32_t VDecSyncSample::Reset() { isRunning_.store(false); return OH_VideoDecoder_Reset(vdec_); } int32_t VDecSyncSample::Release() { int ret = 0; if (vdec_ != nullptr) { ret = OH_VideoDecoder_Destroy(vdec_); vdec_ = nullptr; } return ret; } int32_t VDecSyncSample::Stop() { return OH_VideoDecoder_Stop(vdec_); } int32_t VDecSyncSample::Start() { isRunning_.store(true); return OH_VideoDecoder_Start(vdec_); } int32_t VDecSyncSample::DecodeSetSurface() { CreateSurface(); return OH_VideoDecoder_SetSurface(vdec_, nativeWindow[0]); } void VDecSyncSample::SetParameter(int32_t data) { OH_AVFormat *format = OH_AVFormat_Create(); (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, data); (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, data); OH_VideoDecoder_SetParameter(vdec_, format); OH_AVFormat_Destroy(format); }