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_decoder_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 "securec.h"
28
29 using namespace OHOS;
30 using namespace OHOS::MediaAVCodec;
31 using namespace OHOS::MediaAVCodec::AudioDemo;
32 using namespace std;
33 namespace {
34 constexpr uint32_t CHANNEL_COUNT = 2;
35 constexpr uint32_t SAMPLE_RATE = 44100;
36 constexpr uint32_t DEFAULT_AAC_TYPE = 1;
37 constexpr int64_t BITS_RATE[TYPE_MAX] = {199000, 261000, 60000, 320000};
38 constexpr uint32_t AMRWB_SAMPLE_RATE = 16000;
39 constexpr uint32_t AMRNB_SAMPLE_RATE = 8000;
40 constexpr uint32_t OPUS_SAMPLE_RATE = 48000;
41 constexpr string_view INPUT_AAC_FILE_PATH = "/data/test/media/aac_2c_44100hz_199k.dat";
42 constexpr string_view OUTPUT_AAC_PCM_FILE_PATH = "/data/test/media/aac_2c_44100hz_199k.pcm";
43 constexpr string_view INPUT_FLAC_FILE_PATH = "/data/test/media/flac_2c_44100hz_261k.dat";
44 constexpr string_view OUTPUT_FLAC_PCM_FILE_PATH = "/data/test/media/flac_2c_44100hz_261k.pcm";
45 constexpr string_view INPUT_MP3_FILE_PATH = "/data/test/media/mp3_2c_44100hz_60k.dat";
46 constexpr string_view OUTPUT_MP3_PCM_FILE_PATH = "/data/test/media/mp3_2c_44100hz_60k.pcm";
47 constexpr string_view INPUT_VORBIS_FILE_PATH = "/data/test/media/vorbis_2c_44100hz_320k.dat";
48 constexpr string_view OUTPUT_VORBIS_PCM_FILE_PATH = "/data/test/media/vorbis_2c_44100hz_320k.pcm";
49 constexpr string_view INPUT_AMRNB_FILE_PATH = "/data/test/media/voice_amrnb_10200.dat";
50 constexpr string_view OUTPUT_AMRNB_PCM_FILE_PATH = "/data/test/media/voice_amrnb_10200.pcm";
51 constexpr string_view INPUT_AMRWB_FILE_PATH = "/data/test/media/voice_amrwb_23850.dat";
52 constexpr string_view OUTPUT_AMRWB_PCM_FILE_PATH = "/data/test/media/voice_amrwb_23850.pcm";
53 constexpr string_view INPUT_OPUS_FILE_PATH = "/data/test/media/opus_48000.dat";
54 constexpr string_view OUTPUT_OPUS_PCM_FILE_PATH = "/data/test/media/opus_48000.pcm";
55 constexpr string_view INPUT_G711MU_FILE_PATH = "/data/test/media/g711mu_8kHz.dat";
56 constexpr string_view OUTPUT_G711MU_PCM_FILE_PATH = "/data/test/media/g711mu_8kHz_decode.pcm";
57 } // namespace
58
OnError(OH_AVCodec * codec,int32_t errorCode,void * userData)59 static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData)
60 {
61 (void)codec;
62 (void)errorCode;
63 (void)userData;
64 cout << "Error received, errorCode:" << errorCode << endl;
65 }
66
OnOutputFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)67 static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
68 {
69 (void)codec;
70 (void)format;
71 (void)userData;
72 cout << "OnOutputFormatChanged received" << endl;
73 }
74
OnInputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)75 static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
76 {
77 (void)codec;
78 ADecSignal *signal = static_cast<ADecSignal *>(userData);
79 unique_lock<mutex> lock(signal->inMutex_);
80 signal->inQueue_.push(index);
81 signal->inBufferQueue_.push(data);
82 signal->inCond_.notify_all();
83 }
84
OnOutputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)85 static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
86 void *userData)
87 {
88 (void)codec;
89 ADecSignal *signal = static_cast<ADecSignal *>(userData);
90 unique_lock<mutex> lock(signal->outMutex_);
91 signal->outQueue_.push(index);
92 signal->outBufferQueue_.push(data);
93 if (attr) {
94 signal->attrQueue_.push(*attr);
95 } else {
96 cout << "OnOutputBufferAvailable error, attr is nullptr!" << endl;
97 }
98 signal->outCond_.notify_all();
99 }
100
InitFile(AudioFormatType audioType)101 bool ADecDemo::InitFile(AudioFormatType audioType)
102 {
103 if (audioType == TYPE_AAC) {
104 inputFile_.open(INPUT_AAC_FILE_PATH, std::ios::binary);
105 pcmOutputFile_.open(OUTPUT_AAC_PCM_FILE_PATH.data(), std::ios::out | std::ios::binary);
106 } else if (audioType == TYPE_FLAC) {
107 inputFile_.open(INPUT_FLAC_FILE_PATH, std::ios::binary);
108 pcmOutputFile_.open(OUTPUT_FLAC_PCM_FILE_PATH.data(), std::ios::out | std::ios::binary);
109 } else if (audioType == TYPE_MP3) {
110 inputFile_.open(INPUT_MP3_FILE_PATH, std::ios::binary);
111 pcmOutputFile_.open(OUTPUT_MP3_PCM_FILE_PATH.data(), std::ios::out | std::ios::binary);
112 } else if (audioType == TYPE_VORBIS) {
113 inputFile_.open(INPUT_VORBIS_FILE_PATH, std::ios::binary);
114 pcmOutputFile_.open(OUTPUT_VORBIS_PCM_FILE_PATH.data(), std::ios::out | std::ios::binary);
115 } else if (audioType == TYPE_AMRNB) {
116 inputFile_.open(INPUT_AMRNB_FILE_PATH, std::ios::binary);
117 pcmOutputFile_.open(OUTPUT_AMRNB_PCM_FILE_PATH.data(), std::ios::out | std::ios::binary);
118 } else if (audioType == TYPE_AMRWB) {
119 inputFile_.open(INPUT_AMRWB_FILE_PATH, std::ios::binary);
120 pcmOutputFile_.open(OUTPUT_AMRWB_PCM_FILE_PATH.data(), std::ios::out | std::ios::binary);
121 } else if (audioType == TYPE_OPUS) {
122 inputFile_.open(INPUT_OPUS_FILE_PATH, std::ios::binary);
123 pcmOutputFile_.open(OUTPUT_OPUS_PCM_FILE_PATH.data(), std::ios::out | std::ios::binary);
124 } else if (audioType == TYPE_G711MU) {
125 inputFile_.open(INPUT_G711MU_FILE_PATH, std::ios::binary);
126 pcmOutputFile_.open(OUTPUT_G711MU_PCM_FILE_PATH.data(), std::ios::out | std::ios::binary);
127 } else {
128 std::cout << "audio format type not support\n";
129 return false;
130 }
131 DEMO_CHECK_AND_RETURN_RET_LOG(inputFile_.is_open(), false, "Fatal: open input file failed");
132 DEMO_CHECK_AND_RETURN_RET_LOG(pcmOutputFile_.is_open(), false, "Fatal: open output file failed");
133 return true;
134 }
135
RunCase(AudioFormatType audioType)136 void ADecDemo::RunCase(AudioFormatType audioType)
137 {
138 DEMO_CHECK_AND_RETURN_LOG(InitFile(audioType), "Fatal: InitFile file failed");
139 audioType_ = audioType;
140 DEMO_CHECK_AND_RETURN_LOG(CreateDec() == AVCS_ERR_OK, "Fatal: CreateDec fail");
141 OH_AVFormat *format = OH_AVFormat_Create();
142 int32_t channelCount = 1;
143 int32_t sampleRate = SAMPLE_RATE;
144 if (audioType == TYPE_AAC) {
145 channelCount = CHANNEL_COUNT;
146 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_AAC_IS_ADTS.data(), DEFAULT_AAC_TYPE);
147 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(),
148 OH_BitsPerSample::SAMPLE_S16LE);
149 } else if (audioType == TYPE_AMRNB || audioType == TYPE_G711MU) {
150 sampleRate = AMRNB_SAMPLE_RATE;
151 } else if (audioType == TYPE_AMRWB) {
152 sampleRate = AMRWB_SAMPLE_RATE;
153 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(),
154 OH_BitsPerSample::SAMPLE_S16LE);
155 } else if (audioType == TYPE_OPUS) {
156 sampleRate = OPUS_SAMPLE_RATE;
157 }
158 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), channelCount);
159 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), sampleRate);
160 OH_AVFormat_SetLongValue(format, MediaDescriptionKey::MD_KEY_BITRATE.data(), BITS_RATE[audioType]);
161 if (audioType == TYPE_VORBIS) {
162 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(),
163 OH_BitsPerSample::SAMPLE_S16LE);
164 int64_t extradataSize;
165 DEMO_CHECK_AND_RETURN_LOG(inputFile_.is_open(), "Fatal: file is not open");
166 inputFile_.read(reinterpret_cast<char *>(&extradataSize), sizeof(int64_t));
167 DEMO_CHECK_AND_RETURN_LOG(inputFile_.gcount() == sizeof(int64_t), "Fatal: read extradataSize bytes error");
168 if (extradataSize < 0) {
169 return;
170 }
171 char buffer[extradataSize];
172 inputFile_.read(buffer, extradataSize);
173 DEMO_CHECK_AND_RETURN_LOG(inputFile_.gcount() == extradataSize, "Fatal: read extradata bytes error");
174 OH_AVFormat_SetBuffer(format, MediaDescriptionKey::MD_KEY_CODEC_CONFIG.data(), (uint8_t *)buffer,
175 extradataSize);
176 }
177 DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail");
178 DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail");
179
180 unique_lock<mutex> lock(signal_->startMutex_);
181 signal_->startCond_.wait(lock, [this]() { return (!(isRunning_.load())); });
182
183 DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail");
184 DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail");
185 }
186
ADecDemo()187 ADecDemo::ADecDemo() : audioDec_(nullptr), signal_(nullptr), audioType_(TYPE_AAC) {}
188
~ADecDemo()189 ADecDemo::~ADecDemo()
190 {
191 if (signal_) {
192 delete signal_;
193 signal_ = nullptr;
194 }
195 if (inputFile_.is_open()) {
196 inputFile_.close();
197 }
198 if (pcmOutputFile_.is_open()) {
199 pcmOutputFile_.close();
200 }
201 }
202
CreateDec()203 int32_t ADecDemo::CreateDec()
204 {
205 if (audioType_ == TYPE_AAC) {
206 audioDec_ = OH_AudioDecoder_CreateByName((AVCodecCodecName::AUDIO_DECODER_AAC_NAME).data());
207 } else if (audioType_ == TYPE_FLAC) {
208 audioDec_ = OH_AudioDecoder_CreateByName((AVCodecCodecName::AUDIO_DECODER_FLAC_NAME).data());
209 } else if (audioType_ == TYPE_MP3) {
210 audioDec_ = OH_AudioDecoder_CreateByName((AVCodecCodecName::AUDIO_DECODER_MP3_NAME).data());
211 } else if (audioType_ == TYPE_VORBIS) {
212 audioDec_ = OH_AudioDecoder_CreateByName((AVCodecCodecName::AUDIO_DECODER_VORBIS_NAME).data());
213 } else if (audioType_ == TYPE_AMRNB) {
214 audioDec_ = OH_AudioDecoder_CreateByName((AVCodecCodecName::AUDIO_DECODER_AMRNB_NAME).data());
215 } else if (audioType_ == TYPE_AMRWB) {
216 audioDec_ = OH_AudioDecoder_CreateByName((AVCodecCodecName::AUDIO_DECODER_AMRWB_NAME).data());
217 } else if (audioType_ == TYPE_OPUS) {
218 audioDec_ = OH_AudioDecoder_CreateByName((AVCodecCodecName::AUDIO_DECODER_OPUS_NAME).data());
219 } else if (audioType_ == TYPE_G711MU) {
220 audioDec_ = OH_AudioDecoder_CreateByName((AVCodecCodecName::AUDIO_DECODER_G711MU_NAME).data());
221 } else {
222 return AVCS_ERR_INVALID_VAL;
223 }
224 DEMO_CHECK_AND_RETURN_RET_LOG(audioDec_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail");
225
226 signal_ = new ADecSignal();
227 DEMO_CHECK_AND_RETURN_RET_LOG(signal_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
228
229 cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable};
230 int32_t ret = OH_AudioDecoder_SetCallback(audioDec_, cb_, signal_);
231 DEMO_CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, "Fatal: SetCallback fail");
232
233 return AVCS_ERR_OK;
234 }
235
Configure(OH_AVFormat * format)236 int32_t ADecDemo::Configure(OH_AVFormat *format)
237 {
238 return OH_AudioDecoder_Configure(audioDec_, format);
239 }
240
Start()241 int32_t ADecDemo::Start()
242 {
243 isRunning_.store(true);
244
245 inputLoop_ = make_unique<thread>(&ADecDemo::InputFunc, this);
246 DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
247
248 outputLoop_ = make_unique<thread>(&ADecDemo::OutputFunc, this);
249 DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
250
251 return OH_AudioDecoder_Start(audioDec_);
252 }
253
Stop()254 int32_t ADecDemo::Stop()
255 {
256 isRunning_.store(false);
257 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
258 {
259 unique_lock<mutex> lock(signal_->inMutex_);
260 signal_->inCond_.notify_all();
261 }
262 inputLoop_->join();
263 inputLoop_ = nullptr;
264 while (!signal_->inQueue_.empty()) {
265 signal_->inQueue_.pop();
266 }
267 while (!signal_->inBufferQueue_.empty()) {
268 signal_->inBufferQueue_.pop();
269 }
270 }
271
272 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
273 {
274 unique_lock<mutex> lock(signal_->outMutex_);
275 signal_->outCond_.notify_all();
276 }
277 outputLoop_->join();
278 outputLoop_ = nullptr;
279 while (!signal_->outQueue_.empty()) {
280 signal_->outQueue_.pop();
281 }
282 while (!signal_->attrQueue_.empty()) {
283 signal_->attrQueue_.pop();
284 }
285 while (!signal_->outBufferQueue_.empty()) {
286 signal_->outBufferQueue_.pop();
287 }
288 }
289 std::cout << "start stop!\n";
290 return OH_AudioDecoder_Stop(audioDec_);
291 }
292
Flush()293 int32_t ADecDemo::Flush()
294 {
295 isRunning_.store(false);
296 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
297 {
298 unique_lock<mutex> lock(signal_->inMutex_);
299 signal_->inCond_.notify_all();
300 }
301 inputLoop_->join();
302 inputLoop_ = nullptr;
303 while (!signal_->inQueue_.empty()) {
304 signal_->inQueue_.pop();
305 }
306 while (!signal_->inBufferQueue_.empty()) {
307 signal_->inBufferQueue_.pop();
308 }
309 std::cout << "clear input buffer!\n";
310 }
311
312 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
313 {
314 unique_lock<mutex> lock(signal_->outMutex_);
315 signal_->outCond_.notify_all();
316 }
317 outputLoop_->join();
318 outputLoop_ = nullptr;
319 while (!signal_->outQueue_.empty()) {
320 signal_->outQueue_.pop();
321 }
322 while (!signal_->attrQueue_.empty()) {
323 signal_->attrQueue_.pop();
324 }
325 while (!signal_->outBufferQueue_.empty()) {
326 signal_->outBufferQueue_.pop();
327 }
328 std::cout << "clear output buffer!\n";
329 }
330 return OH_AudioDecoder_Flush(audioDec_);
331 }
332
Reset()333 int32_t ADecDemo::Reset()
334 {
335 return OH_AudioDecoder_Reset(audioDec_);
336 }
337
Release()338 int32_t ADecDemo::Release()
339 {
340 return OH_AudioDecoder_Destroy(audioDec_);
341 }
342
HandleInputEOS(const uint32_t index)343 void ADecDemo::HandleInputEOS(const uint32_t index)
344 {
345 OH_AVCodecBufferAttr info;
346 info.size = 0;
347 info.offset = 0;
348 info.pts = 0;
349 info.flags = AVCODEC_BUFFER_FLAGS_EOS;
350 OH_AudioDecoder_PushInputData(audioDec_, index, info);
351 signal_->inBufferQueue_.pop();
352 signal_->inQueue_.pop();
353 }
354
HandleNormalInput(const uint32_t & index,const int64_t pts,const size_t size)355 int32_t ADecDemo::HandleNormalInput(const uint32_t &index, const int64_t pts, const size_t size)
356 {
357 OH_AVCodecBufferAttr info;
358 info.size = size;
359 info.offset = 0;
360 info.pts = pts;
361
362 int32_t ret = AVCS_ERR_OK;
363 if (isFirstFrame_) {
364 info.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
365 ret = OH_AudioDecoder_PushInputData(audioDec_, index, info);
366 isFirstFrame_ = false;
367 } else {
368 info.flags = AVCODEC_BUFFER_FLAGS_NONE;
369 ret = OH_AudioDecoder_PushInputData(audioDec_, index, info);
370 }
371 signal_->inQueue_.pop();
372 signal_->inBufferQueue_.pop();
373 frameCount_++;
374 return ret;
375 }
376
InputFunc()377 void ADecDemo::InputFunc()
378 {
379 int64_t size;
380 int64_t pts;
381
382 while (isRunning_.load()) {
383 unique_lock<mutex> lock(signal_->inMutex_);
384 signal_->inCond_.wait(lock, [this]() { return (signal_->inQueue_.size() > 0 || !isRunning_.load()); });
385
386 if (!isRunning_.load()) {
387 break;
388 }
389
390 uint32_t index = signal_->inQueue_.front();
391 auto buffer = signal_->inBufferQueue_.front();
392 DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
393 inputFile_.read(reinterpret_cast<char *>(&size), sizeof(size));
394 if (inputFile_.eof() || inputFile_.gcount() == 0 || size == 0) {
395 HandleInputEOS(index);
396 std::cout << "end buffer\n";
397 break;
398 }
399 DEMO_CHECK_AND_BREAK_LOG(inputFile_.gcount() == sizeof(size), "Fatal: read size fail");
400 inputFile_.read(reinterpret_cast<char *>(&pts), sizeof(pts));
401 DEMO_CHECK_AND_BREAK_LOG(inputFile_.gcount() == sizeof(pts), "Fatal: read pts fail");
402 inputFile_.read((char *)OH_AVMemory_GetAddr(buffer), size);
403 DEMO_CHECK_AND_BREAK_LOG(inputFile_.gcount() == size, "Fatal: read buffer fail");
404
405 int32_t ret = HandleNormalInput(index, pts, size);
406 if (ret != AVCS_ERR_OK) {
407 cout << "Fatal error, exit" << endl;
408 break;
409 }
410 }
411 inputFile_.close();
412 }
413
OutputFunc()414 void ADecDemo::OutputFunc()
415 {
416 DEMO_CHECK_AND_RETURN_LOG(pcmOutputFile_.is_open(), "Fatal: output file failedis not open");
417 while (isRunning_.load()) {
418 unique_lock<mutex> lock(signal_->outMutex_);
419 signal_->outCond_.wait(lock, [this]() { return (signal_->outQueue_.size() > 0 || !isRunning_.load()); });
420
421 if (!isRunning_.load()) {
422 cout << "wait to stop, exit" << endl;
423 break;
424 }
425
426 uint32_t index = signal_->outQueue_.front();
427 OH_AVCodecBufferAttr attr = signal_->attrQueue_.front();
428 OH_AVMemory *data = signal_->outBufferQueue_.front();
429 if (attr.flags != AVCODEC_BUFFER_FLAGS_EOS && data != nullptr) {
430 pcmOutputFile_.write(reinterpret_cast<char *>(OH_AVMemory_GetAddr(data)), attr.size);
431 }
432
433 if (attr.flags == AVCODEC_BUFFER_FLAGS_EOS) {
434 cout << "decode eos" << endl;
435 isRunning_.store(false);
436 signal_->startCond_.notify_all();
437 }
438 signal_->outBufferQueue_.pop();
439 signal_->attrQueue_.pop();
440 signal_->outQueue_.pop();
441 if (OH_AudioDecoder_FreeOutputData(audioDec_, index) != AV_ERR_OK) {
442 cout << "Fatal: FreeOutputData fail" << endl;
443 break;
444 }
445 }
446 pcmOutputFile_.close();
447 }
448