• 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 <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 }