1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "avcodec_audio_avbuffer_flac_encoder_demo.h"
17 #include <iostream>
18 #include <unistd.h>
19 #include <chrono>
20 #include "avcodec_codec_name.h"
21 #include "avcodec_common.h"
22 #include "avcodec_errors.h"
23 #include "demo_log.h"
24 #include "media_description.h"
25 #include "native_avcodec_base.h"
26 #include "native_avformat.h"
27 #include "native_avbuffer.h"
28 #include "native_avmemory.h"
29 #include "securec.h"
30 #include "ffmpeg_converter.h"
31
32 using namespace OHOS;
33 using namespace OHOS::MediaAVCodec;
34 using namespace OHOS::MediaAVCodec::AudioFlacEncDemo;
35 using namespace std;
36 namespace {
37 constexpr uint32_t CHANNEL_COUNT = 2;
38 constexpr uint32_t SAMPLE_RATE = 44100;
39 constexpr uint32_t BITS_RATE = 261000;
40 constexpr uint32_t BITS_PER_CODED_SAMPLE = OH_BitsPerSample::SAMPLE_S16LE;
41 constexpr uint64_t CHANNEL_LAYOUT = AudioChannelLayout::STEREO;
42 constexpr int32_t SAMPLE_FORMAT = AudioSampleFormat::SAMPLE_S16LE;
43 constexpr int32_t COMPLIANCE_LEVEL = 0;
44 constexpr int32_t DEFAULT_FRAME_BYTES = 1152;
45 static std::map<uint32_t, uint32_t> FRAME_BYTES_MAP = {{8000, 576}, {16000, 1152}, {22050, 2304}, {24000, 2304},
46 {32000, 2304}, {44100, 4608}, {48000, 4608}, {88200, 8192},
47 {96000, 8192}};
48
49 constexpr string_view INPUT_FILE_PATH = "/data/test/media/flac_2c_44100hz_261k.pcm";
50 constexpr string_view OUTPUT_FILE_PATH = "/data/test/media/flac_encoder_test.flac";
51 } // namespace
52
OnError(OH_AVCodec * codec,int32_t errorCode,void * userData)53 static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData)
54 {
55 (void)codec;
56 (void)errorCode;
57 (void)userData;
58 cout << "Error received, errorCode:" << errorCode << endl;
59 }
60
OnOutputFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)61 static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
62 {
63 (void)codec;
64 (void)format;
65 (void)userData;
66 cout << "OnOutputFormatChanged received" << endl;
67 }
68
OnInputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * data,void * userData)69 static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData)
70 {
71 (void)codec;
72 AEncBufferSignal *signal = static_cast<AEncBufferSignal *>(userData);
73 unique_lock<mutex> lock(signal->inMutex_);
74 signal->inQueue_.push(index);
75 signal->inBufferQueue_.push(data);
76 signal->inCond_.notify_all();
77 }
78
OnOutputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * data,void * userData)79 static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData)
80 {
81 (void)codec;
82 AEncBufferSignal *signal = static_cast<AEncBufferSignal *>(userData);
83 unique_lock<mutex> lock(signal->outMutex_);
84 signal->outQueue_.push(index);
85 signal->outBufferQueue_.push(data);
86 signal->outCond_.notify_all();
87 }
88
InitFile()89 bool AudioBufferFlacEncDemo::InitFile()
90 {
91 inputFile_.open(INPUT_FILE_PATH, std::ios::binary);
92 outputFile_.open(OUTPUT_FILE_PATH.data(), std::ios::out | std::ios::binary);
93 DEMO_CHECK_AND_RETURN_RET_LOG(inputFile_.is_open(), false, "Fatal: open input file failed");
94 DEMO_CHECK_AND_RETURN_RET_LOG(outputFile_.is_open(), false, "Fatal: open output file failed");
95 return true;
96 }
97
RunCase()98 void AudioBufferFlacEncDemo::RunCase()
99 {
100 cout << "RunCase Enter" << endl;
101 DEMO_CHECK_AND_RETURN_LOG(InitFile(), "Fatal: InitFile file failed");
102
103 DEMO_CHECK_AND_RETURN_LOG(CreateEnc() == AVCS_ERR_OK, "Fatal: CreateEnc fail");
104
105 OH_AVFormat *format = OH_AVFormat_Create();
106 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), CHANNEL_COUNT);
107 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), SAMPLE_RATE);
108 OH_AVFormat_SetLongValue(format, MediaDescriptionKey::MD_KEY_BITRATE.data(), BITS_RATE);
109 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_BITS_PER_CODED_SAMPLE.data(), BITS_PER_CODED_SAMPLE);
110 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), SAMPLE_FORMAT);
111 OH_AVFormat_SetLongValue(format, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CHANNEL_LAYOUT);
112 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_COMPLIANCE_LEVEL.data(), COMPLIANCE_LEVEL);
113
114 DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail");
115
116 DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail");
117
118 {
119 unique_lock<mutex> lock(signal_->startMutex_);
120 signal_->startCond_.wait(lock, [this]() { return (!(isRunning_.load())); });
121 }
122
123 DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail");
124 DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail");
125 }
126
AudioBufferFlacEncDemo()127 AudioBufferFlacEncDemo::AudioBufferFlacEncDemo() : audioEnc_(nullptr), signal_(nullptr) {}
128
~AudioBufferFlacEncDemo()129 AudioBufferFlacEncDemo::~AudioBufferFlacEncDemo()
130 {
131 if (signal_) {
132 delete signal_;
133 signal_ = nullptr;
134 }
135 if (inputFile_.is_open()) {
136 inputFile_.close();
137 }
138 if (outputFile_.is_open()) {
139 outputFile_.close();
140 }
141 }
142
CreateEnc()143 int32_t AudioBufferFlacEncDemo::CreateEnc()
144 {
145 audioEnc_ = OH_AudioCodec_CreateByName((AVCodecCodecName::AUDIO_ENCODER_FLAC_NAME).data());
146 DEMO_CHECK_AND_RETURN_RET_LOG(audioEnc_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail");
147
148 signal_ = new AEncBufferSignal();
149 DEMO_CHECK_AND_RETURN_RET_LOG(signal_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
150
151 cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable};
152 int32_t ret = OH_AudioCodec_RegisterCallback(audioEnc_, cb_, signal_);
153 DEMO_CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, "Fatal: SetCallback fail");
154
155 return AVCS_ERR_OK;
156 }
157
Configure(OH_AVFormat * format)158 int32_t AudioBufferFlacEncDemo::Configure(OH_AVFormat *format)
159 {
160 return OH_AudioCodec_Configure(audioEnc_, format);
161 }
162
Start()163 int32_t AudioBufferFlacEncDemo::Start()
164 {
165 cout << "AudioBufferFlacEncDemo::Start Enter" << endl;
166 isRunning_.store(true);
167
168 cout << "InputFunc" << endl;
169 inputLoop_ = make_unique<thread>(&AudioBufferFlacEncDemo::InputFunc, this);
170 DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
171
172 cout << "OutputFunc" << endl;
173 outputLoop_ = make_unique<thread>(&AudioBufferFlacEncDemo::OutputFunc, this);
174 DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
175
176 cout << "OH_AudioCodec_Start" << endl;
177 return OH_AudioCodec_Start(audioEnc_);
178 }
179
Stop()180 int32_t AudioBufferFlacEncDemo::Stop()
181 {
182 isRunning_.store(false);
183
184 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
185 {
186 unique_lock<mutex> lock(signal_->inMutex_);
187 signal_->inCond_.notify_all();
188 }
189 inputLoop_->join();
190 inputLoop_ = nullptr;
191 while (!signal_->inQueue_.empty()) {
192 signal_->inQueue_.pop();
193 }
194 while (!signal_->inBufferQueue_.empty()) {
195 signal_->inBufferQueue_.pop();
196 }
197 }
198
199 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
200 {
201 unique_lock<mutex> lock(signal_->outMutex_);
202 signal_->outCond_.notify_all();
203 }
204 outputLoop_->join();
205 outputLoop_ = nullptr;
206 while (!signal_->outQueue_.empty()) {
207 signal_->outQueue_.pop();
208 }
209 while (!signal_->outBufferQueue_.empty()) {
210 signal_->outBufferQueue_.pop();
211 }
212 }
213
214 return OH_AudioCodec_Stop(audioEnc_);
215 }
216
Flush()217 int32_t AudioBufferFlacEncDemo::Flush()
218 {
219 isRunning_.store(false);
220 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
221 {
222 unique_lock<mutex> lock(signal_->inMutex_);
223 signal_->inCond_.notify_all();
224 }
225 inputLoop_->join();
226 inputLoop_ = nullptr;
227 while (!signal_->inQueue_.empty()) {
228 signal_->inQueue_.pop();
229 }
230 while (!signal_->inBufferQueue_.empty()) {
231 signal_->inBufferQueue_.pop();
232 }
233 std::cout << "clear input buffer!\n";
234 }
235
236 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
237 {
238 unique_lock<mutex> lock(signal_->outMutex_);
239 signal_->outCond_.notify_all();
240 }
241 outputLoop_->join();
242 outputLoop_ = nullptr;
243 while (!signal_->outQueue_.empty()) {
244 signal_->outQueue_.pop();
245 }
246 while (!signal_->outBufferQueue_.empty()) {
247 signal_->outBufferQueue_.pop();
248 }
249 std::cout << "clear output buffer!\n";
250 }
251 return OH_AudioCodec_Flush(audioEnc_);
252 }
253
Reset()254 int32_t AudioBufferFlacEncDemo::Reset()
255 {
256 return OH_AudioCodec_Reset(audioEnc_);
257 }
258
Release()259 int32_t AudioBufferFlacEncDemo::Release()
260 {
261 return OH_AudioCodec_Destroy(audioEnc_);
262 }
263
HandleEOS(const uint32_t & index)264 void AudioBufferFlacEncDemo::HandleEOS(const uint32_t &index)
265 {
266 OH_AudioCodec_PushInputBuffer(audioEnc_, index);
267 signal_->inQueue_.pop();
268 signal_->inBufferQueue_.pop();
269 }
270
GetFrameBytes()271 static int32_t GetFrameBytes()
272 {
273 auto bitsPerSamples = (SAMPLE_FORMAT == AudioSampleFormat::SAMPLE_S16LE) ? 2 : 4;
274 auto iter = FRAME_BYTES_MAP.find(SAMPLE_RATE);
275 uint32_t frameSize = DEFAULT_FRAME_BYTES;
276 if (iter != FRAME_BYTES_MAP.end()) {
277 frameSize = iter->second;
278 }
279 int32_t frameBytes = CHANNEL_COUNT * bitsPerSamples * frameSize;
280 std::cout << "frameBytes : " << frameBytes << std::endl;
281 return frameBytes;
282 }
283
InputFunc()284 void AudioBufferFlacEncDemo::InputFunc()
285 {
286 auto frameBytes = GetFrameBytes();
287 DEMO_CHECK_AND_RETURN_LOG(inputFile_.is_open(), "Fatal: open file fail");
288 while (isRunning_.load()) {
289 unique_lock<mutex> lock(signal_->inMutex_);
290 signal_->inCond_.wait(lock, [this]() { return (signal_->inQueue_.size() > 0 || !isRunning_.load()); });
291 if (!isRunning_.load()) {
292 break;
293 }
294 uint32_t index = signal_->inQueue_.front();
295 auto buffer = signal_->inBufferQueue_.front();
296 DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
297 OH_AVCodecBufferAttr attr = {0, 0, 0, 0};
298 if (!inputFile_.eof()) {
299 inputFile_.read(reinterpret_cast<char *>(OH_AVBuffer_GetAddr(buffer)), frameBytes);
300 attr.size = frameBytes;
301 OH_AVBuffer_SetBufferAttr(buffer, &attr);
302 } else {
303 attr.size = 0;
304 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
305 OH_AVBuffer_SetBufferAttr(buffer, &attr);
306 std::cout << "EOS " << std::endl;
307 HandleEOS(index);
308 break;
309 }
310
311 int32_t ret = AVCS_ERR_OK;
312 if (isFirstFrame_) {
313 buffer->buffer_->flag_ = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
314 ret = OH_AudioCodec_PushInputBuffer(audioEnc_, index);
315 isFirstFrame_ = false;
316 } else {
317 buffer->buffer_->flag_ = AVCODEC_BUFFER_FLAGS_NONE;
318 ret = OH_AudioCodec_PushInputBuffer(audioEnc_, index);
319 }
320
321 signal_->inQueue_.pop();
322 signal_->inBufferQueue_.pop();
323 if (ret != AVCS_ERR_OK) {
324 cout << "Fatal error, exit" << endl;
325 isRunning_ = false;
326 break;
327 }
328 }
329 inputFile_.close();
330 }
331
OutputFunc()332 void AudioBufferFlacEncDemo::OutputFunc()
333 {
334 DEMO_CHECK_AND_RETURN_LOG(outputFile_.is_open(), "Fatal: open output file fail");
335 while (isRunning_.load()) {
336 unique_lock<mutex> lock(signal_->outMutex_);
337 signal_->outCond_.wait(lock, [this]() { return (signal_->outQueue_.size() > 0 || !isRunning_.load()); });
338
339 if (!isRunning_.load()) {
340 cout << "wait to stop, exit" << endl;
341 break;
342 }
343
344 uint32_t index = signal_->outQueue_.front();
345
346 OH_AVBuffer *data = signal_->outBufferQueue_.front();
347 if (data != nullptr) {
348 outputFile_.write(reinterpret_cast<char *>(OH_AVBuffer_GetAddr(data)), data->buffer_->memory_->GetSize());
349 } else {
350 cout << "OutputFunc OH_AVBuffer is nullptr" << endl;
351 continue;
352 }
353
354 if (data != nullptr &&
355 (data->buffer_->flag_ == AVCODEC_BUFFER_FLAGS_EOS || data->buffer_->memory_->GetSize() == 0)) {
356 cout << "encode eos" << endl;
357 isRunning_.store(false);
358 signal_->startCond_.notify_all();
359 }
360
361 signal_->outBufferQueue_.pop();
362 signal_->outQueue_.pop();
363 if (OH_AudioCodec_FreeOutputBuffer(audioEnc_, index) != AV_ERR_OK) {
364 cout << "Fatal: FreeOutputData fail" << endl;
365 break;
366 }
367
368 if (data->buffer_->flag_ == AVCODEC_BUFFER_FLAGS_EOS) {
369 cout << "encode eos" << endl;
370 isRunning_.store(false);
371 signal_->startCond_.notify_all();
372 }
373 }
374 outputFile_.close();
375 }
376