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_flac_encoder_demo.h"
17 #include <iostream>
18 #include <unistd.h>
19 #include "securec.h"
20 #include "avcodec_common.h"
21 #include "avcodec_errors.h"
22 #include "media_description.h"
23 #include "native_avformat.h"
24 #include "demo_log.h"
25 #include "avcodec_codec_name.h"
26 #include "ffmpeg_converter.h"
27
28 using namespace OHOS;
29 using namespace OHOS::MediaAVCodec;
30 using namespace OHOS::MediaAVCodec::AudioFlacDemo;
31 using namespace std;
32 namespace {
33 constexpr uint32_t CHANNEL_COUNT = 2;
34 constexpr uint32_t SAMPLE_RATE = 44100;
35 constexpr uint32_t BITS_RATE = 261000;
36 constexpr uint32_t BITS_PER_CODED_SAMPLE = AudioSampleFormat::SAMPLE_S16LE;
37 constexpr uint32_t FRAME_DURATION_US = 33000;
38 constexpr uint32_t CHANNEL_LAYOUT = AudioChannelLayout::STEREO;
39 constexpr int32_t SAMPLE_FORMAT = AudioSampleFormat::SAMPLE_S16LE;
40 constexpr int32_t COMPLIANCE_LEVEL = 0;
41 constexpr int32_t DEFAULT_FRAME_BYTES = 1152;
42 static std::map<uint32_t, uint32_t> FRAME_BYTES_MAP = {{8000, 576}, {16000, 1152}, {22050, 2304}, {24000, 2304},
43 {32000, 2304}, {44100, 4608}, {48000, 4608}, {88200, 8192},
44 {96000, 8192}};
45
46 constexpr string_view INPUT_FILE_PATH = "/data/test/media/flac_2c_44100hz_261k.pcm";
47 constexpr string_view OUTPUT_FILE_PATH = "/data/test/media/flac_encoder_test.flac";
48 } // namespace
49
OnError(OH_AVCodec * codec,int32_t errorCode,void * userData)50 static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData)
51 {
52 (void)codec;
53 (void)errorCode;
54 (void)userData;
55 cout << "Error received, errorCode:" << errorCode << endl;
56 }
57
OnOutputFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)58 static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
59 {
60 (void)codec;
61 (void)format;
62 (void)userData;
63 cout << "OnOutputFormatChanged received" << endl;
64 }
65
OnInputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)66 static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
67 {
68 (void)codec;
69 AEncSignal *signal = static_cast<AEncSignal *>(userData);
70 unique_lock<mutex> lock(signal->inMutex_);
71 signal->inQueue_.push(index);
72 signal->inBufferQueue_.push(data);
73 signal->inCond_.notify_all();
74 }
75
OnOutputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)76 static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
77 void *userData)
78 {
79 (void)codec;
80 AEncSignal *signal = static_cast<AEncSignal *>(userData);
81 unique_lock<mutex> lock(signal->outMutex_);
82 signal->outQueue_.push(index);
83 signal->outBufferQueue_.push(data);
84 if (attr) {
85 signal->attrQueue_.push(*attr);
86 } else {
87 cout << "OnOutputBufferAvailable error, attr is nullptr!" << endl;
88 }
89 signal->outCond_.notify_all();
90 }
91
RunCase()92 void AEncFlacDemo::RunCase()
93 {
94 DEMO_CHECK_AND_RETURN_LOG(CreateEnc() == AVCS_ERR_OK, "Fatal: CreateEnc fail");
95
96 OH_AVFormat *format = OH_AVFormat_Create();
97 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), CHANNEL_COUNT);
98 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), SAMPLE_RATE);
99 OH_AVFormat_SetLongValue(format, MediaDescriptionKey::MD_KEY_BITRATE.data(), BITS_RATE);
100 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_BITS_PER_CODED_SAMPLE.data(), BITS_PER_CODED_SAMPLE);
101 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), SAMPLE_FORMAT);
102 OH_AVFormat_SetLongValue(format, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CHANNEL_LAYOUT);
103 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_COMPLIANCE_LEVEL.data(), COMPLIANCE_LEVEL);
104
105 DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail");
106
107 DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail");
108
109 {
110 unique_lock<mutex> lock(signal_->startMutex_);
111 signal_->startCond_.wait(lock, [this]() { return (!(isRunning_.load())); });
112 }
113
114 DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail");
115 DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail");
116 }
117
AEncFlacDemo()118 AEncFlacDemo::AEncFlacDemo() : isRunning_(false), audioEnc_(nullptr), signal_(nullptr), frameCount_(0)
119 {
120 inputFile_ = std::make_unique<std::ifstream>(INPUT_FILE_PATH, std::ios::binary);
121 outputFile_ = std::make_unique<std::ofstream>(OUTPUT_FILE_PATH, std::ios::binary);
122 }
123
~AEncFlacDemo()124 AEncFlacDemo::~AEncFlacDemo()
125 {
126 if (signal_) {
127 delete signal_;
128 signal_ = nullptr;
129 }
130 }
131
CreateEnc()132 int32_t AEncFlacDemo::CreateEnc()
133 {
134 audioEnc_ = OH_AudioEncoder_CreateByName((AVCodecCodecName::AUDIO_ENCODER_FLAC_NAME).data());
135 DEMO_CHECK_AND_RETURN_RET_LOG(audioEnc_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail");
136
137 signal_ = new AEncSignal();
138 DEMO_CHECK_AND_RETURN_RET_LOG(signal_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
139
140 cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable};
141 int32_t ret = OH_AudioEncoder_SetCallback(audioEnc_, cb_, signal_);
142 DEMO_CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, "Fatal: SetCallback fail");
143
144 return AVCS_ERR_OK;
145 }
146
Configure(OH_AVFormat * format)147 int32_t AEncFlacDemo::Configure(OH_AVFormat *format)
148 {
149 return OH_AudioEncoder_Configure(audioEnc_, format);
150 }
151
Start()152 int32_t AEncFlacDemo::Start()
153 {
154 isRunning_.store(true);
155
156 inputLoop_ = make_unique<thread>(&AEncFlacDemo::InputFunc, this);
157 DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
158
159 outputLoop_ = make_unique<thread>(&AEncFlacDemo::OutputFunc, this);
160 DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
161
162 return OH_AudioEncoder_Start(audioEnc_);
163 }
164
Stop()165 int32_t AEncFlacDemo::Stop()
166 {
167 isRunning_.store(false);
168
169 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
170 {
171 unique_lock<mutex> lock(signal_->inMutex_);
172 signal_->inCond_.notify_all();
173 }
174 inputLoop_->join();
175 inputLoop_ = nullptr;
176 while (!signal_->inQueue_.empty()) {
177 signal_->inQueue_.pop();
178 }
179 while (!signal_->inBufferQueue_.empty()) {
180 signal_->inBufferQueue_.pop();
181 }
182 }
183
184 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
185 {
186 unique_lock<mutex> lock(signal_->outMutex_);
187 signal_->outCond_.notify_all();
188 }
189 outputLoop_->join();
190 outputLoop_ = nullptr;
191 while (!signal_->outQueue_.empty()) {
192 signal_->outQueue_.pop();
193 }
194 while (!signal_->attrQueue_.empty()) {
195 signal_->attrQueue_.pop();
196 }
197 while (!signal_->outBufferQueue_.empty()) {
198 signal_->outBufferQueue_.pop();
199 }
200 }
201
202 return OH_AudioEncoder_Stop(audioEnc_);
203 }
204
Flush()205 int32_t AEncFlacDemo::Flush()
206 {
207 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
208 {
209 unique_lock<mutex> lock(signal_->inMutex_);
210 signal_->inCond_.notify_all();
211 }
212 inputLoop_->join();
213 inputLoop_ = nullptr;
214 while (!signal_->inQueue_.empty()) {
215 signal_->inQueue_.pop();
216 }
217 while (!signal_->inBufferQueue_.empty()) {
218 signal_->inBufferQueue_.pop();
219 }
220 std::cout << "clear input buffer!\n";
221 }
222
223 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
224 {
225 unique_lock<mutex> lock(signal_->outMutex_);
226 signal_->outCond_.notify_all();
227 }
228 outputLoop_->join();
229 outputLoop_ = nullptr;
230 while (!signal_->outQueue_.empty()) {
231 signal_->outQueue_.pop();
232 }
233 while (!signal_->attrQueue_.empty()) {
234 signal_->attrQueue_.pop();
235 }
236 while (!signal_->outBufferQueue_.empty()) {
237 signal_->outBufferQueue_.pop();
238 }
239 std::cout << "clear output buffer!\n";
240 }
241 return OH_AudioEncoder_Flush(audioEnc_);
242 }
243
Reset()244 int32_t AEncFlacDemo::Reset()
245 {
246 return OH_AudioEncoder_Reset(audioEnc_);
247 }
248
Release()249 int32_t AEncFlacDemo::Release()
250 {
251 return OH_AudioEncoder_Destroy(audioEnc_);
252 }
253
HandleEOS(const uint32_t & index)254 void AEncFlacDemo::HandleEOS(const uint32_t &index)
255 {
256 OH_AVCodecBufferAttr info;
257 info.size = 0;
258 info.offset = 0;
259 info.pts = 0;
260 info.flags = AVCODEC_BUFFER_FLAGS_EOS;
261 OH_AudioEncoder_PushInputData(audioEnc_, index, info);
262 signal_->inQueue_.pop();
263 signal_->inBufferQueue_.pop();
264 }
265
GetFrameBytes()266 static int32_t GetFrameBytes()
267 {
268 auto bitsPerSamples = (SAMPLE_FORMAT == AudioSampleFormat::SAMPLE_S16LE) ? 2 : 4;
269 auto iter = FRAME_BYTES_MAP.find(SAMPLE_RATE);
270 uint32_t frameSize = DEFAULT_FRAME_BYTES;
271 if (iter != FRAME_BYTES_MAP.end()) {
272 frameSize = iter->second;
273 }
274 int32_t frameBytes = CHANNEL_COUNT * bitsPerSamples * frameSize;
275 return frameBytes;
276 }
277
InputFunc()278 void AEncFlacDemo::InputFunc()
279 {
280 auto frameBytes = GetFrameBytes();
281 DEMO_CHECK_AND_RETURN_LOG(inputFile_ != nullptr && inputFile_->is_open(), "Fatal: open file fail");
282 while (isRunning_.load()) {
283 unique_lock<mutex> lock(signal_->inMutex_);
284 signal_->inCond_.wait(lock, [this]() { return (signal_->inQueue_.size() > 0 || !isRunning_.load()); });
285 if (!isRunning_.load()) {
286 break;
287 }
288 uint32_t index = signal_->inQueue_.front();
289 auto buffer = signal_->inBufferQueue_.front();
290 DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
291 if (!inputFile_->eof()) {
292 inputFile_->read((char *)OH_AVMemory_GetAddr(buffer), frameBytes);
293 } else {
294 HandleEOS(index);
295 break;
296 }
297 DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
298 OH_AVCodecBufferAttr info;
299 info.size = frameBytes;
300 info.offset = 0;
301
302 int32_t ret = AVCS_ERR_OK;
303 if (isFirstFrame_) {
304 info.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
305 ret = OH_AudioEncoder_PushInputData(audioEnc_, index, info);
306 isFirstFrame_ = false;
307 } else {
308 info.flags = AVCODEC_BUFFER_FLAGS_NONE;
309 ret = OH_AudioEncoder_PushInputData(audioEnc_, index, info);
310 }
311
312 timeStamp_ += FRAME_DURATION_US;
313 signal_->inQueue_.pop();
314 signal_->inBufferQueue_.pop();
315 frameCount_++;
316 if (ret != AVCS_ERR_OK) {
317 cout << "Fatal error, exit" << endl;
318 isRunning_ = false;
319 break;
320 }
321 }
322 inputFile_->close();
323 }
324
OutputFunc()325 void AEncFlacDemo::OutputFunc()
326 {
327 DEMO_CHECK_AND_RETURN_LOG(outputFile_ != nullptr && outputFile_->is_open(), "Fatal: open output file fail");
328 while (isRunning_.load()) {
329 unique_lock<mutex> lock(signal_->outMutex_);
330 signal_->outCond_.wait(lock, [this]() { return (signal_->outQueue_.size() > 0 || !isRunning_.load()); });
331
332 if (!isRunning_.load()) {
333 cout << "wait to stop, exit" << endl;
334 break;
335 }
336
337 uint32_t index = signal_->outQueue_.front();
338
339 OH_AVCodecBufferAttr attr = signal_->attrQueue_.front();
340 OH_AVMemory *data = signal_->outBufferQueue_.front();
341 if (data != nullptr) {
342 outputFile_->write(reinterpret_cast<char *>(OH_AVMemory_GetAddr(data)), attr.size);
343 }
344 if (attr.flags == AVCODEC_BUFFER_FLAGS_EOS || attr.size == 0) {
345 cout << "encode eos" << endl;
346 isRunning_.store(false);
347 signal_->startCond_.notify_all();
348 }
349
350 signal_->outBufferQueue_.pop();
351 signal_->attrQueue_.pop();
352 signal_->outQueue_.pop();
353 if (OH_AudioEncoder_FreeOutputData(audioEnc_, index) != AV_ERR_OK) {
354 cout << "Fatal: FreeOutputData fail" << endl;
355 break;
356 }
357 }
358 outputFile_->close();
359 }
360