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 }