Merge branch 'develop_test' of gitee.com:zjskpajs/av_codec into dev_av_muxer

Signed-off-by: cailei24 <cailei24@huawei.com>
This commit is contained in:
cailei24 2023-04-26 08:28:50 +00:00 committed by Gitee
commit cec62116c6
23 changed files with 1090 additions and 110 deletions

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/config/ohos/rules.gni")
import("//build/config/ohos/config.gni")
import("//build/ohos.gni")
group("av_codec_packages") {

View File

@ -10,7 +10,7 @@
"dirs": {},
"scripts": {},
"component": {
"name": "multimedia_av_codec",
"name": "av_codec",
"subsystem": "multimedia",
"syscap": [
"SystemCapability.Multimedia.Avcodec.Core",
@ -56,8 +56,8 @@
"//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client"
],
"service_group": [
"//foundation/multimedia/av_codec/services:av_codec_services_package",
"//foundation/multimedia/av_codec/sa_profile:av_codec_service_sa_profile"
"//foundation/multimedia/av_codec/services:av_codec_services_package",
"//foundation/multimedia/av_codec/sa_profile:av_codec_service_profile"
]
},
"inner_kits": [

View File

@ -240,5 +240,5 @@ ohos_shared_library("av_codec_client") {
]
subsystem_name = "multimedia"
part_name = "multimedia_av_codec"
part_name = "av_codec"
}

View File

@ -163,7 +163,7 @@ ohos_shared_library("native_av_codec_core") {
]
output_extension = "so"
subsystem_name = "multimedia"
part_name = "multimedia_av_codec"
part_name = "av_codec"
}
ohos_shared_library("native_av_codec_codec") {
@ -200,7 +200,7 @@ ohos_shared_library("native_av_codec_codec") {
]
output_extension = "so"
subsystem_name = "multimedia"
part_name = "multimedia_av_codec"
part_name = "av_codec"
}
ohos_shared_library("native_av_codec_avmuxer") {
@ -225,5 +225,5 @@ ohos_shared_library("native_av_codec_avmuxer") {
]
output_extension = "so"
subsystem_name = "multimedia"
part_name = "multimedia_av_codec"
part_name = "av_codec"
}

View File

@ -13,8 +13,7 @@
import("//build/ohos/sa_profile/sa_profile.gni")
ohos_sa_profile("av_codec_service_sa_profile") {
ohos_sa_profile("av_codec_service_profile") {
sources = [ "3011.xml" ]
part_name = "multimedia_av_codec"
part_name = "av_codec"
}

View File

@ -77,5 +77,5 @@ ohos_shared_library("av_codec_service_dfx") {
]
subsystem_name = "multimedia"
part_name = "multimedia_av_codec"
part_name = "av_codec"
}

View File

@ -68,5 +68,5 @@ ohos_static_library("av_codec_engine_avcodeclist") {
]
subsystem_name = "multimedia"
part_name = "multimedia_av_codec"
part_name = "av_codec"
}

View File

@ -55,5 +55,20 @@ int32_t CodecBase::SignalRequestIDRFrame()
return 0;
}
std::shared_ptr<CodecBase> CodecBase::Create(const std::string& name)
{
AVCODEC_LOGW("Create is not supported");
(void)name;
return nullptr;
}
std::shared_ptr<CodecBase> CodecBase::Create(bool isEncoder, const std::string& mime)
{
AVCODEC_LOGW("Create is not supported");
(void)isEncoder;
(void)mime;
return nullptr;
}
} // namespace Media
} // namespace OHOS

View File

@ -1,4 +1,4 @@
# Copyright (C) 2021 Huawei Device Co., Ltd.
# Copyright (c) 2022 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
@ -16,6 +16,6 @@ import("//build/ohos.gni")
ohos_prebuilt_etc("av_codec_service.cfg") {
source = "av_codec_service.cfg"
relative_install_dir = "init"
part_name = "multimedia_av_codec"
part_name = "av_codec"
subsystem_name = "multimedia"
}

View File

@ -1,10 +1,10 @@
{
"services" : [{
"name" : "av_codec_service",
"path" : ["/system/bin/sa_main", "/system/profile/av_codec_service.xml"],
"ondemand" : true,
"uid" : "system",
"gid" : ["system", "shell"]
"name" : "av_codec_service",
"path" : ["/system/bin/sa_main", "/system/profile/av_codec_service.xml"],
"uid" : "media",
"gid" : ["av_codec_rw", "system"],
"secon" : "u:r:media_service:s0"
}
]
}

View File

@ -215,5 +215,5 @@ ohos_shared_library("av_codec_service") {
]
subsystem_name = "multimedia"
part_name = "multimedia_av_codec"
part_name = "av_codec"
}

View File

