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_inner_demo.h"
17 #include <iostream>
18 #include <unistd.h>
19 #include "avcodec_codec_name.h"
20 #include "avcodec_errors.h"
21 #include "avcodec_common.h"
22 #include "demo_log.h"
23 #include "media_description.h"
24 #include "securec.h"
25 
26 using namespace OHOS;
27 using namespace OHOS::MediaAVCodec;
28 using namespace OHOS::MediaAVCodec::InnerAudioDemo;
29 using namespace std;
30 namespace {
31 constexpr uint32_t CHANNEL_COUNT = 2;
32 constexpr uint32_t SAMPLE_RATE = 44100;
33 constexpr uint32_t BITS_RATE = 320000;
34 constexpr string_view INPUT_FILE_PATH = "/data/test/media/vorbis_2c_44100hz_320k.dat";
35 constexpr string_view OUTPUT_FILE_PATH = "/data/test/media/decode_ogg.pcm";
36 constexpr uint32_t TMP_BUFFER_SIZE = 4096;
37 } // namespace
38 
RunCase()39 void ADecInnerDemo::RunCase()
40 {
41     inputFile_.open(INPUT_FILE_PATH, std::ios::binary);
42     DEMO_CHECK_AND_RETURN_LOG(inputFile_.is_open(), "Fatal: open file failed");
43 
44     DEMO_CHECK_AND_RETURN_LOG(CreateDec() == AVCS_ERR_OK, "Fatal: CreateDec fail");
45 
46     Format format;
47     format.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, CHANNEL_COUNT);
48     format.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, SAMPLE_RATE);
49     format.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, BITS_RATE);
50 
51     // extradata for vorbis
52     char buffer[TMP_BUFFER_SIZE]; // 临时buffer,仅测试vorbis时需要
53     int64_t extradataSize;
54     inputFile_.read((char *)&extradataSize, sizeof(int64_t));
55     DEMO_CHECK_AND_RETURN_LOG(inputFile_.gcount() == sizeof(int64_t), "Fatal: read extradataSize bytes error");
56 
57     DEMO_CHECK_AND_RETURN_LOG(extradataSize <= TMP_BUFFER_SIZE, "Fatal: buffer not large enough");
58     inputFile_.read(buffer, extradataSize);
59     DEMO_CHECK_AND_RETURN_LOG(inputFile_.gcount() == extradataSize, "Fatal: read extradata bytes error");
60     format.PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG.data(), (uint8_t *)buffer, extradataSize);
61 
62     DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail");
63 
64     DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail");
65 
66     unique_lock<mutex> lock(signal_->startMutex_);
67     signal_->startCond_.wait(lock, [this]() { return (!(isRunning_.load())); });
68 
69     DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail");
70     DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail");
71 }
72 
CreateDec()73 int32_t ADecInnerDemo::CreateDec()
74 {
75     audioDec_ = AudioDecoderFactory::CreateByName((AVCodecCodecName::AUDIO_DECODER_VORBIS_NAME).data());
76     DEMO_CHECK_AND_RETURN_RET_LOG(audioDec_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail");
77 
78     signal_ = make_shared<ADecSignal>();
79 
80     cb_ = make_unique<ADecDemoCallback>(signal_);
81     DEMO_CHECK_AND_RETURN_RET_LOG(cb_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
82     DEMO_CHECK_AND_RETURN_RET_LOG(audioDec_->SetCallback(cb_) == AVCS_ERR_OK, AVCS_ERR_UNKNOWN,
83                                   "Fatal: SetCallback fail");
84 
85     return AVCS_ERR_OK;
86 }
87 
Configure(const Format & format)88 int32_t ADecInnerDemo::Configure(const Format &format)
89 {
90     return audioDec_->Configure(format);
91 }
92 
Start()93 int32_t ADecInnerDemo::Start()
94 {
95     isRunning_.store(true);
96 
97     inputLoop_ = make_unique<thread>(&ADecInnerDemo::InputFunc, this);
98     DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
99 
100     outputLoop_ = make_unique<thread>(&ADecInnerDemo::OutputFunc, this);
101     DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
102 
103     return audioDec_->Start();
104 }
105 
Stop()106 int32_t ADecInnerDemo::Stop()
107 {
108     isRunning_.store(false);
109 
110     if (inputLoop_ != nullptr && inputLoop_->joinable()) {
111         {
112             unique_lock<mutex> lock(signal_->inMutex_);
113             signal_->inQueue_.push(0);
114             signal_->inCond_.notify_all();
115         }
116         inputLoop_->join();
117         inputLoop_.reset();
118     }
119 
120     if (outputLoop_ != nullptr && outputLoop_->joinable()) {
121         {
122             unique_lock<mutex> lock(signal_->outMutex_);
123             signal_->outQueue_.push(0);
124             signal_->outCond_.notify_all();
125         }
126         outputLoop_->join();
127         outputLoop_.reset();
128     }
129 
130     return audioDec_->Stop();
131 }
132 
Flush()133 int32_t ADecInnerDemo::Flush()
134 {
135     return audioDec_->Flush();
136 }
137 
Reset()138 int32_t ADecInnerDemo::Reset()
139 {
140     return audioDec_->Reset();
141 }
142 
Release()143 int32_t ADecInnerDemo::Release()
144 {
145     return audioDec_->Release();
146 }
147 
HandleInputEOS(const uint32_t & index)148 void ADecInnerDemo::HandleInputEOS(const uint32_t &index)
149 {
150     AVCodecBufferInfo attr;
151     AVCodecBufferFlag flag;
152     attr.presentationTimeUs = 0;
153     attr.size = 0;
154     attr.offset = 0;
155     flag = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_EOS;
156     (void)audioDec_->QueueInputBuffer(index, attr, flag);
157     signal_->inQueue_.pop();
158     signal_->inBufferQueue_.pop();
159     std::cout << "end buffer\n";
160 }
161 
HandleNormalInput(const uint32_t & index,const int64_t & pts,const size_t & size)162 int32_t ADecInnerDemo::HandleNormalInput(const uint32_t &index, const int64_t &pts, const size_t &size)
163 {
164     AVCodecBufferInfo attr;
165     AVCodecBufferFlag flag;
166     attr.presentationTimeUs = pts;
167     attr.size = size;
168     attr.offset = 0;
169     flag = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE;
170     frameCount_++;
171     auto result = audioDec_->QueueInputBuffer(index, attr, flag);
172     signal_->inQueue_.pop();
173     signal_->inBufferQueue_.pop();
174     return result;
175 }
176 
InputFunc()177 void ADecInnerDemo::InputFunc()
178 {
179     int64_t size;
180     int64_t pts;
181     while (isRunning_.load()) {
182         std::unique_lock<std::mutex> lock(signal_->inMutex_);
183         signal_->inCond_.wait(lock, [this]() { return signal_->inQueue_.size() > 0; });
184         if (!isRunning_.load()) {
185             break;
186         }
187         uint32_t index = signal_->inQueue_.front();
188         std::shared_ptr<AVSharedMemory> buffer = signal_->inBufferQueue_.front();
189         if (buffer == nullptr) {
190             isRunning_.store(false);
191             std::cout << "buffer is null:" << index << "\n";
192             break;
193         }
194 
195         inputFile_.read((char *)&size, sizeof(size));
196         if (inputFile_.eof() || inputFile_.gcount() == 0) {
197             std::cout << "eof reached" << std::endl;
198             HandleInputEOS(index);
199             break;
200         }
201         DEMO_CHECK_AND_BREAK_LOG(inputFile_.gcount() == sizeof(size), "Fatal: read size fail");
202 
203         inputFile_.read((char *)&pts, sizeof(pts));
204         DEMO_CHECK_AND_BREAK_LOG(inputFile_.gcount() == sizeof(pts), "Fatal: read pts fail");
205         inputFile_.read((char *)buffer->GetBase(), size);
206         DEMO_CHECK_AND_BREAK_LOG(inputFile_.gcount() == size, "Fatal: read buffer fail");
207 
208         auto result = HandleNormalInput(index, pts, size);
209         if (result != AVCS_ERR_OK) {
210             std::cout << "QueueInputBuffer error:\n";
211             isRunning_ = false;
212             break;
213         }
214     }
215 }
216 
OutputFunc()217 void ADecInnerDemo::OutputFunc()
218 {
219     std::ofstream outputFile(OUTPUT_FILE_PATH.data(), std::ios::binary);
220     while (isRunning_.load()) {
221         unique_lock<mutex> lock(signal_->outMutex_);
222         signal_->outCond_.wait(lock, [this]() { return signal_->outQueue_.size() > 0; });
223 
224         if (!isRunning_.load()) {
225             break;
226         }
227 
228         uint32_t index = signal_->outQueue_.front();
229         auto buffer = signal_->outBufferQueue_.front();
230         if (buffer == nullptr) {
231             cout << "get output buffer failed" << endl;
232             isRunning_.store(false);
233             break;
234         }
235         auto attr = signal_->infoQueue_.front();
236         auto flag = signal_->flagQueue_.front();
237         if (flag == AVCODEC_BUFFER_FLAG_EOS) {
238             cout << "decode eos" << endl;
239             isRunning_.store(false);
240             signal_->startCond_.notify_all();
241         }
242         outputFile.write(reinterpret_cast<char *>(buffer->GetBase()), attr.size);
243         if (audioDec_->ReleaseOutputBuffer(index) != AVCS_ERR_OK) {
244             cout << "Fatal: ReleaseOutputBuffer fail" << endl;
245             break;
246         }
247 
248         signal_->outQueue_.pop();
249         signal_->infoQueue_.pop();
250         signal_->flagQueue_.pop();
251         signal_->outBufferQueue_.pop();
252     }
253 }
254 
ADecDemoCallback(shared_ptr<ADecSignal> signal)255 ADecDemoCallback::ADecDemoCallback(shared_ptr<ADecSignal> signal) : signal_(signal) {}
256 
OnError(AVCodecErrorType errorType,int32_t errorCode)257 void ADecDemoCallback::OnError(AVCodecErrorType errorType, int32_t errorCode)
258 {
259     cout << "Error received, errorType:" << errorType << " errorCode:" << errorCode << endl;
260 }
261 
OnOutputFormatChanged(const Format & format)262 void ADecDemoCallback::OnOutputFormatChanged(const Format &format)
263 {
264     (void)format;
265     cout << "OnOutputFormatChanged received" << endl;
266 }
267 
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVSharedMemory> buffer)268 void ADecDemoCallback::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
269 {
270     cout << "OnInputBufferAvailable received, index:" << index << endl;
271     unique_lock<mutex> lock(signal_->inMutex_);
272     signal_->inQueue_.push(index);
273     signal_->inBufferQueue_.push(buffer);
274     signal_->inCond_.notify_all();
275 }
276 
OnOutputBufferAvailable(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag,std::shared_ptr<AVSharedMemory> buffer)277 void ADecDemoCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag,
278                                                std::shared_ptr<AVSharedMemory> buffer)
279 {
280     (void)info;
281     (void)flag;
282     cout << "OnOutputBufferAvailable received, index:" << index << endl;
283     unique_lock<mutex> lock(signal_->outMutex_);
284     signal_->outQueue_.push(index);
285     signal_->infoQueue_.push(info);
286     signal_->flagQueue_.push(flag);
287     signal_->outBufferQueue_.push(buffer);
288     signal_->outCond_.notify_all();
289 }