* Copyright (C) 2026 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 "video_encoder_object.h"
#include "avcodec_log.h"
#include "avcodec_errors.h"
#include "media_core.h"
#include "native_window.h"
#include "preprocessor_encoder.h"
namespace {
bool IsValidVideoEncoderMagic(AVMagic magic)
{
return magic == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER ||
magic == AVMagic::AVCODEC_MAGIC_PRIMARY_VIDEO_ENCODER ||
magic == AVMagic::AVCODEC_MAGIC_SECONDARY_VIDEO_ENCODER;
}
}
namespace OHOS {
namespace MediaAVCodec {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "VideoEncoderObject"};
constexpr size_t MAX_TEMPNUM = 64;
VideoEncoderObject::VideoEncoderObject(const std::shared_ptr<AVCodecVideoEncoder>& encoder)
: OH_AVCodec(AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER), videoEncoder_(encoder)
{
}
void VideoEncoderObject::ClearBufferList()
{
std::lock_guard<std::shared_mutex> lock(objListMutex_);
if (inputBufferMap_.size() > 0) {
BufferToTempFunc(inputBufferMap_);
inputBufferMap_.clear();
}
if (outputBufferMap_.size() > 0) {
BufferToTempFunc(outputBufferMap_);
outputBufferMap_.clear();
}
if (inputMemoryMap_.size() > 0) {
MemoryToTempFunc(inputMemoryMap_);
inputMemoryMap_.clear();
}
if (outputMemoryMap_.size() > 0) {
MemoryToTempFunc(outputMemoryMap_);
outputMemoryMap_.clear();
}
if (inputFormatMap_.size() > 0) {
FormatToTempFunc(inputFormatMap_);
inputFormatMap_.clear();
}
while (tempList_.size() > MAX_TEMPNUM) {
tempList_.pop();
}
}
void VideoEncoderObject::StopCallback()
{
if (callback_ == nullptr) {
return;
}
callback_->StopCallback();
}
void VideoEncoderObject::FormatToTempFunc(std::unordered_map<uint32_t, OHOS::sptr<OH_AVFormat>>& tempMap)
{
for (auto& val : tempMap) {
val.second->magic_ = MFMagic::MFMAGIC_UNKNOWN;
if (val.second->outString_ != nullptr) {
free(val.second->outString_);
val.second->outString_ = nullptr;
}
if (val.second->dumpInfo_ != nullptr) {
free(val.second->dumpInfo_);
val.second->dumpInfo_ = nullptr;
}
val.second->format_ = Media::Format();
tempList_.push(std::move(val.second));
}
}
void VideoEncoderObject::BufferToTempFunc(std::unordered_map<uint32_t, OHOS::sptr<OH_AVBuffer>>& tempMap)
{
for (auto& val : tempMap) {
val.second->magic_ = MFMagic::MFMAGIC_UNKNOWN;
val.second->buffer_ = nullptr;
tempList_.push(std::move(val.second));
}
}
void VideoEncoderObject::MemoryToTempFunc(std::unordered_map<uint32_t, OHOS::sptr<OH_AVMemory>>& tempMap)
{
for (auto& val : tempMap) {
val.second->magic_ = MFMagic::MFMAGIC_UNKNOWN;
val.second->memory_ = nullptr;
tempList_.push(std::move(val.second));
}
}
OH_AVMemory* VideoEncoderObject::GetTransData(const uint32_t& index, std::shared_ptr<AVSharedMemory>& memory,
bool isOutput)
{
auto& memoryMap = isOutput ? outputMemoryMap_ : inputMemoryMap_;
{
std::shared_lock<std::shared_mutex> lock(objListMutex_);
auto iter = memoryMap.find(index);
if (iter != memoryMap.end() && iter->second->IsEqualMemory(memory)) {
return reinterpret_cast<OH_AVMemory*>(iter->second.GetRefPtr());
}
}
OHOS::sptr<OH_AVMemory> object = new (std::nothrow) OH_AVMemory(memory);
CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "AV memory create failed");
std::lock_guard<std::shared_mutex> lock(objListMutex_);
auto iterAndRet = memoryMap.emplace(index, object);
if (!iterAndRet.second) {
auto& temp = iterAndRet.first->second;
temp->magic_ = MFMagic::MFMAGIC_UNKNOWN;
temp->memory_ = nullptr;
tempList_.push(std::move(temp));
iterAndRet.first->second = object;
if (tempList_.size() > MAX_TEMPNUM) {
tempList_.pop();
}
}
return reinterpret_cast<OH_AVMemory*>(object.GetRefPtr());
}
OH_AVBuffer* VideoEncoderObject::GetTransData(const uint32_t& index, std::shared_ptr<AVBuffer>& buffer, bool isOutput)
{
auto& bufferMap = isOutput ? outputBufferMap_ : inputBufferMap_;
{
std::shared_lock<std::shared_mutex> lock(objListMutex_);
auto iter = bufferMap.find(index);
if (iter != bufferMap.end() && iter->second->IsEqualBuffer(buffer)) {
return reinterpret_cast<OH_AVBuffer*>(iter->second.GetRefPtr());
}
}
OHOS::sptr<OH_AVBuffer> object = new (std::nothrow) OH_AVBuffer(buffer);
CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "failed to new OH_AVBuffer");
std::lock_guard<std::shared_mutex> lock(objListMutex_);
auto iterAndRet = bufferMap.emplace(index, object);
if (!iterAndRet.second) {
auto& temp = iterAndRet.first->second;
temp->magic_ = MFMagic::MFMAGIC_UNKNOWN;
temp->buffer_ = nullptr;
tempList_.push(std::move(temp));
iterAndRet.first->second = object;
if (tempList_.size() > MAX_TEMPNUM) {
tempList_.pop();
}
}
return reinterpret_cast<OH_AVBuffer*>(object.GetRefPtr());
}
OH_AVFormat* VideoEncoderObject::GetTransData(const uint32_t& index, std::shared_ptr<Media::Format>& format)
{
{
std::shared_lock<std::shared_mutex> lock(objListMutex_);
auto iter = inputFormatMap_.find(index);
if (iter != inputFormatMap_.end() && iter->second->format_.GetMeta() == format->GetMeta()) {
return reinterpret_cast<OH_AVFormat*>(iter->second.GetRefPtr());
}
}
OHOS::sptr<OH_AVFormat> object = new (std::nothrow) OH_AVFormat();
CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "failed to new OH_AVFormat");
object->format_.SetMetaPtr(format->GetMeta());
std::lock_guard<std::shared_mutex> lock(objListMutex_);
auto iterAndRet = inputFormatMap_.emplace(index, object);
if (!iterAndRet.second) {
auto& temp = iterAndRet.first->second;
temp->magic_ = MFMagic::MFMAGIC_UNKNOWN;
if (temp->outString_ != nullptr) {
free(temp->outString_);
temp->outString_ = nullptr;
}
if (temp->dumpInfo_ != nullptr) {
free(temp->dumpInfo_);
temp->dumpInfo_ = nullptr;
}
temp->format_ = Media::Format();
tempList_.push(std::move(temp));
iterAndRet.first->second = object;
if (tempList_.size() > MAX_TEMPNUM) {
tempList_.pop();
}
}
return reinterpret_cast<OH_AVFormat*>(object.GetRefPtr());
}
NativeVideoEncoderCallback::NativeVideoEncoderCallback(struct OH_AVCodec* codec,
struct OH_AVCodecAsyncCallback cb,
void* userData)
: codec_(codec), asyncCallback_(cb), userData_(userData)
{
}
NativeVideoEncoderCallback::NativeVideoEncoderCallback(struct OH_AVCodec* codec,
OH_VideoEncoder_OnNeedInputParameter onInputParameter,
void* userData)
: codec_(codec), onInputParameter_(onInputParameter), paramUserData_(userData)
{
}
NativeVideoEncoderCallback::NativeVideoEncoderCallback(struct OH_AVCodec* codec,
struct OH_AVCodecCallback cb,
void* userData)
: codec_(codec), callback_(cb), userData_(userData)
{
}
void NativeVideoEncoderCallback::OnError(AVCodecErrorType errorType, int32_t errorCode)
{
std::shared_lock<std::shared_mutex> lock(mutex_);
(void)errorType;
CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr");
CHECK_AND_RETURN_LOG(IsValidVideoEncoderMagic(codec_->magic_), "Codec magic error!");
CHECK_AND_RETURN_LOG(asyncCallback_.onError != nullptr || callback_.onError != nullptr, "Callback is nullptr");
int32_t extErr = AVCSErrorToOHAVErrCode(static_cast<AVCodecServiceErrCode>(errorCode));
if (asyncCallback_.onError != nullptr) {
asyncCallback_.onError(codec_, extErr, userData_);
} else if (callback_.onError != nullptr) {
callback_.onError(codec_, extErr, userData_);
}
}
void NativeVideoEncoderCallback::OnOutputFormatChanged(const Media::Format& format)
{
std::shared_lock<std::shared_mutex> lock(mutex_);
CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr");
CHECK_AND_RETURN_LOG(IsValidVideoEncoderMagic(codec_->magic_), "Codec magic error!");
if (PreprocessorEncoder::IsPreprocEncoderMagic(codec_->magic_)) {
return;
}
CHECK_AND_RETURN_LOG(asyncCallback_.onStreamChanged != nullptr || callback_.onStreamChanged != nullptr,
"Callback is nullptr");
OHOS::sptr<OH_AVFormat> object = new (std::nothrow) OH_AVFormat(format);
CHECK_AND_RETURN_LOG(object != nullptr, "OH_AVFormat create failed");
if (asyncCallback_.onStreamChanged != nullptr) {
asyncCallback_.onStreamChanged(codec_, reinterpret_cast<OH_AVFormat *>(object.GetRefPtr()), userData_);
} else if (callback_.onStreamChanged != nullptr) {
callback_.onStreamChanged(codec_, reinterpret_cast<OH_AVFormat *>(object.GetRefPtr()), userData_);
}
}
void NativeVideoEncoderCallback::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
{
std::shared_lock<std::shared_mutex> lock(mutex_);
CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr");
CHECK_AND_RETURN_LOG(codec_->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, "Codec magic error!");
CHECK_AND_RETURN_LOG(asyncCallback_.onNeedInputData != nullptr, "Callback is nullptr");
struct VideoEncoderObject *videoEncObj = reinterpret_cast<VideoEncoderObject *>(codec_);
CHECK_AND_RETURN_LOG(videoEncObj->videoEncoder_ != nullptr, "Context video encoder is nullptr!");
if (videoEncObj->isInputSurfaceMode_) {
AVCODEC_LOGD("At surface mode, no buffer available");
return;
}
OH_AVMemory *data = videoEncObj->GetTransData(index, buffer, false);
asyncCallback_.onNeedInputData(codec_, index, data, userData_);
}
void NativeVideoEncoderCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info,
AVCodecBufferFlag flag,
std::shared_ptr<AVSharedMemory> buffer)
{
std::shared_lock<std::shared_mutex> lock(mutex_);
CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr");
CHECK_AND_RETURN_LOG(codec_->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, "Codec magic error!");
CHECK_AND_RETURN_LOG(asyncCallback_.onNeedOutputData != nullptr, "Callback is nullptr");
struct VideoEncoderObject *videoEncObj = reinterpret_cast<VideoEncoderObject *>(codec_);
CHECK_AND_RETURN_LOG(videoEncObj->videoEncoder_ != nullptr, "Context video encoder is nullptr!");
struct OH_AVCodecBufferAttr bufferAttr {
info.presentationTimeUs, info.size, info.offset, flag
};
OH_AVMemory *data = videoEncObj->GetTransData(index, buffer, true);
asyncCallback_.onNeedOutputData(codec_, index, data, &bufferAttr, userData_);
}
void NativeVideoEncoderCallback::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
{
std::shared_lock<std::shared_mutex> lock(mutex_);
CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr");
CHECK_AND_RETURN_LOG(codec_->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, "Codec magic error!");
CHECK_AND_RETURN_LOG(callback_.onNeedInputBuffer != nullptr, "Callback is nullptr");
struct VideoEncoderObject *videoEncObj = reinterpret_cast<VideoEncoderObject *>(codec_);
CHECK_AND_RETURN_LOG(videoEncObj->videoEncoder_ != nullptr, "Context video encoder is nullptr!");
OH_AVBuffer *data = videoEncObj->GetTransData(index, buffer, false);
callback_.onNeedInputBuffer(codec_, index, data, userData_);
}
void NativeVideoEncoderCallback::OnOutputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
{
std::shared_lock<std::shared_mutex> lock(mutex_);
CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr");
CHECK_AND_RETURN_LOG(IsValidVideoEncoderMagic(codec_->magic_), "Codec magic error!");
CHECK_AND_RETURN_LOG(callback_.onNewOutputBuffer != nullptr, "Callback is nullptr");
OH_AVBuffer *data = nullptr;
if (PreprocessorEncoder::IsPreprocEncoderMagic(codec_->magic_)) {
auto *preprocEnc = reinterpret_cast<PreprocessorEncoder *>(codec_);
auto result = preprocEnc->GetTransData(index, buffer, true);
if (!result) {
return;
}
data = *result;
} else {
struct VideoEncoderObject *videoEncObj = reinterpret_cast<VideoEncoderObject *>(codec_);
CHECK_AND_RETURN_LOG(videoEncObj->videoEncoder_ != nullptr, "Context video encoder is nullptr!");
data = videoEncObj->GetTransData(index, buffer, true);
}
callback_.onNewOutputBuffer(codec_, index, data, userData_);
}
void NativeVideoEncoderCallback::OnInputParameterAvailable(uint32_t index, std::shared_ptr<Media::Format> parameter)
{
std::shared_lock<std::shared_mutex> lock(mutex_);
CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr!");
CHECK_AND_RETURN_LOG(codec_->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, "Codec magic error!");
CHECK_AND_RETURN_LOG(onInputParameter_ != nullptr, "Callback is nullptr");
struct VideoEncoderObject *videoEncObj = reinterpret_cast<VideoEncoderObject *>(codec_);
CHECK_AND_RETURN_LOG(videoEncObj->videoEncoder_ != nullptr, "Video encoder is nullptr!");
OH_AVFormat *data = videoEncObj->GetTransData(index, parameter);
onInputParameter_(codec_, index, data, paramUserData_);
}
void NativeVideoEncoderCallback::StopCallback()
{
std::lock_guard<std::shared_mutex> lock(mutex_);
codec_ = nullptr;
}
void NativeVideoEncoderCallback::UpdateCallback(const struct OH_AVCodecAsyncCallback& cb, void* userData)
{
std::lock_guard<std::shared_mutex> lock(mutex_);
userData_ = userData;
asyncCallback_ = cb;
}
void NativeVideoEncoderCallback::UpdateCallback(const OH_VideoEncoder_OnNeedInputParameter& onInputParameter,
void* userData)
{
std::lock_guard<std::shared_mutex> lock(mutex_);
paramUserData_ = userData;
onInputParameter_ = onInputParameter;
}
void NativeVideoEncoderCallback::UpdateCallback(const struct OH_AVCodecCallback& cb, void* userData)
{
std::lock_guard<std::shared_mutex> lock(mutex_);
userData_ = userData;
callback_ = cb;
}
}
}