@ -285,7 +285,6 @@ int32_t CodecServer::SetParameter(const Format &format)
int32_t CodecServer::SetCallback(const std::shared_ptr<AVCodecCallback> &callback)
{
std::lock_guard<std::mutex> lock(mutex_);
CHECK_AND_RETURN_RET_LOG(status_ == INITIALIZED, AVCS_ERR_INVALID_OPERATION, "invalid state");
{
std::lock_guard<std::mutex> cbLock(cbMutex_);
codecCb_ = callback;
@ -294,8 +293,6 @@ int32_t CodecServer::SetCallback(const std::shared_ptr<AVCodecCallback> &callbac
return AVCS_ERR_OK;
}
int32_t CodecServer::DumpInfo(int32_t fd)
{
std::string dumpString;

View File

@ -35,7 +35,7 @@ ohos_static_library("av_codec_format") {
]
subsystem_name = "multimedia"
part_name = "multimedia_av_codec"
part_name = "av_codec"
}
ohos_shared_library("av_codec_service_utils") {
@ -93,5 +93,5 @@ include_dirs = [
]
subsystem_name = "multimedia"
part_name = "multimedia_av_codec"
part_name = "av_codec"
}

View File

@ -31,4 +31,4 @@ group("av_codec_unit_test") {
"unittest:format_unit_test",
]
}
}
}

View File

@ -1,4 +1,4 @@
# Copyright (C) 2021 Huawei Device Co., Ltd.
# 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
@ -24,6 +24,9 @@ ohos_executable("av_codec_demo") {
"//foundation/multimedia/av_codec/services/engine/plugin/interface",
"//foundation/multimedia/av_codec/services/dfx/include",
"//foundation/multimedia/av_codec/services/utils/include",
"./av_codec_audio",
"./audio_demo",
"./include",
]
cflags = [
@ -59,6 +62,9 @@ ohos_executable("av_codec_demo") {
"//foundation/multimedia/av_codec/test/nativedemo/avmuxer/avmuxer_ffmpeg_demo.cpp",
"//foundation/multimedia/av_codec/test/nativedemo/avmuxer/avmuxer_demo_common.c",
"//foundation/multimedia/av_codec/test/nativedemo/avmuxer/native_avmuxer_demo.c",
"./audio_demo/avcodec_audio_encoder_inner_demo.cpp",
"./audio_demo/avcodec_audio_decoder_demo.cpp",
"./audio_demo/avcodec_audio_encoder_demo.cpp"
]
deps = [
@ -66,14 +72,16 @@ ohos_executable("av_codec_demo") {
"//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client",
"//foundation/multimedia/av_codec/services/services:av_codec_service",
"//foundation/multimedia/av_codec/services/utils:av_codec_format",
"//foundation/multimedia/av_codec/interfaces/kits/c:capi_packages"
]
external_deps = [
"c_utils:utils",
"hiviewdfx_hilog_native:libhilog",
"ipc:ipc_core",
]
install_enable = false
part_name = "multimedia_av_codec"
part_name = "av_codec"
subsystem_name = "multimedia"
}
}

View File

