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