* Copyright (C) 2023 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 "avcodec_audio_codec_impl.h"
#include "i_avcodec_service.h"
#include "avcodec_log.h"
#include "avcodec_errors.h"
#include "avcodec_trace.h"
#include "avcodec_codec_name.h"
#include "avcodec_mime_type.h"
#include "audio_codec_server.h"
#include "qos.h"
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO, "AVCodecAudioCodecImpl"};
constexpr int32_t DEFAULT_BUFFER_NUM = 4;
constexpr const char *INPUT_BUFFER_QUEUE_NAME = "AVCodecAudioCodecImpl";
const std::string_view ASYNC_HANDLE_INPUT = "OS_ACodecIn";
const std::string_view ASYNC_OUTPUT_FRAME = "OS_ACodecOut";
constexpr uint8_t LOGD_FREQUENCY = 5;
constexpr uint8_t TIME_OUT_MS = 50;
constexpr uint32_t DEFAULT_TRY_DECODE_TIME = 1000;
constexpr uint32_t MAX_INDEX = 1000000000;
constexpr int64_t MILLISECONDS = 100;
}
namespace OHOS {
namespace MediaAVCodec {
AudioCodecConsumerListener::AudioCodecConsumerListener(AVCodecAudioCodecImpl *impl)
{
impl_ = impl;
}
void AudioCodecConsumerListener::OnBufferAvailable()
{
impl_->Notify();
}
int32_t AVCodecAudioCodecImpl::Init(AVCodecType type, bool isMimeType, const std::string &name)
{
AVCODEC_SYNC_TRACE;
bool enableOuter = isMimeType
? AVCodecMimeType::CheckAudioCodecMimeSupportOuter(name, type == AVCODEC_TYPE_AUDIO_ENCODER)
: AVCodecCodecName::CheckAudioCodecNameSupportOuter(name);
if (!enableOuter) {
AVCODEC_LOGW("AVCodecAudioCodecImpl: %{public}s not support", name.c_str());
return AVCS_ERR_UNSUPPORT;
}
Format format;
codecService_ = AudioCodecServer::Create();
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_UNKNOWN, "failed to create codec service");
implBufferQueue_ = Media::AVBufferQueue::Create(DEFAULT_BUFFER_NUM, Media::MemoryType::SHARED_MEMORY,
INPUT_BUFFER_QUEUE_NAME);
CHECK_AND_RETURN_RET_LOG(implBufferQueue_ != nullptr, AVCS_ERR_NO_MEMORY, "failed to create buffer queue");
inputTask_ = std::make_unique<TaskThread>(ASYNC_HANDLE_INPUT);
CHECK_AND_RETURN_RET_LOG(inputTask_ != nullptr, AVCS_ERR_NO_MEMORY, "failed to create input task");
outputTask_ = std::make_unique<TaskThread>(ASYNC_OUTPUT_FRAME);
CHECK_AND_RETURN_RET_LOG(outputTask_ != nullptr, AVCS_ERR_NO_MEMORY, "failed to create output task");
return codecService_->Init(type, isMimeType, name, *format.GetMeta(), API_VERSION::API_VERSION_11);
}
AVCodecAudioCodecImpl::AVCodecAudioCodecImpl()
{
AVCODEC_LOGI("AVCodecAudioCodecImpl:0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
}
AVCodecAudioCodecImpl::~AVCodecAudioCodecImpl()
{
codecService_ = nullptr;
AVCODEC_LOGI("AVCodecAudioCodecImpl:0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
}
int32_t AVCodecAudioCodecImpl::Configure(const Format &format)
{
AVCODEC_SYNC_TRACE;
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_STATE, "service died");
auto meta = const_cast<Format &>(format).GetMeta();
inputBufferSize_ = 0;
int32_t syncMode = 0;
format.GetIntValue(Media::Tag::AV_CODEC_ENABLE_SYNC_MODE, syncMode);
isSyncMode_.store(syncMode == 1);
AVCODEC_LOGI("AVCodecAudioCodecImpl:0x%{public}06" PRIXPTR " sync mode:%{public}d", FAKE_POINTER(this), syncMode);
if (isSyncMode_.load()) {
std::shared_ptr<AVCodecInnerCallback> innerCallback = std::make_shared<AVCodecInnerCallback>(this);
codecService_->SetCallback(innerCallback);
}
return codecService_->Configure(meta);
}
int32_t AVCodecAudioCodecImpl::Prepare()
{
AVCODEC_SYNC_TRACE;
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_STATE, "service died");
implProducer_ = implBufferQueue_->GetProducer();
codecService_->SetOutputBufferQueue(implProducer_);
int32_t ret = codecService_->Prepare();
CHECK_AND_RETURN_RET_LOG_LIMIT(ret != AVCS_ERR_TRY_AGAIN, AVCS_ERR_OK,
LOGD_FREQUENCY, "no need prepare");
CHECK_AND_RETURN_RET_LOG(ret == 0, AVCS_ERR_INVALID_STATE, "prepare fail, ret:%{public}d", ret);
implConsumer_ = implBufferQueue_->GetConsumer();
mediaCodecProducer_ = codecService_->GetInputBufferQueue();
CHECK_AND_RETURN_RET_LOG(mediaCodecProducer_ != nullptr, AVCS_ERR_INVALID_VAL, "mediaCodecProducer_ is nullptr");
sptr<Media::IConsumerListener> comsumerListener = new AudioCodecConsumerListener(this);
implConsumer_->SetBufferAvailableListener(comsumerListener);
outputTask_->RegisterHandler([this] { ConsumerOutputBuffer(); });
if (!isSyncMode_.load()) {
inputTask_->RegisterHandler([this] { ProduceInputBuffer(); });
}
return AVCS_ERR_OK;
}
int32_t AVCodecAudioCodecImpl::Start()
{
AVCODEC_SYNC_TRACE;
CHECK_AND_RETURN_RET_LOG(Prepare() == AVCS_ERR_OK, AVCS_ERR_INVALID_STATE, "Prepare failed");
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_STATE, "service died");
int32_t ret = codecService_->Start();
CHECK_AND_RETURN_RET_LOG(ret == 0, ret, "Start failed, ret:%{public}d", ret);
isRunning_ = true;
indexInput_ = 0;
indexOutput_ = 0;
if (!isSyncMode_.load()) {
if (inputTask_) {
inputTask_->Start();
} else {
AVCODEC_LOGE("Start failed, inputTask_ is nullptr, please check the inputTask_.");
ret = AVCS_ERR_UNKNOWN;
}
}
if (outputTask_) {
outputTask_->Start();
} else {
AVCODEC_LOGE("Start failed, outputTask_ is nullptr, please check the outputTask_.");
ret = AVCS_ERR_UNKNOWN;
}
AVCODEC_LOGI("Instances:0x%{public}06" PRIXPTR " Start, ret = %{public}d", FAKE_POINTER(this), ret);
return ret;
}
int32_t AVCodecAudioCodecImpl::Stop()
{
AVCODEC_SYNC_TRACE;
AVCODEC_LOGI("Instances:0x%{public}06" PRIXPTR " Stop", FAKE_POINTER(this));
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_STATE, "service died");
StopTaskAsync();
int32_t ret = codecService_->Stop();
StopTask();
ClearCache();
ReturnInputBuffer();
return ret;
}
int32_t AVCodecAudioCodecImpl::Flush()
{
AVCODEC_SYNC_TRACE;
AVCODEC_LOGI("Instances:0x%{public}06" PRIXPTR " Flush", FAKE_POINTER(this));
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_STATE, "service died");
PauseTaskAsync();
int32_t ret = codecService_->Flush();
PauseTask();
ClearCache();
ReturnInputBuffer();
return ret;
}
int32_t AVCodecAudioCodecImpl::Reset()
{
AVCODEC_SYNC_TRACE;
AVCODEC_LOGI("Instances:0x%{public}06" PRIXPTR " Reset", FAKE_POINTER(this));
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_STATE, "service died");
StopTaskAsync();
int32_t ret = codecService_->Reset();
StopTask();
ClearCache();
ClearInputBuffer();
implBufferQueue_ = Media::AVBufferQueue::Create(DEFAULT_BUFFER_NUM, Media::MemoryType::SHARED_MEMORY,
INPUT_BUFFER_QUEUE_NAME);
CHECK_AND_RETURN_RET_LOG(implBufferQueue_ != nullptr, AVCS_ERR_NO_MEMORY, "failed to create buffer queue");
inputBufferSize_ = 0;
isSyncMode_.store(false);
return ret;
}
int32_t AVCodecAudioCodecImpl::Release()
{
AVCODEC_SYNC_TRACE;
AVCODEC_LOGI("Instances:0x%{public}06" PRIXPTR " Release", FAKE_POINTER(this));
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_STATE, "service died");
Stop();
int32_t ret = codecService_->Release();
inputBufferSize_ = 0;
return ret;
}
int32_t AVCodecAudioCodecImpl::QueueInputBuffer(uint32_t index)
{
AVCODEC_SYNC_TRACE;
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_STATE, "service died");
CHECK_AND_RETURN_RET_LOG(mediaCodecProducer_ != nullptr, AVCS_ERR_INVALID_STATE,
"mediaCodecProducer_ is nullptr");
CHECK_AND_RETURN_RET_LOG(codecService_->CheckRunning(), AVCS_ERR_INVALID_STATE, "CheckRunning is not running");
std::shared_ptr<AVBuffer> buffer;
{
std::unique_lock lock(inputMutex_);
auto it = inputBufferObjMap_.find(index);
if (it == inputBufferObjMap_.end()) {
AVCODEC_LOGE("Index:%{public}d does not exist", index);
return AVCS_ERR_INVALID_VAL;
}
buffer = it->second;
inputBufferObjMap_.erase(index);
}
CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AVCS_ERR_INVALID_STATE, "buffer not found");
if (!(buffer->flag_ & AVCODEC_BUFFER_FLAG_EOS) && buffer->GetConfig().size <= 0) {
AVCODEC_LOGE("buffer size is 0,please fill audio buffer in");
return AVCS_ERR_UNKNOWN;
}
{
std::unique_lock lock(outputMutex_2);
inputIndexQueue.emplace(buffer);
}
outputCondition_.notify_one();
return AVCS_ERR_OK;
}
#ifdef SUPPORT_DRM
int32_t AVCodecAudioCodecImpl::SetAudioDecryptionConfig(const sptr<DrmStandard::IMediaKeySessionService> &keySession,
const bool svpFlag)
{
AVCODEC_SYNC_TRACE;
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_STATE, "service died");
return codecService_->SetAudioDecryptionConfig(keySession, svpFlag);
}
#else
int32_t AVCodecAudioCodecImpl::SetAudioDecryptionConfig(const sptr<DrmStandard::IMediaKeySessionService> &keySession,
const bool svpFlag)
{
(void)keySession;
(void)svpFlag;
return 0;
}
#endif
int32_t AVCodecAudioCodecImpl::GetOutputFormat(Format &format)
{
AVCODEC_SYNC_TRACE;
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_STATE, "service died");
std::shared_ptr<Media::Meta> parameter = std::make_shared<Media::Meta>();
int32_t ret = codecService_->GetOutputFormat(parameter);
CHECK_AND_RETURN_RET_LOG(ret == 0, ret, "GetOutputFormat fail, ret:%{public}d", ret);
format.SetMeta(parameter);
return ret;
}
int32_t AVCodecAudioCodecImpl::ReleaseOutputBuffer(uint32_t index)
{
AVCODEC_SYNC_TRACE;
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_STATE, "service died");
std::shared_ptr<AVBuffer> buffer;
{
std::unique_lock lock(outputMutex_);
auto it = outputBufferObjMap_.find(index);
CHECK_AND_RETURN_RET_LOG(it != outputBufferObjMap_.end(), AVCS_ERR_INVALID_VAL,
"Index does not exist");
buffer = it->second;
outputBufferObjMap_.erase(index);
}
CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AVCS_ERR_INVALID_STATE, "buffer is nullptr");
if (buffer->flag_ == AVCODEC_BUFFER_FLAG_EOS) {
AVCODEC_LOGI("EOS detected, QueueInputBuffer set eos status.");
codecService_->NotifyEos();
}
Media::Status ret = implConsumer_->ReleaseBuffer(buffer);
return StatusToAVCodecServiceErrCode(ret);
}
int32_t AVCodecAudioCodecImpl::SetParameter(const Format &format)
{
AVCODEC_SYNC_TRACE;
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_STATE, "service died");
auto meta = const_cast<Format &>(format).GetMeta();
inputBufferSize_ = 0;
return codecService_->SetParameter(meta);
}
int32_t AVCodecAudioCodecImpl::SetCallback(const std::shared_ptr<MediaCodecCallback> &callback)
{
AVCODEC_SYNC_TRACE;
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_STATE, "service died");
CHECK_AND_RETURN_RET_LOG(callback != nullptr, AVCS_ERR_INVALID_VAL, "callback is nullptr");
callback_ = callback;
std::shared_ptr<AVCodecInnerCallback> innerCallback = std::make_shared<AVCodecInnerCallback>(this);
return codecService_->SetCallback(innerCallback);
}
void AVCodecAudioCodecImpl::Notify()
{
bufferConsumerAvailableCount_++;
inputCondition_.notify_one();
outputCondition_.notify_one();
}
int32_t AVCodecAudioCodecImpl::GetInputBufferSize()
{
if (inputBufferSize_ > 0) {
return inputBufferSize_;
}
int32_t capacity = 0;
CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, capacity, "codecService_ is nullptr");
std::shared_ptr<Media::Meta> bufferConfig = std::make_shared<Media::Meta>();
CHECK_AND_RETURN_RET_LOG(bufferConfig != nullptr, capacity, "bufferConfig is nullptr");
int32_t ret = codecService_->GetOutputFormat(bufferConfig);
CHECK_AND_RETURN_RET_LOG(ret == 0, capacity, "GetOutputFormat fail");
CHECK_AND_RETURN_RET_LOG(bufferConfig->Get<Media::Tag::AUDIO_MAX_INPUT_SIZE>(capacity), capacity,
"get max input buffer size fail");
inputBufferSize_ = capacity;
return capacity;
}
void AVCodecAudioCodecImpl::ProduceInputBuffer()
{
AVCODEC_SYNC_TRACE;
if (indexInput_ == 0) {
auto ret = SetThreadQos(OHOS::QOS::QosLevel::QOS_USER_INTERACTIVE);
AVCODEC_LOGD("set OS_ACodecIn thread qos, ret = %{public}d", ret);
}
AVCODEC_LOGD_LIMIT(LOGD_FREQUENCY, "produceInputBuffer enter");
if (!isRunning_) {
usleep(DEFAULT_TRY_DECODE_TIME);
AVCODEC_LOGE("ProduceInputBuffer isRunning_ false");
return;
}
Media::Status ret = Media::Status::OK;
Media::AVBufferConfig avBufferConfig;
avBufferConfig.size = GetInputBufferSize();
std::unique_lock lock2(inputMutex2_);
while (isRunning_) {
std::shared_ptr<AVBuffer> emptyBuffer = nullptr;
CHECK_AND_CONTINUE_LOG(mediaCodecProducer_ != nullptr, "mediaCodecProducer_ is nullptr");
ret = mediaCodecProducer_->RequestBuffer(emptyBuffer, avBufferConfig, TIME_OUT_MS);
if (ret != Media::Status::OK) {
AVCODEC_LOGD_LIMIT(LOGD_FREQUENCY, "produceInputBuffer RequestBuffer fail, ret=%{public}d", ret);
break;
}
CHECK_AND_CONTINUE_LOG(emptyBuffer != nullptr, "buffer is nullptr");
{
std::unique_lock lock1(inputMutex_);
inputBufferObjMap_[indexInput_] = emptyBuffer;
}
CHECK_AND_CONTINUE_LOG(callback_ != nullptr, "callback is nullptr");
callback_->OnInputBufferAvailable(indexInput_, emptyBuffer);
indexInput_ = (indexInput_ >= MAX_INDEX) ? 0 : ++indexInput_;
}
if (!isRunning_) {
AVCODEC_LOGI("ProduceInputBuffer exit");
return;
}
inputCondition_.wait_for(lock2, std::chrono::milliseconds(MILLISECONDS),
[this] { return ((mediaCodecProducer_->GetQueueSize() > 0) || !isRunning_); });
AVCODEC_LOGD_LIMIT(LOGD_FREQUENCY, "produceInputBuffer exit");
}
void AVCodecAudioCodecImpl::ConsumerOutputBuffer()
{
AVCODEC_SYNC_TRACE;
if (indexOutput_ == 0) {
auto ret = SetThreadQos(OHOS::QOS::QosLevel::QOS_USER_INTERACTIVE);
AVCODEC_LOGD("set OS_ACodecOut thread qos, ret = %{public}d", ret);
}
AVCODEC_LOGD_LIMIT(LOGD_FREQUENCY, "ConsumerOutputBuffer enter");
if (!isRunning_) {
usleep(DEFAULT_TRY_DECODE_TIME);
AVCODEC_LOGE("Consumer isRunning_ false");
return;
}
while (isRunning_) {
std::unique_lock lock2(outputMutex_2);
if (inputIndexQueue.empty()) {
break;
}
std::shared_ptr<AVBuffer> buffer;
buffer = inputIndexQueue.front();
inputIndexQueue.pop();
lock2.unlock();
Media::Status ret = mediaCodecProducer_->PushBuffer(buffer, true);
if (ret != Media::Status::OK) {
AVCODEC_LOGW("ConsumerOutputBuffer PushBuffer fail, ret=%{public}d", ret);
break;
}
inputCondition_.notify_all();
}
if (!isRunning_) {
AVCODEC_LOGI("ConsumerOutputBuffer exit");
return;
}
std::unique_lock lock2(outputMutex_2);
outputCondition_.wait_for(lock2, std::chrono::milliseconds(MILLISECONDS),
[this] { return ((!inputIndexQueue.empty()) || !isRunning_); });
AVCODEC_LOGD_LIMIT(LOGD_FREQUENCY, "ConsumerOutputBuffer exit");
}
void AVCodecAudioCodecImpl::ClearCache()
{
std::unique_lock lock(outputMutex_);
for (auto iter = outputBufferObjMap_.begin(); iter != outputBufferObjMap_.end();) {
std::shared_ptr<AVBuffer> buffer;
buffer = iter->second;
iter = outputBufferObjMap_.erase(iter);
implConsumer_->ReleaseBuffer(buffer);
}
}
void AVCodecAudioCodecImpl::ReturnInputBuffer()
{
{
std::unique_lock lock(inputMutex_);
for (const auto &inputMap : inputBufferObjMap_) {
mediaCodecProducer_->PushBuffer(inputMap.second, false);
}
inputBufferObjMap_.clear();
}
std::unique_lock lock(outputMutex_2);
while (!inputIndexQueue.empty()) {
std::shared_ptr<AVBuffer> buffer;
buffer = inputIndexQueue.front();
inputIndexQueue.pop();
lock.unlock();
mediaCodecProducer_->PushBuffer(buffer, false);
lock.lock();
}
}
void AVCodecAudioCodecImpl::ClearInputBuffer()
{
{
std::unique_lock lock(inputMutex_);
inputBufferObjMap_.clear();
}
std::unique_lock lock(outputMutex_2);
while (!inputIndexQueue.empty()) {
inputIndexQueue.pop();
}
}
void AVCodecAudioCodecImpl::StopTaskAsync()
{
isRunning_ = false;
ClearCache();
ReturnInputBuffer();
{
std::lock_guard lock(inputMutex2_);
inputCondition_.notify_one();
}
{
std::lock_guard lock(outputMutex_2);
outputCondition_.notify_one();
}
if (inputTask_) {
inputTask_->StopAsync();
}
if (outputTask_) {
outputTask_->StopAsync();
}
}
void AVCodecAudioCodecImpl::PauseTaskAsync()
{
isRunning_ = false;
ClearCache();
ReturnInputBuffer();
{
std::lock_guard lock(inputMutex2_);
inputCondition_.notify_one();
}
{
std::lock_guard lock(outputMutex_2);
outputCondition_.notify_one();
}
if (inputTask_) {
inputTask_->PauseAsync();
}
if (outputTask_) {
outputTask_->PauseAsync();
}
}
void AVCodecAudioCodecImpl::StopTask()
{
if (inputTask_) {
inputTask_->Stop();
}
if (outputTask_) {
outputTask_->Stop();
}
}
void AVCodecAudioCodecImpl::PauseTask()
{
if (inputTask_) {
inputTask_->Pause();
}
if (outputTask_) {
outputTask_->Pause();
}
}
int32_t AVCodecAudioCodecImpl::QueryInputBuffer(uint32_t *index, int64_t timeoutUs)
{
if (index == nullptr) {
AVCODEC_LOGE("input nullptr index");
return AVCS_ERR_INVALID_VAL;
}
if (!isRunning_.load()) {
AVCODEC_LOGE("not start");
return AVCS_ERR_INVALID_STATE;
}
if (!isSyncMode_.load()) {
AVCODEC_LOGE("not in sync mode");
return AVCS_ERR_INVALID_OPERATION;
}
AVCODEC_SYNC_TRACE;
Media::AVBufferConfig avBufferConfig;
avBufferConfig.size = GetInputBufferSize();
std::unique_lock lock2(inputMutex2_);
CHECK_AND_RETURN_RET_LOG(mediaCodecProducer_ != nullptr, AVCS_ERR_INVALID_VAL, "mediaCodecProducer_ is nullptr");
std::shared_ptr<AVBuffer> emptyBuffer = nullptr;
Status ret = mediaCodecProducer_->RequestBufferWaitUs(emptyBuffer, avBufferConfig, timeoutUs);
if (ret == Media::Status::ERROR_WAIT_TIMEOUT) {
AVCODEC_LOGW("produceInputBuffer RequestBuffer wait:%{public}" PRId64 " us timeout", timeoutUs);
return AVCS_ERR_TRY_AGAIN;
} else if (ret != Media::Status::OK) {
AVCODEC_LOGE("produceInputBuffer RequestBuffer fail, ret=%{public}d", ret);
return AVCS_ERR_INVALID_VAL;
}
if (emptyBuffer == nullptr) {
AVCODEC_LOGE("buffer is nullptr");
return AVCS_ERR_INVALID_VAL;
}
std::unique_lock lock1(inputMutex_);
inputBufferObjMap_[indexInput_] = emptyBuffer;
*index = indexInput_;
AVCODEC_LOGD("new input buffer index:%{public}d", *index);
indexInput_ = (indexInput_ >= MAX_INDEX) ? 0 : ++indexInput_;
return AVCS_ERR_OK;
}
std::shared_ptr<AVBuffer> AVCodecAudioCodecImpl::GetInputBuffer(uint32_t index)
{
if (!isSyncMode_.load() || !isRunning_.load()) {
AVCODEC_LOGE("not start or not in sync mode, %{public}d, %{public}d", isSyncMode_.load(), isRunning_.load());
return nullptr;
}
AVCODEC_SYNC_TRACE;
std::unique_lock lock(inputMutex_);
std::shared_ptr<AVBuffer> buffer;
auto it = inputBufferObjMap_.find(index);
if (it == inputBufferObjMap_.end()) {
AVCODEC_LOGE("Index:%{public}d does not exist", index);
return nullptr;
}
buffer = it->second;
CHECK_AND_RETURN_RET_LOG(buffer != nullptr, nullptr, "buffer not found");
return buffer;
}
int32_t AVCodecAudioCodecImpl::QueryOutputBuffer(uint32_t *index, int64_t timeoutUs)
{
if (index == nullptr) {
AVCODEC_LOGE("input nullptr index");
return AVCS_ERR_INVALID_VAL;
}
if (!isRunning_.load()) {
AVCODEC_LOGE("not start");
return AVCS_ERR_INVALID_STATE;
}
if (!isSyncMode_.load()) {
AVCODEC_LOGE("not in sync mode");
return AVCS_ERR_INVALID_OPERATION;
}
AVCODEC_SYNC_TRACE;
std::unique_lock lock(syncOutputMutex_);
if (syncOutputQueue_.empty() && timeoutUs != 0) {
if (timeoutUs < 0) {
syncOutCond_.wait(lock, [this] { return !syncOutputQueue_.empty(); });
} else {
auto timeout = std::chrono::microseconds(timeoutUs);
syncOutCond_.wait_for(lock, timeout, [this] { return !syncOutputQueue_.empty(); });
}
}
if (syncOutputQueue_.empty()) {
AVCODEC_LOGW("output RequestBuffer wait:%{public}" PRId64 " us timeout", timeoutUs);
return AVCS_ERR_TRY_AGAIN;
}
std::shared_ptr<OutputInfo> out = syncOutputQueue_.front();
syncOutputQueue_.pop();
if (out->type_ == OUTPUT_STREAM_CHANGED) {
return AVCS_ERR_STREAM_CHANGED;
}
std::lock_guard mapLock(outputMutex_);
*index = indexOutput_;
outputBufferObjMap_[indexOutput_] = out->buffer_;
indexOutput_ = (indexOutput_ >= MAX_INDEX) ? 0 : ++indexOutput_;
return AVCS_ERR_OK;
}
std::shared_ptr<AVBuffer> AVCodecAudioCodecImpl::GetOutputBuffer(uint32_t index)
{
if (!isSyncMode_.load() || !isRunning_.load()) {
AVCODEC_LOGE("not start or not in sync mode, %{public}d, %{public}d", isSyncMode_.load(), isRunning_.load());
return nullptr;
}
AVCODEC_SYNC_TRACE;
std::lock_guard mapLock(outputMutex_);
if (outputBufferObjMap_.find(index) == outputBufferObjMap_.end()) {
AVCODEC_LOGE("not find output buffer index:%{public}d", index);
return nullptr;
}
return outputBufferObjMap_[index];
}
AVCodecAudioCodecImpl::AVCodecInnerCallback::AVCodecInnerCallback(AVCodecAudioCodecImpl *impl) : impl_(impl) {}
void AVCodecAudioCodecImpl::AVCodecInnerCallback::OnError(AVCodecErrorType errorType, int32_t errorCode)
{
if (impl_->callback_) {
impl_->callback_->OnError(errorType, errorCode);
}
}
void AVCodecAudioCodecImpl::AVCodecInnerCallback::OnOutputFormatChanged(const Format &format)
{
if (!impl_->isSyncMode_.load()) {
if (impl_->callback_) {
impl_->callback_->OnOutputFormatChanged(format);
} else {
AVCODEC_LOGE("receive format changed, but impl callback is nullptr");
}
return;
}
AVCODEC_SYNC_TRACE;
std::lock_guard lock(impl_->syncOutputMutex_);
std::shared_ptr<OutputInfo> out = std::make_shared<OutputInfo>(format);
impl_->syncOutputQueue_.push(out);
impl_->syncOutCond_.notify_all();
}
void AVCodecAudioCodecImpl::AVCodecInnerCallback::OnInputBufferAvailable(uint32_t index,
std::shared_ptr<AVBuffer> buffer)
{
(void)index;
(void)buffer;
}
void AVCodecAudioCodecImpl::AVCodecInnerCallback::OnOutputBufferAvailable(uint32_t index,
std::shared_ptr<AVBuffer> buffer)
{
std::shared_ptr<AVBuffer> outputBuffer;
if (!impl_->isSyncMode_.load()) {
if (impl_->callback_) {
Media::Status ret = impl_->implConsumer_->AcquireBuffer(outputBuffer);
if (ret != Media::Status::OK) {
AVCODEC_LOGE("Consumer AcquireBuffer fail,ret=%{public}d", ret);
return;
}
{
std::unique_lock lock(impl_->outputMutex_);
impl_->outputBufferObjMap_[impl_->indexOutput_] = outputBuffer;
}
impl_->callback_->OnOutputBufferAvailable(impl_->indexOutput_, outputBuffer);
impl_->indexOutput_ = (impl_->indexOutput_ >= MAX_INDEX) ? 0 : ++impl_->indexOutput_;
}
return;
}
AVCODEC_SYNC_TRACE;
Media::Status ret = impl_->implConsumer_->AcquireBuffer(outputBuffer);
if (ret != Media::Status::OK) {
AVCODEC_LOGE("In sync mode Consumer AcquireBuffer fail,ret=%{public}d", ret);
return;
}
std::lock_guard lock(impl_->syncOutputMutex_);
std::shared_ptr<OutputInfo> out = std::make_shared<OutputInfo>(outputBuffer);
impl_->syncOutputQueue_.push(out);
impl_->syncOutCond_.notify_all();
}
}
}