@ -0,0 +1,234 @@
/*
* 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_decoder_demo.h"
#include "avcodec_errors.h"
#include "avcodec_common.h"
#include "demo_log.h"
#include "securec.h"
#include <iostream>
#include <unistd.h>
using namespace OHOS;
using namespace OHOS::Media;
using namespace OHOS::Media::AudioDemo;
using namespace std;
namespace {
constexpr uint32_t CHANNEL_COUNT = 2;
constexpr uint32_t SAMPLE_RATE = 44100;
constexpr uint32_t BITS_RATE = 169000;
constexpr uint32_t BITS_PER_CODED_RATE = 4;
constexpr uint32_t FRAME_DURATION_US = 33000;
constexpr uint32_t DEFAULT_FRAME_COUNT = 1;
} // namespace
static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) {
cout << "Error received, errorCode:" << errorCode << endl;
}
static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) {
cout << "OnOutputFormatChanged received" << endl;
}
static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData) {
ADecSignal *signal_ = static_cast<ADecSignal *>(userData);
cout << "OnInputBufferAvailable received, index:" << index << endl;
unique_lock<mutex> lock(signal_->inMutex_);
signal_->inQueue_.push(index);
signal_->inBufferQueue_.push(data);
signal_->inCond_.notify_all();
}
static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
void *userData) {
ADecSignal *signal_ = static_cast<ADecSignal *>(userData);
cout << "OnOutputBufferAvailable received, index:" << index << endl;
unique_lock<mutex> lock(signal_->outMutex_);
signal_->outQueue_.push(index);
signal_->outBufferQueue_.push(data);
signal_->attrQueue_.push(attr);
signal_->outCond_.notify_all();
}
void ADecDemo::RunCase() {
DEMO_CHECK_AND_RETURN_LOG(CreateDec() == AVCS_ERR_OK, "Fatal: CreateDec fail");
OH_AVFormat *format = OH_AVFormat_Create();
OH_AVFormat_SetIntValue(format, "channel-count", CHANNEL_COUNT);
OH_AVFormat_SetIntValue(format, "sample-rate", SAMPLE_RATE);
OH_AVFormat_SetIntValue(format, "bits_per_coded-rate", BITS_PER_CODED_RATE);
OH_AVFormat_SetLongValue(format, "bits-rate", BITS_RATE);
DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail");
DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail");
sleep(3); // start run 3s
DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail");
DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail");
}
ADecDemo::~ADecDemo() {
OH_AudioDecoder_Destroy(audioDec_);
if (signal_) {
delete signal_;
signal_ = nullptr;
}
}
int32_t ADecDemo::CreateDec() {
audioDec_ = OH_AudioDecoder_CreateByName("OH.Media.Codec.MP3.FFMPEGMp3");
DEMO_CHECK_AND_RETURN_RET_LOG(audioDec_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail");
signal_ = new ADecSignal();
DEMO_CHECK_AND_RETURN_RET_LOG(signal_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable};
int32_t ret = OH_AudioDecoder_SetCallback(audioDec_, cb_, signal_);
DEMO_CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, "Fatal: SetCallback fail");
return AVCS_ERR_OK;
}
int32_t ADecDemo::Configure(OH_AVFormat *format) {
return OH_AudioDecoder_Configure(audioDec_, format);
}
int32_t ADecDemo::Start() {
isRunning_.store(true);
testFile_ = std::make_unique<std::ifstream>();
DEMO_CHECK_AND_RETURN_RET_LOG(testFile_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
testFile_->open("/data/media/audio.mp3", std::ios::in | std::ios::binary);
inputLoop_ = make_unique<thread>(&ADecDemo::InputFunc, this);
DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
outputLoop_ = make_unique<thread>(&ADecDemo::OutputFunc, this);
DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
return OH_AudioDecoder_Start(audioDec_);
}
int32_t ADecDemo::Stop() {
isRunning_.store(false);
if (inputLoop_ != nullptr && inputLoop_->joinable()) {
unique_lock<mutex> lock(signal_->inMutex_);
signal_->inCond_.notify_all();
lock.unlock();
inputLoop_->join();
inputLoop_.reset();
}
if (outputLoop_ != nullptr && outputLoop_->joinable()) {
unique_lock<mutex> lock(signal_->outMutex_);
signal_->outCond_.notify_all();
lock.unlock();
outputLoop_->join();
outputLoop_.reset();
}
return OH_AudioDecoder_Stop(audioDec_);
}
int32_t ADecDemo::Flush() {
return OH_AudioDecoder_Flush(audioDec_);
}
int32_t ADecDemo::Reset() {
return OH_AudioDecoder_Reset(audioDec_);
}
int32_t ADecDemo::Release() {
return OH_AudioDecoder_Destroy(audioDec_);
}
void ADecDemo::InputFunc() {
while (true) {
if (!isRunning_.load()) {
break;
}
unique_lock<mutex> lock(signal_->inMutex_);
signal_->inCond_.wait(lock, [this]() { return signal_->inQueue_.size() > 0; });
if (!isRunning_.load()) {
break;
}
uint32_t index = signal_->inQueue_.front();
auto buffer = signal_->inBufferQueue_.front();
DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
DEMO_CHECK_AND_BREAK_LOG(testFile_ != nullptr && testFile_->is_open(), "Fatal: open file fail");
constexpr uint32_t bufferSize = 0;
(void)testFile_->read((char *)OH_AVMemory_GetAddr(buffer), bufferSize);
OH_AVCodecBufferAttr info;
info.size = bufferSize;
info.offset = 0;
// info.presentationTimeUs = timeStamp_;
int32_t ret = AVCS_ERR_OK;
if (isFirstFrame_) {
info.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
ret = OH_AudioDecoder_PushInputData(audioDec_, index, info);
isFirstFrame_ = false;
} else {
info.flags = AVCODEC_BUFFER_FLAGS_NONE;
ret = OH_AudioDecoder_PushInputData(audioDec_, index, info);
}
// free(fileBuffer);
timeStamp_ += FRAME_DURATION_US;
signal_->inQueue_.pop();
signal_->inBufferQueue_.pop();
frameCount_++;
if (frameCount_ == DEFAULT_FRAME_COUNT) {
cout << "Finish decode, exit" << endl;
break;
}
if (ret != AVCS_ERR_OK) {
cout << "Fatal error, exit" << endl;
break;
}
}
}
void ADecDemo::OutputFunc() {
while (true) {
if (!isRunning_.load()) {
break;
}
unique_lock<mutex> lock(signal_->outMutex_);
signal_->outCond_.wait(lock, [this]() { return signal_->outQueue_.size() > 0; });
if (!isRunning_.load()) {
break;
}
uint32_t index = signal_->outQueue_.front();
if (OH_AudioDecoder_FreeOutputData(audioDec_, index) != AV_ERR_OK) {
cout << "Fatal: ReleaseOutputBuffer fail" << endl;
break;
}
signal_->outBufferQueue_.pop();
signal_->attrQueue_.pop();
signal_->outQueue_.pop();
}
}

View File

@ -0,0 +1,74 @@
/*
* 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.
*/
#ifndef AVCODEC_AUDIO_DECODER_DEMO_H
#define AVCODEC_AUDIO_DECODER_DEMO_H
#include "native_avcodec_audiodecoder.h"
#include <atomic>
#include <fstream>
#include <queue>
#include <string>
#include <thread>
#include "nocopyable.h"
namespace OHOS {
namespace Media {
namespace AudioDemo {
class ADecSignal {
public:
std::mutex inMutex_;
std::mutex outMutex_;
std::condition_variable inCond_;
std::condition_variable outCond_;
std::queue<uint32_t> inQueue_;
std::queue<uint32_t> outQueue_;
std::queue<OH_AVMemory *> inBufferQueue_;
std::queue<OH_AVMemory *> outBufferQueue_;
std::queue<OH_AVCodecBufferAttr *> attrQueue_;
};
class ADecDemo : public NoCopyable {
public:
ADecDemo() = default;
virtual ~ADecDemo();
void RunCase();
private:
int32_t CreateDec();
int32_t Configure(OH_AVFormat *format);
int32_t Start();
int32_t Stop();
int32_t Flush();
int32_t Reset();
int32_t Release();
void InputFunc();
void OutputFunc();
std::atomic<bool> isRunning_ = false;
std::unique_ptr<std::ifstream> testFile_;
std::unique_ptr<std::thread> inputLoop_;
std::unique_ptr<std::thread> outputLoop_;
OH_AVCodec *audioDec_;
ADecSignal *signal_;
struct OH_AVCodecAsyncCallback cb_;
bool isFirstFrame_ = true;
int64_t timeStamp_ = 0;
uint32_t frameCount_ = 0;
};
} // AudioDemo
} // namespace AV_Codec
} // namespace OHOS
#endif // AVCODEC_AUDIO_DECODER_DEMO_H

