提交 41e463c4 编写于 作者: O openharmony_ci 提交者: Gitee

!6 基于AI-Engine增加SDK及Plugin

Merge pull request !6 from litte_coder_man/template0321
# Copyright (c) 2021 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.
import("//build/lite/config/component/lite_component.gni")
lite_component("ai") {
features = [
"asr:asr",
"cv:cv",
]
}
# Copyright (c) 2021 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.
import("//build/lite/config/component/lite_component.gni")
lite_component("asr") {
features = [ "keyword_spotting:kws" ]
}
# Copyright (c) 2021 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.
import("//build/lite/config/component/lite_component.gni")
executable("kws_app") {
sources = [
"audio_cache.cpp",
"kws_app.cpp",
"kws_manager.cpp",
]
cflags = [ "-Wall" ]
cflags_cc = cflags
include_dirs = [
"//foundation/ai/engine/services/common/platform/os_wrapper/audio_loader/include",
"//foundation/ai/engine/services/common/platform/os_wrapper/audio_loader/include/codec",
"//foundation/ai/engine/interfaces/kits/asr/keyword_spotting",
"//foundation/ai/engine/interfaces/kits",
"//foundation/multimedia/interfaces/kits/audio_lite",
"//foundation/multimedia/utils/include",
"//foundation/ai/engine/services/common/utils",
"//foundation/ai/engine/services/common/platform/utils",
"//foundation/ai/engine/services/common/platform/os_wrapper/utils",
"//third_party/bounds_checking_function/include",
]
ldflags = [
"-lstdc++",
"-lpthread",
"-lcodec",
]
deps = [
"//foundation/ai/engine/services/client/algorithm_sdk/asr:asr",
"//foundation/ai/engine/services/common/platform/os_wrapper/audio_loader:audio_loader",
"//foundation/multimedia/audio_lite/frameworks:audio_capturer_lite",
"//foundation/multimedia/utils/lite:media_common",
"//third_party/bounds_checking_function:libsec_static",
]
output_dir = "$root_out_dir/dev_tools"
}
lite_component("kws") {
features = [ ":kws_app" ]
}
/*
* Copyright (c) 2021 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 "audio_cache.h"
#include <string>
#include "securec.h"
namespace KWS {
const int32_t MAX_BUFFER_SIZE = 36000;
const int32_t MIN_BUFFER_SIZE = 8000;
AudioCache::AudioCache()
: maxBufferSize_(0), left_(0), right_(0), buffer_(nullptr), prepared_(false)
{
}
AudioCache::~AudioCache()
{
if (prepared_ && buffer_ != nullptr) {
delete[] buffer_;
buffer_ = nullptr;
}
prepared_ = false;
maxBufferSize_ = 0;
left_ = 0;
right_ = 0;
}
bool AudioCache::Init(int32_t maxSize)
{
if (prepared_) {
printf("[AudioCache]Cache has ready init.\n");
return false;
}
if (maxSize > MAX_BUFFER_SIZE || maxSize < MIN_BUFFER_SIZE) {
printf("[AudioCache]maxSize out of range, init failed.\n");
return false;
}
maxBufferSize_ = maxSize;
buffer_ = new (std::nothrow) uint8_t[maxBufferSize_];
if (buffer_ == nullptr) {
printf("[AudioCache]Fail to allocate buffer for given size.\n");
return false;
}
errno_t ret = memset_s(buffer_, maxBufferSize_, 0x00, maxBufferSize_);
if (ret != EOK) {
printf("[AudioCache]Cache buffer init failed.\n");
return false;
}
prepared_ = true;
return true;
}
bool AudioCache::AppendBuffer(int32_t bufferSize, const uint8_t *buffer)
{
if (!prepared_) {
return false;
}
if (bufferSize + right_ >= maxBufferSize_) {
left_ = 0;
right_ = 0;
}
size_t remainLength = maxBufferSize_ - right_;
size_t length = (bufferSize > remainLength) ? remainLength : bufferSize;
size_t copySize = sizeof(uint8_t) * length;
errno_t ret = memcpy_s(&buffer_[right_], copySize, buffer, copySize);
if (ret != EOK) {
printf("[AudioCache]AppendBuffer failed.\n");
return false;
}
right_ += length;
return true;
}
size_t AudioCache::GetCapturedBuffer(uintptr_t &samplePtr)
{
if (right_ - left_ <= 0 || buffer_ == nullptr) {
return 0;
}
samplePtr = reinterpret_cast<uintptr_t>(buffer_ + left_);
size_t length = right_ - left_;
left_ = right_;
return length;
}
} // namespace KWS
\ No newline at end of file
/*
* Copyright (c) 2021 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 AUDIO_CACHE_H
#define AUDIO_CACHE_H
#include <cstdint>
#include <mutex>
namespace KWS {
class AudioCache {
public:
AudioCache();
virtual ~AudioCache();
bool Init(int32_t maxSize);
size_t GetCapturedBuffer(uintptr_t &samplePtr);
bool AppendBuffer(int32_t bufferSize, const uint8_t *buffer);
private:
int32_t maxBufferSize_;
int32_t left_;
int32_t right_;
uint8_t *buffer_;
bool prepared_;
};
} // namespace KWS
#endif // AUDIO_CACHE_H
\ No newline at end of file
/*
* Copyright (c) 2021 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 <cstdio>
#include <iostream>
#include <memory>
#include "kws_manager.h"
using namespace std;
using namespace KWS;
static void SampleHelp()
{
printf("****************************************\n");
printf("Select the behavior of KWS app.\n");
printf("s: AudioCap (Press q to quit)\n");
printf("q: quit the sample.\n");
printf("****************************************\n");
}
int main()
{
printf("Keyword spotting started.\n");
SampleHelp();
shared_ptr<KwsManager> kwsMgr = make_shared<KwsManager>(AUDIO_SAMPLE_RATE, AUDIO_CODEC_BITRATE);
if (kwsMgr == nullptr) {
printf("Keyword spotting failed to allocate KWSManager.\n");
return -1;
}
if (!kwsMgr->Prepare()) {
printf("Keyword spotting failed to prepare KWSManager.\n");
return -1;
}
char input = ' ';
while (cin >> input) {
switch (input) {
case 's':
kwsMgr->Start();
break;
case 'q':
kwsMgr->Stop();
printf("Keyword spotting Terminated.\n");
return 0;
default:
SampleHelp();
break;
}
}
return 0;
}
\ No newline at end of file
/*
* Copyright (c) 2021 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 <cstdint>
#include <cstdio>
#include "kws_manager.h"
using namespace OHOS::AI;
using namespace OHOS::Audio;
using namespace OHOS::Media;
namespace KWS {
namespace {
const int32_t CONFIDENCE = 2662;
const int32_t NUM_SLIDE_WINDOW = 10;
const int32_t MAX_CACHE_SIZE = 16000;
const int32_t WINDOW_SIZE = 480; // times of per window: 30ms
const int32_t STRIDE_SIZE = 320; // times of per stride: 20ms
const int32_t SUCCESS = 0;
const int32_t CHANNEL_COUNT = 1;
using Capturer = std::shared_ptr<AudioCapturer>;
using Cache = std::shared_ptr<AudioCache>;
using Plugin = std::shared_ptr<KWSSdk>;
// Can not create KwsManager twice
std::shared_ptr<std::thread> g_producer = nullptr;
std::shared_ptr<std::thread> g_consumer = nullptr;
const auto DELETE_ARRAY = [](uint8_t *array) {
if (array != nullptr) {
delete[] array;
}
};
}
class MyKwsCallback : public KWSCallback {
public:
MyKwsCallback() {}
~MyKwsCallback() {}
void OnError(int32_t errorCode)
{
printf("Executing error, error code: %d\n", errorCode);
}
void OnResult(const Array<int32_t> &result)
{
if (result.size != WORD_CONTENT.size()) {
return;
}
for (size_t i = 0; i < result.size; ++i) {
if (result.data[i] > CONFIDENCE) {
printf("[%s]\n", WORD_CONTENT[i].c_str());
}
}
}
};
void ThreadTask::AudioProducer(KwsManager *kwsManager)
{
kwsManager->ProduceSamples();
}
void ThreadTask::AudioConsumer(KwsManager *kwsManager)
{
kwsManager->ConsumeSamples();
}
KwsManager::KwsManager(int32_t sampleRate, int32_t bitRate)
: sampleRate_(sampleRate), bitRate_(bitRate)
{
status_ = IDLE;
}
KwsManager::~KwsManager()
{
OnStop();
status_ = IDLE;
}
void KwsManager::ProduceSamples()
{
printf("[KwsManager]ProduceSamples start\n");
if (capturer_ == nullptr || cache_ == nullptr || aacHandler_ == -1) {
printf("[KwsManager]Produce AudioSample failed for nullptr\n");
return;
}
int32_t readLen = 0;
int32_t retCode = SUCCESS;
size_t frameSize = capturer_->GetFrameCount() * sizeof(uint16_t);
if (frameSize <= 0) {
printf("[KwsManager]Capturer get frame count failed.\n");
return;
}
CoderStream aacStream = {
.buffer = new (std::nothrow) uint8_t[frameSize],
.size = frameSize
};
CoderStream pcmStream = {
.buffer = new (std::nothrow) uint8_t[frameSize],
.size = frameSize
};
if (aacStream.buffer == nullptr || pcmStream.buffer == nullptr) {
printf("[KwsManager]Allocate buffer for aacStream and pcmStream failed.\n");
DELETE_ARRAY(aacStream.buffer);
DELETE_ARRAY(pcmStream.buffer);
return;
}
while (status_ == RUNNING) {
{
std::lock_guard<std::mutex> lock(mutex_);
if (capturer_ == nullptr) {
break;
}
readLen = capturer_->Read(aacStream.buffer, frameSize, false);
}
if (readLen <= 0 || readLen > static_cast<int32_t>(frameSize)) {
continue;
}
aacStream.size = readLen;
retCode = AudioWrapper::GetInstance().Convert(aacHandler_, aacStream, pcmStream);
if (retCode != SUCCESS) {
continue;
}
{
std::lock_guard<std::mutex> lock(mutex_);
if (cache_ == nullptr) {
break;
}
if (!cache_->AppendBuffer(pcmStream.size, pcmStream.buffer)) {
printf("[KwsManager]Fail to append pcm into cache.\n");
}
}
}
DELETE_ARRAY(aacStream.buffer);
DELETE_ARRAY(pcmStream.buffer);
}
void KwsManager::ConsumeSamples()
{
uintptr_t sampleAddr = 0;
size_t sampleSize = 0;
int32_t retCode = SUCCESS;
while (status_ == RUNNING) {
{
std::lock_guard<std::mutex> lock(mutex_);
if (cache_ == nullptr) {
printf("[KwsManager]cache_ is nullptr\n");
break;
}
sampleSize = cache_->GetCapturedBuffer(sampleAddr);
}
if (sampleSize == 0 || sampleAddr == 0) {
continue;
}
Array<int16_t> input = {
.data = (int16_t *)sampleAddr,
.size = sampleSize >> 1
};
{
std::lock_guard<std::mutex> lock(mutex_);
if (plugin_ == nullptr) {
printf("[KwsManager]cache_ is nullptr\n");
break;
}
if ((retCode = plugin_->SyncExecute(input)) != SUCCESS) {
printf("[KwsManager]SyncExecute KWS failed with retcode = [%d]\n", retCode);
continue;
}
}
}
}
bool KwsManager::Prepare()
{
printf("[KwsManager]Prepare.\n");
if (status_ != IDLE) {
printf("[KwsManager]Already prepared.\n");
return false;
}
if (!PreparedAudioCapturer()) {
printf("[KwsManager]Fail to prepare AudioCapturer!\n");
OnStop();
return false;
}
if (!PreparedAudioWrapper()) {
printf("[KwsManager]Fail to prepare AudioWrapper!\n");
OnStop();
return false;
}
if (!PreparedInference()) {
printf("[KwsManager]Fail to prepare Inference!\n");
OnStop();
return false;
}
status_ = PREPARED;
return true;
}
void KwsManager::Start()
{
printf("[KwsManager]Start.\n");
if (status_ == RUNNING) {
printf("[KwsManager]Already running.\n");
return;
}
if (status_ != PREPARED && !Prepare()) {
printf("[KwsManager]Fail to prepare KwsManager!\n");
return;
}
OnStart();
}
void KwsManager::Stop()
{
printf("[KwsManager]Stop.\n");
if (status_ == IDLE) {
printf("[KwsManager]Is already stopped.\n");
return;
}
std::lock_guard<std::mutex> lock(mutex_);
status_ = IDLE;
OnStop();
}
void KwsManager::OnStart()
{
if (!capturer_->Start()) {
printf("[KwsManager]Fail to start audioCapturer\n");
OnStop();
return;
}
if (aacHandler_ == -1) {
printf("[KwsManager]Fail to start producer for the illegal aac-to-pcm handler\n");
OnStop();
return;
}
if (cache_ == nullptr) {
printf("[KwsManager]Fail to start producer for the nullptr cache\n");
OnStop();
return;
}
if (plugin_ == nullptr) {
printf("[KwsManager]Fail to start producer for the nullptr plugin\n");
OnStop();
return;
}
status_ = RUNNING;
g_producer = std::make_shared<std::thread>(ThreadTask::AudioProducer, this);
g_consumer = std::make_shared<std::thread>(ThreadTask::AudioConsumer, this);
}
void KwsManager::StopAudioCapturer()
{
printf("[KwsManager]StopAudioCapturer\n");
if (capturer_ != nullptr) {
capturer_->Stop();
capturer_ = nullptr;
}
}
void KwsManager::StopAudioWrapper()
{
printf("[KwsManager]StopAudioWrapper\n");
AudioWrapper::GetInstance().Deinit(aacHandler_);
}
void KwsManager::StopInference()
{
printf("[KwsManager]StopInference\n");
if (plugin_ != nullptr) {
int32_t ret = plugin_->Destroy();
if (ret != SUCCESS) {
printf("[KwsManager]plugin_ destroy failed.\n");
}
plugin_ = nullptr;
}
}
void KwsManager::OnStop()
{
if (capturer_ != nullptr) {
StopAudioCapturer();
}
StopAudioWrapper();
if (plugin_ != nullptr) {
StopInference();
}
if (g_producer != nullptr) {
g_producer->join();
}
if (g_consumer != nullptr) {
g_consumer->join();
}
}
bool KwsManager::PreparedAudioCapturer()
{
// Set audio wrapper mode before build audio capturer
AudioWrapper::GetInstance().SetCodecMode(false);
if (capturer_ != nullptr) {
printf("[KwsManager]Stop created AudioCapturer at first\n");
StopAudioCapturer();
}
capturer_ = std::make_shared<AudioCapturer>();
if (capturer_ == nullptr || !ConfiguredAudioCapturer()) {
printf("[KwsManager]Fail to create AudioCapturer.\n");
OnStop();
return false;
}
return true;
}
bool KwsManager::PreparedAudioWrapper()
{
cache_ = std::make_shared<AudioCache>();
if (cache_ == nullptr) {
printf("[KwsManager]Failed to create AudioCache\n");
return false;
}
if (!cache_->Init(MAX_CACHE_SIZE)) {
printf("[KwsManager]Failed to init AudioCache\n");
return false;
}
if (!ConfiguredAudioWrapper()) {
printf("[KwsManager]Failed to prepared AudioWrapper.\n");
OnStop();
return false;
}
return true;
}
bool KwsManager::PreparedInference()
{
if (capturer_ == nullptr) {
printf("[KwsManager]Only load plugin after AudioCapturer ready.\n");
return false;
}
if (plugin_ != nullptr) {
printf("[KwsManager]Stop created Inference Plugin at first.\n");
StopInference();
}
plugin_ = std::make_shared<KWSSdk>();
if (plugin_ == nullptr) {
printf("[KwsManager]Failed to create InferencePlugin.\n");
return false;
}
if (plugin_->Create() != SUCCESS) {
printf("[KwsManager]Failed to create KWSSDK.\n");
return false;
}
std::shared_ptr<KWSCallback> callback = std::make_shared<MyKwsCallback>();
if (callback == nullptr) {
printf("[KwsManager]Create callback failed.\n");
return false;
}
plugin_->SetCallback(callback);
return true;
}
bool KwsManager::ConfiguredAudioCapturer()
{
AudioCapturerInfo audioConfig;
audioConfig.inputSource = AUDIO_MIC;
audioConfig.audioFormat = AAC_LC;
audioConfig.sampleRate = AUDIO_SAMPLE_RATE;
audioConfig.channelCount = CHANNEL_COUNT;
audioConfig.bitRate = AUDIO_CODEC_BITRATE;
audioConfig.streamType = TYPE_MEDIA;
audioConfig.bitWidth = BIT_WIDTH_16;
int32_t ret = capturer_->SetCapturerInfo(audioConfig);
if (ret != SUCCESS) {
printf("[KwsManager]ConfiguredAudioCapturer fail with ret = 0x%.8x\n", ret);
return false;
}
return true;
}
bool KwsManager::ConfiguredAudioWrapper()
{
ConvertType typo = CONVERT_AAC_TO_PCM;
CoderConfig codecConfig;
codecConfig.audioFormat = AAC_LC;
codecConfig.bitRate = bitRate_;
codecConfig.sampleRate = sampleRate_;
codecConfig.channelCount = CHANNEL_COUNT;
codecConfig.bitWidth = BIT_WIDTH_16;
if (AudioWrapper::GetInstance().Init(typo, aacHandler_) != SUCCESS) {
return false;
}
if (AudioWrapper::GetInstance().SetConfig(aacHandler_, codecConfig) != SUCCESS) {
return false;
}
if (AudioWrapper::GetInstance().StartCodec(aacHandler_) != SUCCESS) {
return false;
}
return true;
}
}
\ No newline at end of file
/*
* Copyright (c) 2021 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 KWS_MANAGER_H
#define KWS_MANAGER_H
#include <mutex>
#include <thread>
#include <unistd.h>
#include <vector>
#include "ai_datatype.h"
#include "audio_cache.h"
#include "audio_capturer.h"
#include "audio_wrapper.h"
#include "kws_callback.h"
#include "kws_sdk.h"
#include "media_errors.h"
#include "media_info.h"
namespace KWS {
const int32_t AUDIO_SAMPLE_RATE = 16000; // 16kHz
const int32_t AUDIO_CODEC_BITRATE = 32000; // 32kHz
const std::vector<std::string> WORD_CONTENT = {
"Hi Xiaowen",
"Nihao Wenwen",
"Unknown"
};
enum KwsStatus {
IDLE = 1000,
PREPARED,
RUNNING,
};
class KwsManager {
public:
KwsManager(int32_t sampleRate, int32_t bitRate);
~KwsManager();
void Start();
void Stop();
bool Prepare();
void ProduceSamples();
void ConsumeSamples();
private:
void OnStart();
void OnStop();
bool PreparedAudioCapturer();
bool PreparedAudioWrapper();
bool PreparedInference();
bool ConfiguredAudioCapturer();
bool ConfiguredAudioWrapper();
void StopAudioCapturer();
void StopAudioWrapper();
void StopInference();
private:
std::shared_ptr<AudioCache> cache_ = nullptr;
std::shared_ptr<OHOS::AI::KWSSdk> plugin_ = nullptr;
std::shared_ptr<OHOS::Audio::AudioCapturer> capturer_ = nullptr;
int32_t sampleRate_ = AUDIO_SAMPLE_RATE;
int32_t bitRate_ = AUDIO_CODEC_BITRATE;
KwsStatus status_ = IDLE;
intptr_t aacHandler_ = -1;
std::mutex mutex_;
};
class ThreadTask {
public:
static void AudioProducer(KwsManager *kwsManager);
static void AudioConsumer(KwsManager *kwsManager);
};
} // namespace KWS
#endif
\ No newline at end of file
# Copyright (c) 2021 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.
import("//build/lite/config/component/lite_component.gni")
lite_component("cv") {
features = [ "image_classification:ic" ]
}
# Copyright (c) 2021 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.
import("//build/lite/config/component/lite_component.gni")
copy("demo_image_for_test") {
sources = [ "resources/image_classification_demo.jpg" ]
outputs = [ "$root_out_dir/data/image_classification_demo.jpg" ]
}
executable("ic_app") {
sources = [
"camera_manager.cpp",
"image_classification_sample.cpp",
"picture_utils.cpp",
"resize_computer.cpp",
]
cflags = [ "-Wall" ]
cflags_cc = cflags
include_dirs = [
"//third_party/libjpeg",
"//foundation/ai/engine/interfaces/kits",
"//foundation/ai/engine/interfaces/kits/cv/image_classification",
"//foundation/ai/engine/services/client/algorithm_sdk/cv/image_classification/include",
"//foundation/multimedia/media_lite/interfaces/kits/recorder_lite",
]
ldflags = [ "-lstdc++" ]
ldflags += [ "-lpthread" ]
ldflags += [ "-Wl,-rpath-link=$ohos_root_path/$root_out_dir" ]
deps = [
"//foundation/ai/engine/services/client/algorithm_sdk/cv/image_classification:image_classification_sdk",
"//foundation/multimedia/camera_lite/frameworks:camera_lite",
"//foundation/multimedia/media_lite/frameworks/recorder_lite:recorder_lite",
"//third_party/libjpeg",
]
output_dir = "$root_out_dir/dev_tools"
}
lite_component("ic") {
features = [ ":ic_app" ]
}
/*
* Copyright (c) 2021 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 "camera_manager.h"
using namespace std;
using namespace OHOS;
using namespace OHOS::Media;
namespace IC {
const int QFACTOR = 90;
std::mutex g_mutex;
std::condition_variable g_cv;
static void SampleSaveCapture(const char *p, uint32_t size)
{
printf("Start saving picture.\n");
ofstream pic(CAMERA_SAVE_PATH, ofstream::out | ofstream::trunc);
if (pic.is_open()) {
printf("Write %d bytes.\n", size);
pic.write(p, size);
pic.close();
printf("Saving picture end.\n");
}
}
void SampleSurfaceListener::SetSurface(Surface *surface)
{
surface_ = surface;
}
void SampleFrameStateCallback::OnFrameFinished(Camera &camera, FrameConfig &fc, FrameResult &result)
{
std::unique_lock<std::mutex> lock(g_mutex);
printf("Receive frame complete inform.\n");
if (fc.GetFrameConfigType() == FRAME_CONFIG_CAPTURE) {
printf("Capture frame received.\n");
list<Surface *> surfaceList = fc.GetSurfaces();
for (Surface *surface : surfaceList) {
SurfaceBuffer *buffer = surface->AcquireBuffer();
if (buffer != nullptr) {
char *virtAddr = static_cast<char *>(buffer->GetVirAddr());
if (virtAddr != nullptr) {
SampleSaveCapture(virtAddr, buffer->GetSize());
}
surface->ReleaseBuffer(buffer);
}
delete surface;
}
} else if (fc.GetFrameConfigType() == FRAME_CONFIG_PREVIEW) {
printf("Preview frame received.\n");
list<Surface *> surfaceList = fc.GetSurfaces();
for (Surface *surface : surfaceList) {
printf("surface release.\n");
delete surface;
}
}
delete &fc;
g_cv.notify_all();
}
void SampleSurfaceListener::OnBufferAvailable()
{
if (surface_ == nullptr) {
return;
}
SurfaceBuffer *buffer = surface_->AcquireBuffer();
if (buffer != nullptr) {
surface_->ReleaseBuffer(buffer);
}
}
SampleCameraStateMng::SampleCameraStateMng(EventHandler &eventHdlr) : eventHdlr_(eventHdlr)
{
}
SampleCameraStateMng::~SampleCameraStateMng()
{
}
void SampleCameraStateMng::OnCreated(Camera &c)
{
std::unique_lock<std::mutex> lock(g_mutex);
printf("Sample recv OnCreate camera.\n");
auto config = CameraConfig::CreateCameraConfig();
if (config != nullptr) {
config->SetFrameStateCallback(&fsCb_, &eventHdlr_);
}
c.Configure(*config);
cam_ = &c;
g_cv.notify_all();
}
void SampleCameraStateMng::OnCreateFailed(const string cameraId, int32_t errorCode)
{
printf("Sample camera create failed. Error code: %d.\n", errorCode);
}
void SampleCameraStateMng::OnReleased(Camera &c)
{
printf("Sample camera OnReleased.\n");
}
void SampleCameraStateMng::Capture()
{
if (cam_ == nullptr) {
printf("Camera is not ready.\n");
return;
}
FrameConfig *fc = new (std::nothrow) FrameConfig(FRAME_CONFIG_CAPTURE);
if (fc == nullptr) {
printf("Create FrameConfig failed.\n");
return;
}
Surface *surface = Surface::CreateSurface();
if (surface == nullptr) {
delete fc;
printf("CreateSurface failed.\n");
return;
}
surface->SetWidthAndHeight(CAMERA_PIC_WIDTH, CAMERA_PIC_HEIGHT);
surface->SetUsage(BUFFER_CONSUMER_USAGE_HARDWARE);
fc->AddSurface(*surface);
fc->SetParameter(PARAM_KEY_IMAGE_ENCODE_QFACTOR, QFACTOR);
cam_->TriggerSingleCapture(*fc);
}
} // namespace IC
\ No newline at end of file
/*
* Copyright (c) 2021 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 CAMERA_MANAGER_H
#define CAMERA_MANAGER_H
#include "camera_kit.h"
#include "recorder.h"
#include <algorithm>
#include <condition_variable>
#include <cstring>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <mutex>
#include <pthread.h>
#include <sstream>
#include <string>
#include <sys/io.h>
#include <sys/prctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <thread>
#include <unistd.h>
namespace IC {
// Settings of camera
const int32_t CAMERA_PIC_WIDTH = 1920;
const int32_t CAMERA_PIC_HEIGHT = 1080;
const std::string CAMERA_SAVE_PATH = "/storage/Capture.jpg";
// condition_variable for camera
extern std::mutex g_mutex;
extern std::condition_variable g_cv;
class SampleFrameStateCallback : public OHOS::Media::FrameStateCallback {
public:
void OnFrameFinished(OHOS::Media::Camera &camera,
OHOS::Media::FrameConfig &fc,
OHOS::Media::FrameResult &result) override;
};
class SampleSurfaceListener : public OHOS::IBufferConsumerListener {
public:
void SetSurface(OHOS::Media::Surface *surface);
void OnBufferAvailable() override;
private:
OHOS::Media::Surface *surface_ = nullptr;
};
class SampleCameraDeivceCallback : public OHOS::Media::CameraDeviceCallback {
};
class SampleCameraStateMng : public OHOS::Media::CameraStateCallback {
public:
SampleCameraStateMng() = delete;
explicit SampleCameraStateMng(OHOS::Media::EventHandler &eventHdlr);
~SampleCameraStateMng();
void OnCreated(OHOS::Media::Camera &c) override;
void OnCreateFailed(const std::string cameraId, int32_t errorCode) override;
void OnReleased(OHOS::Media::Camera &c) override;
void Capture();
private:
OHOS::Media::EventHandler &eventHdlr_;
OHOS::Media::Camera *cam_ = nullptr;
SampleSurfaceListener listener_;
SampleFrameStateCallback fsCb_;
OHOS::Media::FrameConfig *fc_ = nullptr;
};
} // namespace IC
#endif
\ No newline at end of file
/*
* Copyright (c) 2021 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 "camera_manager.h"
#include "ic_callback.h"
#include "ic_constants.h"
#include "ic_retcode.h"
#include "ic_sdk.h"
#include "picture_utils.h"
using namespace std;
using namespace IC;
using namespace OHOS;
using namespace OHOS::AI;
using namespace OHOS::Media;
namespace {
const auto DELETE_PIC_BUFFER = [](uint8_t *&buffer) {
if (buffer != nullptr) {
delete[] buffer;
buffer = nullptr;
}
};
}
class MyIcCallback : public IcCallback {
public:
MyIcCallback() {}
~MyIcCallback() {}
void OnError(const IcRetCode errorCode)
{
printf("Executing error, error code: %d\n", errorCode);
}
void OnResult(const IcOutput &result)
{
if (result.size % 2 == 0) {
int numClass = result.size / 2;
for (size_t i = 0; i < numClass; ++i) {
printf("class index [%d] score: %d\n", result.data[i], result.data[i + numClass]);
}
}
}
};
static int CameraCapture()
{
printf("Camera sample begin.\n");
CameraKit *camKit = CameraKit::GetInstance();
if (camKit == nullptr) {
printf("Can not get CameraKit instance\n");
return IC_RETCODE_FAILURE;
}
list<string> camList = camKit->GetCameraIds();
string camId;
for (auto &cam : camList) {
printf("camera name: %s\n", cam.c_str());
const CameraAbility *ability = camKit->GetCameraAbility(cam);
list<CameraPicSize> sizeList = ability->GetSupportedSizes(0);
for (auto &pic : sizeList) {
if (pic.width == CAMERA_PIC_WIDTH && pic.height == CAMERA_PIC_HEIGHT) {
camId = cam;
break;
}
}
if (!camId.empty()) {
break;
}
}
if (camId.empty()) {
printf("No available camera.(1080p wanted)\n");
return IC_RETCODE_FAILURE;
}
EventHandler eventHdlr;
SampleCameraStateMng camStateMng(eventHdlr);
camKit->CreateCamera(camId, camStateMng, eventHdlr);
std::unique_lock<std::mutex> cameraCreateLock(g_mutex);
g_cv.wait(cameraCreateLock);
cameraCreateLock.unlock();
camStateMng.Capture();
std::unique_lock<std::mutex> captureLock(g_mutex);
g_cv.wait(captureLock);
captureLock.unlock();
printf("Camera sample end.\n");
return IC_RETCODE_SUCCESS;
}
static int ImageClassificationExecute(const IcInput &picData)
{
if (picData.data == nullptr || picData.size == 0) {
printf("ImageClassificationExecute: picData is empty.\n");
return IC_RETCODE_FAILURE;
}
shared_ptr<IcSdk> detector = make_shared<IcSdk>();
shared_ptr<MyIcCallback> callback = make_shared<MyIcCallback>();
if (detector == nullptr || callback == nullptr) {
return IC_RETCODE_FAILURE;
}
detector->SetCallback(callback);
int retcode = detector->Create();
if (retcode != IC_RETCODE_SUCCESS) {
printf("ImageClassificationExecute: IcSdk Create failed.\n");
return IC_RETCODE_FAILURE;
}
retcode = detector->SyncExecute(picData);
if (retcode != IC_RETCODE_SUCCESS) {
printf("ImageClassificationExecute: IcSdk SyncExecute failed.\n");
}
(void)detector->Destroy();
return retcode;
}
static int GetPictureData(const string &sourcePath, Array<uint8_t> &picData)
{
int srcWidth = 0;
int srcHeight = 0;
uint8_t *rawData = ReadJpegFile(sourcePath, srcWidth, srcHeight);
if (rawData == nullptr) {
printf("ReadJpegFile failed.\n");
return IC_RETCODE_FAILURE;
}
uint8_t *srcData = Resize(WIDTH_DEST, HEIGHT_DEST, rawData, srcWidth, srcHeight);
if (srcData == nullptr) {
printf("Resize failed.\n");
DELETE_PIC_BUFFER(rawData);
return IC_RETCODE_FAILURE;
}
int srcDataSize = WIDTH_DEST * HEIGHT_DEST * NUM_CHANNELS;
uint8_t *input = ConvertToCaffeInput(srcData, srcDataSize);
if (input == nullptr) {
printf("Convert to caffe input failed.\n");
DELETE_PIC_BUFFER(rawData);
DELETE_PIC_BUFFER(srcData);
return IC_RETCODE_FAILURE;
}
picData.data = input;
picData.size = srcDataSize;
DELETE_PIC_BUFFER(rawData);
DELETE_PIC_BUFFER(srcData);
return IC_RETCODE_SUCCESS;
}
static int GetPicFromCamera(IcInput &picData)
{
int retcode = CameraCapture();
if (retcode != IC_RETCODE_SUCCESS) {
printf("Capture picture failed.\n");
return IC_RETCODE_FAILURE;
}
retcode = GetPictureData(CAMERA_SAVE_PATH, picData);
if (retcode != IC_RETCODE_SUCCESS) {
printf("GetPictureData failed.\n");
return IC_RETCODE_FAILURE;
}
return IC_RETCODE_SUCCESS;
}
static int GetPicFromLocal(IcInput &picData)
{
int retcode = GetPictureData(JPEG_SRC_PATH, picData);
if (retcode != IC_RETCODE_SUCCESS) {
printf("GetPictureData failed.\n");
return IC_RETCODE_FAILURE;
}
return IC_RETCODE_SUCCESS;
}
static void SampleHelp()
{
printf("****************************************\n");
printf("Select the image source.\n");
printf("1: Camera capture\n");
printf("2: Local\n");
printf("****************************************\n");
}
int main()
{
IcInput picData = {
.data = nullptr,
.size = 0
};
int retcode = IC_RETCODE_SUCCESS;
char input = ' ';
SampleHelp();
cin >> input;
switch (input) {
case '1':
retcode = GetPicFromCamera(picData);
break;
case '2':
retcode = GetPicFromLocal(picData);
break;
default:
SampleHelp();
break;
}
if (retcode != IC_RETCODE_SUCCESS) {
printf("GetPicture failed.\n");
return -1;
}
if (retcode != IC_RETCODE_SUCCESS) {
printf("WriteBgrFile failed.\n");
DELETE_PIC_BUFFER(picData.data);
return -1;
}
retcode = ImageClassificationExecute(picData);
if (retcode != IC_RETCODE_SUCCESS) {
printf("ImageClassification failed.\n");
} else {
printf("ImageClassification successed.\n");
}
DELETE_PIC_BUFFER(picData.data);
return 0;
}
\ No newline at end of file
/*
* Copyright (c) 2021 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 "picture_utils.h"
#include <fstream>
#include <iostream>
#include "ic_retcode.h"
#include "resize_computer.h"
#include "securec.h"
using namespace std;
namespace IC {
int WriteJpegFile(const string &filename, int quality,
uint8_t *srcBuffer, int srcWidth, int srcHeight)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW rowPointer[1];
int rowStride = 0;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
if (srcBuffer == nullptr) {
printf("WriteJpegFile: srcBuffer is nullptr\n");
return IC_RETCODE_FAILURE;
}
FILE *outfile;
if ((outfile = fopen(filename.c_str(), "wb")) == nullptr) {
printf("WriteJpegFile: can't open %s\n", filename.c_str());
return IC_RETCODE_FAILURE;
}
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = srcWidth;
cinfo.image_height = srcHeight;
cinfo.input_components = NUM_CHANNELS;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE);
jpeg_start_compress(&cinfo, TRUE);
rowStride = srcWidth * NUM_CHANNELS;
while (cinfo.next_scanline < cinfo.image_height) {
rowPointer[0] = &srcBuffer[cinfo.next_scanline * rowStride];
(void)jpeg_write_scanlines(&cinfo, rowPointer, 1);
}
jpeg_finish_compress(&cinfo);
fclose(outfile);
jpeg_destroy_compress(&cinfo);
return IC_RETCODE_SUCCESS;
}
int WriteBgrFile(const string &filename, uint8_t *dataBuffer, int bufferSize)
{
if (dataBuffer == nullptr || bufferSize <= 0) {
printf("WriteBgrFile: dataBuffer is nullptr.\n");
return IC_RETCODE_FAILURE;
}
ofstream outfile(filename.c_str(), ofstream::out | ofstream::trunc);
if (!outfile.is_open()) {
printf("WriteBgrFile: Error writing file from BGR dataBuffer\n");
return IC_RETCODE_FAILURE;
}
outfile.write((const char*)dataBuffer, bufferSize);
outfile.close();
return IC_RETCODE_SUCCESS;
}
uint8_t *ConvertToCaffeInput(uint8_t *dataBuffer, int maxSize)
{
if (dataBuffer == nullptr) {
return nullptr;
}
if (maxSize % NUM_CHANNELS != 0) {
return nullptr;
}
uint8_t *input = new (std::nothrow) uint8_t[maxSize];
if (input == nullptr) {
return nullptr;
}
int numPreChannel = maxSize / NUM_CHANNELS;
for (int i = 0; i < maxSize; i++) {
input[BGR_RED * numPreChannel + i / NUM_CHANNELS] = dataBuffer[i + RGB_RED];
input[BGR_BLUE * numPreChannel + i / NUM_CHANNELS] = dataBuffer[i + RGB_BLUE];
input[BGR_GREEN * numPreChannel + i / NUM_CHANNELS] = dataBuffer[i + RGB_GREEN];
}
return input;
}
uint8_t *ReadJpegFile(const string &filename, int &srcWidth, int &srcHeight)
{
struct jpeg_decompress_struct cinfo;
struct MyErrorMgr jerr;
FILE *infile;
if ((infile = fopen(filename.c_str(), "rb")) == nullptr) {
printf("ReadJpegFile: can't open %s\n", filename.c_str());
return nullptr;
}
cinfo.err = jpeg_std_error(&jerr.pub);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, infile);
(void)jpeg_read_header(&cinfo, TRUE);
(void)jpeg_start_decompress(&cinfo);
srcHeight = cinfo.output_height;
srcWidth = cinfo.output_width;
int dataSize = srcHeight * srcWidth * cinfo.output_components;
uint8_t *buffer = new (std::nothrow) uint8_t[dataSize];
if (buffer == nullptr) {
printf("ReadJpegFile: error to alloc buffer.\n");
(void)jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return nullptr;
}
uint8_t *rowptr = nullptr;
while (cinfo.output_scanline < srcHeight) {
rowptr = buffer + cinfo.output_scanline * srcWidth * cinfo.output_components;
(void)jpeg_read_scanlines(&cinfo, &rowptr, 1);
}
(void)jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return buffer;
}
uint8_t *Resize(
const int widthDest, const int heightDest, uint8_t *src, int widthSrc, int heightSrc)
{
if (src == nullptr) {
printf("Resize: src is nullptr.\n");
return nullptr;
}
if (widthDest <= 0 || heightDest <= 0 || widthSrc <= 0 || heightSrc <= 0) {
printf("Resize: dimension below zero.\n");
return nullptr;
}
int bufferSize = widthDest * heightDest * NUM_CHANNELS;
uint8_t *pDest = new (std::nothrow) uint8_t[bufferSize];
PicInfo picInfo = {
.widthSrc = widthSrc,
.heightSrc = heightSrc,
.widthDest = widthDest,
.heightDest = heightDest
};
ResizeComputer resizer(picInfo);
if (pDest == nullptr) {
printf("Resize: pDest alloc failed.\n");
return nullptr;
}
if (widthDest == widthSrc && heightDest == heightSrc) {
if (memcpy_s(pDest, bufferSize, src, bufferSize) != EOK) {
printf("Resize: memcpy_s failed.\n");
delete[] pDest;
return nullptr;
} else {
return pDest;
}
}
resizer.Compute(pDest, src, bufferSize, widthSrc * heightSrc * NUM_CHANNELS);
return pDest;
}
} // namespace IC
\ No newline at end of file
/*
* Copyright (c) 2021 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 PICTURE_UTILS_H
#define PICTURE_UTILS_H
#include <csetjmp>
#include <cstdio>
#include <memory>
#include <string>
#include "jpeglib.h"
namespace IC {
struct MyErrorMgr {
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
using MyErrorPtr = MyErrorMgr *;
// The index order of BGR format
enum BgrIndex {
BGR_BLUE = 0,
BGR_GREEN,
BGR_RED,
};
// The index order of RGB format
enum RgbIndex {
RGB_RED = 0,
RGB_GREEN,
RGB_BLUE,
};
// Information about picture
struct PicInfo {
int widthSrc;
int heightSrc;
int widthDest;
int heightDest;
};
// Change this to your own settings
const std::string JPEG_SRC_PATH = "/storage/data/image_classification_demo.jpg";
const int WIDTH_DEST = 224;
const int HEIGHT_DEST = 224;
const int NUM_CHANNELS = 3;
int WriteJpegFile(const std::string &filename, int quality, uint8_t *srcBuffer, int srcWidth, int srcHeight);
int WriteBgrFile(const std::string &filename, uint8_t *dataBuffer, int bufferSize);
uint8_t *ConvertToCaffeInput(uint8_t *dataBuffer, int maxSize);
uint8_t *ReadJpegFile(const std::string &filename, int &srcWidth, int &srcHeight);
uint8_t *Resize(const int widthDest, const int heightDest, uint8_t *src, int widthSrc, int heightSrc);
} // namespace IC
#endif // PICTURE_UTILS_H
/*
* Copyright (c) 2021 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 "ic_retcode.h"
#include "resize_computer.h"
namespace IC {
const int RESIZE_CONSTANT = 2;
ResizeComputer::ResizeComputer(const PicInfo &pInfo)
{
// Initialize parameter for resize computer
sw_ = pInfo.widthSrc - 1;
sh_ = pInfo.heightSrc - 1;
dw_ = pInfo.widthDest - 1;
dh_ = pInfo.heightDest - 1;
B_ = 0;
N_ = 0;
x_ = 0;
y_ = 0;
pLinePrev_ = nullptr;
pLineNext_ = nullptr;
pA_ = nullptr;
pB_ = nullptr;
pC_ = nullptr;
pD_ = nullptr;
}
int ResizeComputer::Compute(uint8_t *pDest, uint8_t *src, int pDestSize, int srcSize)
{
if (pDest == nullptr || src == nullptr || pDestSize <= 0 || srcSize <= 0) {
printf("ResizeComputer::Compute input is nullptr.\n");
return IC_RETCODE_FAILURE;
}
uint8_t *tmp = nullptr;
// This is linear stretch for picture resize
for (int i = 0; i <= dh_; ++i) {
tmp = pDest + i * (dw_ + 1) * NUM_CHANNELS;
y_ = i * sh_ / dh_;
N_ = dh_ - i * sh_ % dh_;
pLinePrev_ = src + y_ * (sw_ + 1) * NUM_CHANNELS;
y_++;
pLineNext_ = (N_ == dh_) ? pLinePrev_ : (src + y_ * (sw_ + 1) * NUM_CHANNELS);
for (int j = 0; j <= dw_; ++j) {
x_ = j * sw_ / dw_ * NUM_CHANNELS;
B_ = dw_ - j * sw_ % dw_;
pA_ = pLinePrev_ + x_;
pB_ = pA_ + NUM_CHANNELS;
pC_ = pLineNext_ + x_;
pD_ = pC_ + NUM_CHANNELS;
if (B_ == dw_) {
pB_ = pA_;
pD_ = pC_;
}
for (int k = 0; k < NUM_CHANNELS; ++k, ++tmp, ++pA_, ++pB_, ++pC_, ++pD_) {
*tmp = static_cast<uint8_t>(
(B_ * N_ * (*pA_ - *pB_ - *pC_ + *pD_) + dw_ * N_ * (*pB_) +
dh_ * B_ * (*pC_) + (dw_ * dh_ - dh_ * B_ - dw_ * N_) * (*pD_) +
dw_ * dh_ / RESIZE_CONSTANT) / (dw_ * dh_));
}
}
}
return IC_RETCODE_SUCCESS;
}
} // namespace IC
\ No newline at end of file
/*
* Copyright (c) 2021 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 RESIZE_COMPUTER_H
#define RESIZE_COMPUTER_H
#include "picture_utils.h"
namespace IC {
class ResizeComputer {
public:
explicit ResizeComputer(const PicInfo &pInfo);
~ResizeComputer() = default;
int Compute(uint8_t *pDest, uint8_t *src, int pDestSize, int srcSize);
private:
int sw_;
int sh_;
int dw_;
int dh_;
int B_;
int N_;
int x_;
int y_;
uint8_t *pLinePrev_;
uint8_t *pLineNext_;
uint8_t *pA_;
uint8_t *pB_;
uint8_t *pC_;
uint8_t *pD_;
};
} // namespace IC
#endif // RESIZE_COMPUTER_H
\ No newline at end of file
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册