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