View File

@ -0,0 +1,234 @@
/*
* 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_encoder_demo.h"
#include "avcodec_errors.h"
#include "avcodec_common.h"
#include "demo_log.h"
#include "securec.h"
#include <iostream>
#include <unistd.h>
using namespace OHOS;
using namespace OHOS::Media;
using namespace OHOS::Media::AudioDemo;
using namespace std;
namespace {
constexpr uint32_t CHANNEL_COUNT = 2;
constexpr uint32_t SAMPLE_RATE = 44100;
constexpr uint32_t BITS_RATE = 169000;
constexpr uint32_t BITS_PER_CODED_RATE = 4;
constexpr uint32_t FRAME_DURATION_US = 33000;
constexpr uint32_t DEFAULT_FRAME_COUNT = 1;
} // namespace
static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) {
cout << "Error received, errorCode:" << errorCode << endl;
}
static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) {
cout << "OnOutputFormatChanged received" << endl;
}
static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData) {
AEncSignal *signal_ = static_cast<AEncSignal *>(userData);
cout << "OnInputBufferAvailable received, index:" << index << endl;
unique_lock<mutex> lock(signal_->inMutex_);
signal_->inQueue_.push(index);
signal_->inBufferQueue_.push(data);
signal_->inCond_.notify_all();
}
static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
void *userData) {
AEncSignal *signal_ = static_cast<AEncSignal *>(userData);
cout << "OnOutputBufferAvailable received, index:" << index << endl;
unique_lock<mutex> lock(signal_->outMutex_);
signal_->outQueue_.push(index);
signal_->outBufferQueue_.push(data);
signal_->attrQueue_.push(attr);
signal_->outCond_.notify_all();
}
AEncDemo::~AEncDemo() {
OH_AudioEncoder_Destroy(audioEnc_);
if (signal_) {
delete signal_;
signal_ = nullptr;
}
}
void AEncDemo::RunCase() {
DEMO_CHECK_AND_RETURN_LOG(CreateDec() == AVCS_ERR_OK, "Fatal: CreateDec fail");
OH_AVFormat *format = OH_AVFormat_Create();
OH_AVFormat_SetIntValue(format, "channel-count", CHANNEL_COUNT);
OH_AVFormat_SetIntValue(format, "sample-rate", SAMPLE_RATE);
OH_AVFormat_SetIntValue(format, "bits_per_coded-rate", BITS_PER_CODED_RATE);
OH_AVFormat_SetLongValue(format, "bits-rate", BITS_RATE);
DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail");
DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail");
sleep(3); // start run 3s
DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail");
DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail");
}
int32_t AEncDemo::CreateDec() {
audioEnc_ = OH_AudioEncoder_CreateByName("OH.Media.Codec.MP3.FFMPEGMp3");
DEMO_CHECK_AND_RETURN_RET_LOG(audioEnc_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail");
signal_ = new AEncSignal();
DEMO_CHECK_AND_RETURN_RET_LOG(signal_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable};
int32_t ret = OH_AudioEncoder_SetCallback(audioEnc_, cb_, signal_);
DEMO_CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, "Fatal: SetCallback fail");
return AVCS_ERR_OK;
}
int32_t AEncDemo::Configure(OH_AVFormat *format) {
return OH_AudioEncoder_Configure(audioEnc_, format);
}
int32_t AEncDemo::Start() {
isRunning_.store(true);
testFile_ = std::make_unique<std::ifstream>();
DEMO_CHECK_AND_RETURN_RET_LOG(testFile_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
testFile_->open("/data/media/video.pcm", std::ios::in | std::ios::binary);
inputLoop_ = make_unique<thread>(&AEncDemo::InputFunc, this);
DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
outputLoop_ = make_unique<thread>(&AEncDemo::OutputFunc, this);
DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
return OH_AudioEncoder_Start(audioEnc_);
}
int32_t AEncDemo::Stop() {
isRunning_.store(false);
if (inputLoop_ != nullptr && inputLoop_->joinable()) {
unique_lock<mutex> lock(signal_->inMutex_);
signal_->inCond_.notify_all();
lock.unlock();
inputLoop_->join();
inputLoop_.reset();
}
if (outputLoop_ != nullptr && outputLoop_->joinable()) {
unique_lock<mutex> lock(signal_->outMutex_);
signal_->outCond_.notify_all();
lock.unlock();
outputLoop_->join();
outputLoop_.reset();
}
return OH_AudioEncoder_Stop(audioEnc_);
}
int32_t AEncDemo::Flush() {
return OH_AudioEncoder_Flush(audioEnc_);
}
int32_t AEncDemo::Reset() {
return OH_AudioEncoder_Reset(audioEnc_);
}
int32_t AEncDemo::Release() {
return OH_AudioEncoder_Destroy(audioEnc_);
}
void AEncDemo::InputFunc() {
while (true) {
if (!isRunning_.load()) {
break;
}
unique_lock<mutex> lock(signal_->inMutex_);
signal_->inCond_.wait(lock, [this]() { return signal_->inQueue_.size() > 0; });
if (!isRunning_.load()) {
break;
}
uint32_t index = signal_->inQueue_.front();
auto buffer = signal_->inBufferQueue_.front();
DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
DEMO_CHECK_AND_BREAK_LOG(testFile_ != nullptr && testFile_->is_open(), "Fatal: open file fail");
constexpr uint32_t bufferSize = 0;
(void)testFile_->read((char *)OH_AVMemory_GetAddr(buffer), bufferSize);
OH_AVCodecBufferAttr info;
info.size = bufferSize;
info.offset = 0;
// info.presentationTimeUs = timeStamp_;
int32_t ret = AVCS_ERR_OK;
if (isFirstFrame_) {
info.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
ret = OH_AudioEncoder_PushInputData(audioEnc_, index, info);
isFirstFrame_ = false;
} else {
info.flags = AVCODEC_BUFFER_FLAGS_NONE;
ret = OH_AudioEncoder_PushInputData(audioEnc_, index, info);
}
// free(fileBuffer);
timeStamp_ += FRAME_DURATION_US;
signal_->inQueue_.pop();
signal_->inBufferQueue_.pop();
frameCount_++;
if (frameCount_ == DEFAULT_FRAME_COUNT) {
cout << "Finish decode, exit" << endl;
break;
}
if (ret != AVCS_ERR_OK) {
cout << "Fatal error, exit" << endl;
break;
}
}
}
void AEncDemo::OutputFunc() {
while (true) {
if (!isRunning_.load()) {
break;
}
unique_lock<mutex> lock(signal_->outMutex_);
signal_->outCond_.wait(lock, [this]() { return signal_->outQueue_.size() > 0; });
if (!isRunning_.load()) {
break;
}
uint32_t index = signal_->outQueue_.front();
if (OH_AudioEncoder_FreeOutputData(audioEnc_, index) != AV_ERR_OK) {
cout << "Fatal: ReleaseOutputBuffer fail" << endl;
break;
}
signal_->outQueue_.pop();
signal_->outBufferQueue_.pop();
signal_->attrQueue_.pop();
}
}

View File

@ -0,0 +1,75 @@
/*
* 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.
*/
#ifndef AVCODEC_AUDIO_ENCODER_DEMO_H
#define AVCODEC_AUDIO_ENCODER_DEMO_H
#include "native_avcodec_audioencoder.h"
#include <atomic>
#include <condition_variable>
#include <fstream>
#include <queue>
#include <string>
#include <thread>
#include "nocopyable.h"
namespace OHOS {
namespace Media {
namespace AudioDemo {
class AEncSignal {
public:
std::mutex inMutex_;
std::mutex outMutex_;
std::condition_variable inCond_;
std::condition_variable outCond_;
std::queue<uint32_t> inQueue_;
std::queue<uint32_t> outQueue_;
std::queue<OH_AVMemory *> inBufferQueue_;
std::queue<OH_AVMemory *> outBufferQueue_;
std::queue<OH_AVCodecBufferAttr *> attrQueue_;
};
class AEncDemo : public NoCopyable {
public:
AEncDemo() = default;
virtual ~AEncDemo();
void RunCase();
private:
int32_t CreateDec();
int32_t Configure(OH_AVFormat *format);
int32_t Start();
int32_t Stop();
int32_t Flush();
int32_t Reset();
int32_t Release();
void InputFunc();
void OutputFunc();
std::atomic<bool> isRunning_ = false;
std::unique_ptr<std::ifstream> testFile_;
std::unique_ptr<std::thread> inputLoop_;
std::unique_ptr<std::thread> outputLoop_;
OH_AVCodec *audioEnc_;
AEncSignal *signal_;
struct OH_AVCodecAsyncCallback cb_;
bool isFirstFrame_ = true;
int64_t timeStamp_ = 0;
uint32_t frameCount_ = 0;
};
} // AudioDemo
} // namespace AV_Codec
} // namespace OHOS
#endif // AVCODEC_AUDIO_DECODER_DEMO_H

View File

@ -0,0 +1,246 @@
/*
* 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_encoder_inner_demo.h"
#include <iostream>
#include <unistd.h>
#include "securec.h"
#include "demo_log.h"
#include "avcodec_errors.h"
using namespace OHOS;
using namespace OHOS::Media;
using namespace OHOS::Media::InnerAudioDemo;
using namespace std;
namespace {
constexpr uint32_t CHANNEL_COUNT = 2;
constexpr uint32_t SAMPLE_RATE = 44100;
constexpr uint32_t BITS_RATE = 169000;
constexpr uint32_t BITS_PER_CODED_RATE = 4;
constexpr uint32_t FRAME_DURATION_US = 33000;
constexpr uint32_t DEFAULT_FRAME_COUNT = 1;
}
void ADecInnerDemo::RunCase()
{
DEMO_CHECK_AND_RETURN_LOG(CreateDec() == AVCS_ERR_OK, "Fatal: CreateDec fail");
Format format;
format.PutIntValue("channel-count", CHANNEL_COUNT);
format.PutIntValue("sample-rate", SAMPLE_RATE);
format.PutLongValue("bits-rate", BITS_RATE);
format.PutIntValue("bits_per_coded-rate", BITS_PER_CODED_RATE);
DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail");
DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail");
sleep(3); // start run 3s
DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail");
DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail");
}
int32_t ADecInnerDemo::CreateDec()
{
audioDec_ = AudioDecoderFactory::CreateByName("OH.Media.Codec.MP3.FFMPEGMp3");
DEMO_CHECK_AND_RETURN_RET_LOG(audioDec_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail");
signal_ = make_shared<ADecSignal>();
DEMO_CHECK_AND_RETURN_RET_LOG(signal_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
cb_ = make_unique<ADecDemoCallback>(signal_);
DEMO_CHECK_AND_RETURN_RET_LOG(cb_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
DEMO_CHECK_AND_RETURN_RET_LOG(audioDec_->SetCallback(cb_) == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, "Fatal: SetCallback fail");
return AVCS_ERR_OK;
}
int32_t ADecInnerDemo::Configure(const Format &format)
{
return audioDec_->Configure(format);
}
int32_t ADecInnerDemo::Start()
{
isRunning_.store(true);
testFile_ = std::make_unique<std::ifstream>();
DEMO_CHECK_AND_RETURN_RET_LOG(testFile_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
testFile_->open("/data/media/video.es", std::ios::in | std::ios::binary);
inputLoop_ = make_unique<thread>(&ADecInnerDemo::InputFunc, this);
DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
outputLoop_ = make_unique<thread>(&ADecInnerDemo::OutputFunc, this);
DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
return audioDec_->Start();
}
int32_t ADecInnerDemo::Stop()
{
isRunning_.store(false);
if (inputLoop_ != nullptr && inputLoop_->joinable()) {
unique_lock<mutex> lock(signal_->inMutex_);
signal_->inQueue_.push(0);
signal_->inCond_.notify_all();
lock.unlock();
inputLoop_->join();
inputLoop_.reset();
}
if (outputLoop_ != nullptr && outputLoop_->joinable()) {
unique_lock<mutex> lock(signal_->outMutex_);
signal_->outQueue_.push(0);
signal_->outCond_.notify_all();
lock.unlock();
outputLoop_->join();
outputLoop_.reset();
}
return audioDec_->Stop();
}
int32_t ADecInnerDemo::Flush()
{
return audioDec_->Flush();
}
int32_t ADecInnerDemo::Reset()
{
return audioDec_->Reset();
}
int32_t ADecInnerDemo::Release()
{
return audioDec_->Release();
}
void ADecInnerDemo::InputFunc()
{
while (true) {
if (!isRunning_.load()) {
break;
}
unique_lock<mutex> lock(signal_->inMutex_);
signal_->inCond_.wait(lock, [this](){ return signal_->inQueue_.size() > 0; });
if (!isRunning_.load()) {
break;
}
uint32_t index = signal_->inQueue_.front();
auto buffer = audioDec_->GetInputBuffer(index);
DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
DEMO_CHECK_AND_BREAK_LOG(testFile_ != nullptr && testFile_->is_open(), "Fatal: open file fail");
constexpr uint32_t bufferSize = 0; // replace with the actual size
char *fileBuffer = static_cast<char *>(malloc(sizeof(char) * bufferSize + 1));
DEMO_CHECK_AND_BREAK_LOG(fileBuffer != nullptr, "Fatal: malloc fail");
(void)testFile_->read(fileBuffer, bufferSize);
DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
if (memcpy_s(buffer->GetBase(), buffer->GetSize(), fileBuffer, bufferSize) != EOK) {
free(fileBuffer);
cout << "Fatal: memcpy fail" << endl;
break;
}
AVCodecBufferInfo info;
info.size = bufferSize;
info.offset = 0;
info.presentationTimeUs = timeStamp_;
int32_t ret = AVCS_ERR_OK;
if (isFirstFrame_) {
ret = audioDec_->QueueInputBuffer(index, info, AVCODEC_BUFFER_FLAG_CODEC_DATA);
isFirstFrame_ = false;
} else {
ret = audioDec_->QueueInputBuffer(index, info, AVCODEC_BUFFER_FLAG_NONE);
}
free(fileBuffer);
timeStamp_ += FRAME_DURATION_US;
signal_->inQueue_.pop();
frameCount_++;
if (frameCount_ == DEFAULT_FRAME_COUNT) {
cout << "Finish decode, exit" << endl;
break;
}
if (ret != AVCS_ERR_OK) {
cout << "Fatal error, exit" << endl;
break;
}
}
}
void ADecInnerDemo::OutputFunc()
{
while (true) {
if (!isRunning_.load()) {
break;
}
unique_lock<mutex> lock(signal_->outMutex_);
signal_->outCond_.wait(lock, [this](){ return signal_->outQueue_.size() > 0; });
if (!isRunning_.load()) {
break;
}
uint32_t index = signal_->outQueue_.front();
if (audioDec_->ReleaseOutputBuffer(index) != AVCS_ERR_OK) {
cout << "Fatal: ReleaseOutputBuffer fail" << endl;
break;
}
signal_->outQueue_.pop();
}
}
ADecDemoCallback::ADecDemoCallback(shared_ptr<ADecSignal> signal)
: signal_(signal)
{
}
void ADecDemoCallback::OnError(AVCodecErrorType errorType, int32_t errorCode)
{
cout << "Error received, errorType:" << errorType << " errorCode:" << errorCode << endl;
}
void ADecDemoCallback::OnOutputFormatChanged(const Format &format)
{
cout << "OnOutputFormatChanged received" << endl;
}
void ADecDemoCallback::OnInputBufferAvailable(uint32_t index)
{
cout << "OnInputBufferAvailable received, index:" << index << endl;
unique_lock<mutex> lock(signal_->inMutex_);
signal_->inQueue_.push(index);
signal_->inCond_.notify_all();
}
void ADecDemoCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag)
{
cout << "OnOutputBufferAvailable received, index:" << index << endl;
unique_lock<mutex> lock(signal_->outMutex_);
signal_->outQueue_.push(index);
signal_->outCond_.notify_all();
}

View File

@ -0,0 +1,86 @@
/*
* 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.
*/
#ifndef AVCODEC_AUDIO_ENCODER_INNER_DEMO_H
#define AVCODEC_AUDIO_ENCODER_INNER_DEMO_H
#include <atomic>
#include <fstream>
#include <thread>
#include <queue>
#include <string>
#include "avcodec_common.h"
#include "avcodec_audio_decoder.h"
#include "nocopyable.h"
namespace OHOS {
namespace Media {
namespace InnerAudioDemo {
class ADecSignal {
public:
std::mutex inMutex_;
std::mutex outMutex_;
std::condition_variable inCond_;
std::condition_variable outCond_;
std::queue<uint32_t> inQueue_;
std::queue<uint32_t> outQueue_;
};
class ADecDemoCallback : public AVCodecCallback, public NoCopyable {
public:
explicit ADecDemoCallback(std::shared_ptr<ADecSignal> signal);
virtual ~ADecDemoCallback() = default;
void OnError(AVCodecErrorType errorType, int32_t errorCode) override;
void OnOutputFormatChanged(const Format &format) override;
void OnInputBufferAvailable(uint32_t index) override;
void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override;
private:
std::shared_ptr<ADecSignal> signal_;
};
class ADecInnerDemo : public NoCopyable {
public:
ADecInnerDemo() = default;
virtual ~ADecInnerDemo() = default;
void RunCase();
private:
int32_t CreateDec();
int32_t Configure(const Format &format);
int32_t Start();
int32_t Stop();
int32_t Flush();
int32_t Reset();
int32_t Release();
void InputFunc();
void OutputFunc();
std::atomic<bool> isRunning_ = false;
std::unique_ptr<std::ifstream> testFile_;
std::unique_ptr<std::thread> inputLoop_;
std::unique_ptr<std::thread> outputLoop_;
std::shared_ptr<AVCodecAudioDecoder> audioDec_;
std::shared_ptr<ADecSignal> signal_;
std::shared_ptr<ADecDemoCallback> cb_;
bool isFirstFrame_ = true;
int64_t timeStamp_ = 0;
uint32_t frameCount_ = 0;
};
} // InnerAudioDemo
} // namespace AV_Codec
} // namespace OHOS
#endif // AVCODEC_AUDIO_ENCODER_INNER_DEMO_H

View File

@ -15,79 +15,61 @@
#include <climits>
#include <iostream>
#include <thread>
#include <vector>
#include "avmuxer_demo.h"
#include "avmuxer_ffmpeg_demo.h"
#include "avmuxer_engine_demo.h"
#include "avcodec_audio_encoder_inner_demo.h"
#include "avcodec_audio_decoder_demo.h"
#include "avcodec_audio_encoder_demo.h"
using namespace OHOS;
using namespace OHOS::Media;
using namespace OHOS::Media::Plugin;
using namespace OHOS::Media::AudioDemo;
using namespace OHOS::Media::InnerAudioDemo;
using namespace std;
constexpr int RUN_TIME = 600;
extern "C" {
extern int NativeSelectMode();
extern int RunNativeMuxer(const char *out);
}
static int RunLoopNativeMuxer(string out)
static int RunAudioDecoder()
{
time_t startTime = time(NULL);
time_t curTime = time(NULL);
while (difftime(curTime, startTime) < RUN_TIME) {
RunNativeMuxer(out.c_str());
time(&curTime);
auto audioEnc = std::make_unique<ADecDemo>();
if (audioEnc == nullptr) {
cout << "audio decoder is null" << endl;
return 0;
}
audioEnc->RunCase();
cout << "demo audio decoder end" << endl;
return 0;
}
static int RunAVMuxer()
static int RunAudioEncoder()
{
auto avmuxer = std::make_unique<AVMuxerDemo>();
if (avmuxer == nullptr) {
cout << "avmuxer is null" << endl;
auto audioEnc = std::make_unique<AEncDemo>();
if (audioEnc == nullptr) {
cout << "audio encoder is null" << endl;
return 0;
}
avmuxer->RunCase();
cout << "demo avmuxer end" << endl;
audioEnc->RunCase();
cout << "demo audio encoder end" << endl;
return 0;
}
static int RunAVMuxerWithMultithread()
static int RunAudioInnerDecoder()
{
auto avmuxer = std::make_unique<AVMuxerDemo>();
if (avmuxer == nullptr) {
cout << "avmuxer is null" << endl;
auto audioEnc = std::make_unique<ADecInnerDemo>();
if (audioEnc == nullptr) {
cout << "audio decoder is null" << endl;
return 0;
}
avmuxer->RunMultiThreadCase();
cout << "demo multi thread avmuxer end" << endl;
audioEnc->RunCase();
cout << "demo audio decoder end" << endl;
return 0;
}
static int RunFfmpegMuxer()
static int RunAudioInnerEncoder()
{
std::unique_ptr<AVMuxerDemoBase> ffmpegMuxer = std::make_unique<AVMuxerFFmpegDemo>();
if (ffmpegMuxer == nullptr) {
cout << "ffmpegMuxer is null" << endl;
auto audioEnc = std::make_unique<ADecInnerDemo>();
if (audioEnc == nullptr) {
cout << "audio encoder is null" << endl;
return 0;
}
ffmpegMuxer->RunCase();
cout << "demo ffmpegMuxer end" << endl;
return 0;
}
static int RunEngineMuxer()
{
std::unique_ptr<AVMuxerDemoBase> muxer = std::make_unique<AVMuxerEngineDemo>();
if (muxer == nullptr) {
cout << "AVMuxerEngineDemo is null" << endl;
return 0;
}
muxer->RunCase();
cout << "demo engine demo end" << endl;
audioEnc->RunCase();
cout << "demo audio encoder end" << endl;
return 0;
}
@ -98,44 +80,24 @@ int main(int argc, char *argv[])
if (argc >= minRequiredArgCount && argv[1] != nullptr) {
path = argv[1];
}
cout << "Please select muxer number(default native muxer): " << endl;
cout << "0:native_muxer" << endl;
cout << "1:native_muxer loop" << endl;
cout << "2:native_muxer multithread" << endl;
cout << "3:inner_muxer" << endl;
cout << "4:inner_muxer with multithread write" << endl;
cout << "5:ffmpeg_muxer" << endl;
cout << "6:engine_muxer" << endl;
cout << "Please select a demo scenario number(default Audio Decoder): " << endl;
cout << "0:Audio Decoder" << endl;
cout << "1:Audio Encoder" << endl;
cout << "2:Audio Inner Decoder" << endl;
cout << "3:Audio Inner Encoder" << endl;
string mode;
(void)getline(cin, mode);
if (mode == "" || mode == "0") {
NativeSelectMode();
RunNativeMuxer("native_mux");
(void)RunAudioDecoder();
} else if (mode == "1") {
NativeSelectMode();
RunLoopNativeMuxer("loop_native_mux");
(void)RunAudioEncoder();
} else if (mode == "2") {
NativeSelectMode();
vector<thread> vecThread;
for (int i = 0; i < 10; ++i) {
string out = to_string(i + 1);
out += "_native_mux";
vecThread.push_back(thread(RunLoopNativeMuxer, out));
}
for (int i = 0; i < 10; ++i) {
vecThread[i].join();
}
(void)RunAudioInnerDecoder();
} else if (mode == "3") {
RunAVMuxer();
} else if (mode == "4") {
RunAVMuxerWithMultithread();
} else if (mode == "5") {
RunFfmpegMuxer();
} else if (mode == "6") {
RunEngineMuxer();
} else {
(void)RunAudioInnerEncoder();
} else {
cout << "no that selection" << endl;
}
return 0;
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.
*/
#ifndef DEMO_LOG_H
#define DEMO_LOG_H
#include <cstdio>
namespace OHOS {
#define DEMO_CHECK_AND_RETURN_RET_LOG(cond, ret, fmt, ...) \
do { \
if (!(cond)) { \
(void)printf("%s\n", fmt, ##__VA_ARGS__); \
return ret; \
} \
} while (0)
#define DEMO_CHECK_AND_RETURN_LOG(cond, fmt, ...) \
do { \
if (!(cond)) { \
(void)printf("%s\n", fmt, ##__VA_ARGS__); \
return; \
} \
} while (0)
#define DEMO_CHECK_AND_BREAK_LOG(cond, fmt, ...) \
if (!(cond)) { \
(void)printf("%s\n", fmt, ##__VA_ARGS__); \
break; \
}
#define DEMO_CHECK_AND_CONTINUE_LOG(cond, fmt, ...) \
if (!(cond)) { \
(void)printf("%s\n", fmt, ##__VA_ARGS__); \
continue; \
}
}
#endif // DEMO_LOG_H