1 /*
2 * Copyright (C) 2022 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 "nocopyable.h"
17 #include "media_errors.h"
18 #include "avcodec_common.h"
19 #include "vdec_mock.h"
20 using namespace std;
21 using namespace OHOS::Media::VCodecTestParam;
22 namespace OHOS {
23 namespace Media {
VDecCallbackTest(std::shared_ptr<VDecSignal> signal)24 VDecCallbackTest::VDecCallbackTest(std::shared_ptr<VDecSignal> signal)
25 : signal_(signal)
26 {
27 }
28
~VDecCallbackTest()29 VDecCallbackTest::~VDecCallbackTest()
30 {
31 }
32
OnError(int32_t errorCode)33 void VDecCallbackTest::OnError(int32_t errorCode)
34 {
35 cout << "VDec Error errorCode=" << errorCode << endl;
36 }
37
OnStreamChanged(std::shared_ptr<FormatMock> format)38 void VDecCallbackTest::OnStreamChanged(std::shared_ptr<FormatMock> format)
39 {
40 cout << "VDec Format Changed" << endl;
41 }
42
OnNeedInputData(uint32_t index,std::shared_ptr<AVMemoryMock> data)43 void VDecCallbackTest::OnNeedInputData(uint32_t index, std::shared_ptr<AVMemoryMock> data)
44 {
45 if (signal_ == nullptr) {
46 return;
47 }
48 unique_lock<mutex> lock(signal_->inMutex_);
49 if (!signal_->isRunning_.load()) {
50 return;
51 }
52 signal_->inIndexQueue_.push(index);
53 signal_->inBufferQueue_.push(data);
54 signal_->inCond_.notify_all();
55 }
56
OnNewOutputData(uint32_t index,std::shared_ptr<AVMemoryMock> data,AVCodecBufferAttrMock attr)57 void VDecCallbackTest::OnNewOutputData(uint32_t index, std::shared_ptr<AVMemoryMock> data, AVCodecBufferAttrMock attr)
58 {
59 if (signal_ == nullptr) {
60 return;
61 }
62 unique_lock<mutex> lock(signal_->outMutex_);
63 if (!signal_->isRunning_.load()) {
64 return;
65 }
66 signal_->outIndexQueue_.push(index);
67
68 signal_->outSizeQueue_.push(attr.size);
69 signal_->outCond_.notify_all();
70 }
71
VDecMock(std::shared_ptr<VDecSignal> signal)72 VDecMock::VDecMock(std::shared_ptr<VDecSignal> signal)
73 : signal_(signal)
74 {
75 }
76
~VDecMock()77 VDecMock::~VDecMock()
78 {
79 }
80
CreateVideoDecMockByMime(const std::string & mime)81 bool VDecMock::CreateVideoDecMockByMime(const std::string &mime)
82 {
83 videoDec_ = AVCodecMockFactory::CreateVideoDecMockByMime(mime);
84 return videoDec_ != nullptr;
85 }
86
CreateVideoDecMockByName(const std::string & name)87 bool VDecMock::CreateVideoDecMockByName(const std::string &name)
88 {
89 videoDec_ = AVCodecMockFactory::CreateVideoDecMockByName(name);
90 return videoDec_ != nullptr;
91 }
92
SetCallback(std::shared_ptr<AVCodecCallbackMock> cb)93 int32_t VDecMock::SetCallback(std::shared_ptr<AVCodecCallbackMock> cb)
94 {
95 if (videoDec_ == nullptr) {
96 return MSERR_INVALID_VAL;
97 }
98 return videoDec_->SetCallback(cb);
99 }
100
SetOutputSurface(std::shared_ptr<SurfaceMock> surface)101 int32_t VDecMock::SetOutputSurface(std::shared_ptr<SurfaceMock> surface)
102 {
103 if (videoDec_ == nullptr) {
104 return MSERR_INVALID_VAL;
105 }
106 return videoDec_->SetOutputSurface(surface);
107 }
108
Configure(std::shared_ptr<FormatMock> format)109 int32_t VDecMock::Configure(std::shared_ptr<FormatMock> format)
110 {
111 if (videoDec_ == nullptr) {
112 return MSERR_INVALID_VAL;
113 }
114 return videoDec_->Configure(format);
115 }
116
Prepare()117 int32_t VDecMock::Prepare()
118 {
119 if (videoDec_ == nullptr) {
120 return MSERR_INVALID_VAL;
121 }
122 return videoDec_->Prepare();
123 }
124
Start()125 int32_t VDecMock::Start()
126 {
127 if (signal_ == nullptr || videoDec_ == nullptr) {
128 return MSERR_INVALID_VAL;
129 }
130 signal_->isRunning_.store(true);
131
132 testFile_ = std::make_unique<std::ifstream>();
133 UNITTEST_CHECK_AND_RETURN_RET_LOG(testFile_ != nullptr, MSERR_OK, "Fatal: No memory");
134 testFile_->open(inpPath_, std::ios::in | std::ios::binary);
135
136 inputLoop_ = make_unique<thread>(&VDecMock::InpLoopFunc, this);
137 UNITTEST_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, MSERR_OK, "Fatal: No memory");
138
139 outputLoop_ = make_unique<thread>(&VDecMock::OutLoopFunc, this);
140 UNITTEST_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, MSERR_OK, "Fatal: No memory");
141 return videoDec_->Start();
142 }
143
FlushInner()144 void VDecMock::FlushInner()
145 {
146 if (signal_ == nullptr) {
147 return;
148 }
149 signal_->isRunning_.store(false);
150 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
151 unique_lock<mutex> queueLock(signal_->inMutex_);
152 signal_->inIndexQueue_.push(10000); // push 10000 to stop queue
153 signal_->inCond_.notify_all();
154 queueLock.unlock();
155 inputLoop_->join();
156 inputLoop_.reset();
157 std::queue<uint32_t> temp;
158 std::swap(temp, signal_->inIndexQueue_);
159 }
160 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
161 unique_lock<mutex> lock(signal_->outMutex_);
162 signal_->outIndexQueue_.push(10000); // push 10000 to stop queue
163 signal_->outCond_.notify_all();
164 lock.unlock();
165 outputLoop_->join();
166 outputLoop_.reset();
167 std::queue<uint32_t> temp;
168 std::swap(temp, signal_->outIndexQueue_);
169 }
170 }
171
Stop()172 int32_t VDecMock::Stop()
173 {
174 FlushInner();
175 if (videoDec_ == nullptr) {
176 return MSERR_INVALID_VAL;
177 }
178 return videoDec_->Stop();
179 }
180
Flush()181 int32_t VDecMock::Flush()
182 {
183 FlushInner();
184 if (videoDec_ == nullptr) {
185 return MSERR_INVALID_VAL;
186 }
187 return videoDec_->Flush();
188 }
189
Reset()190 int32_t VDecMock::Reset()
191 {
192 FlushInner();
193 if (videoDec_ == nullptr) {
194 return MSERR_INVALID_VAL;
195 }
196 return videoDec_->Reset();
197 }
198
Release()199 int32_t VDecMock::Release()
200 {
201 if (videoDec_ == nullptr) {
202 return MSERR_INVALID_VAL;
203 }
204 return videoDec_->Release();
205 }
206
GetOutputMediaDescription()207 std::shared_ptr<FormatMock> VDecMock::GetOutputMediaDescription()
208 {
209 if (videoDec_ == nullptr) {
210 return nullptr;
211 }
212 return videoDec_->GetOutputMediaDescription();
213 }
214
SetParameter(std::shared_ptr<FormatMock> format)215 int32_t VDecMock::SetParameter(std::shared_ptr<FormatMock> format)
216 {
217 if (videoDec_ == nullptr) {
218 return MSERR_INVALID_VAL;
219 }
220 return videoDec_->SetParameter(format);
221 }
222
PushInputData(uint32_t index,AVCodecBufferAttrMock & attr)223 int32_t VDecMock::PushInputData(uint32_t index, AVCodecBufferAttrMock &attr)
224 {
225 if (videoDec_ == nullptr) {
226 return MSERR_INVALID_VAL;
227 }
228 return videoDec_->PushInputData(index, attr);
229 }
230
RenderOutputData(uint32_t index)231 int32_t VDecMock::RenderOutputData(uint32_t index)
232 {
233 if (videoDec_ == nullptr) {
234 return MSERR_INVALID_VAL;
235 }
236 return videoDec_->RenderOutputData(index);
237 }
238
FreeOutputData(uint32_t index)239 int32_t VDecMock::FreeOutputData(uint32_t index)
240 {
241 if (videoDec_ == nullptr) {
242 return MSERR_INVALID_VAL;
243 }
244 return videoDec_->FreeOutputData(index);
245 }
246
SetSource(const std::string & path,const uint32_t es[],const uint32_t & size)247 void VDecMock::SetSource(const std::string &path, const uint32_t es[], const uint32_t &size)
248 {
249 inpPath_ = path;
250 es_ = es;
251 esLength_ = size;
252 }
253
PushInputDataMock(uint32_t index,uint32_t bufferSize)254 int32_t VDecMock::PushInputDataMock(uint32_t index, uint32_t bufferSize)
255 {
256 if (videoDec_ == nullptr) {
257 return MSERR_INVALID_VAL;
258 }
259 struct AVCodecBufferAttrMock attr;
260 attr.offset = 0;
261 if (frameCount_ == esLength_) {
262 attr.flags = AVCODEC_BUFFER_FLAG_EOS;
263 attr.size = 0;
264 attr.pts = 0;
265 cout << "EOS Frame, frameCount = " << frameCount_ << endl;
266 signal_->isRunning_.store(false);
267 } else {
268 if (isFirstFrame_) {
269 attr.flags = AVCODEC_BUFFER_FLAG_CODEC_DATA;
270 isFirstFrame_ = false;
271 } else {
272 attr.flags = AVCODEC_BUFFER_FLAG_NONE;
273 }
274 attr.size = bufferSize;
275 attr.pts = timestamp_;
276 }
277 return videoDec_->PushInputData(index, attr);
278 }
279
InpLoopFunc()280 void VDecMock::InpLoopFunc()
281 {
282 if (signal_ == nullptr || videoDec_ == nullptr) {
283 return;
284 }
285 while (true) {
286 if (!signal_->isRunning_.load()) {
287 break;
288 }
289
290 unique_lock<mutex> lock(signal_->inMutex_);
291 signal_->inCond_.wait(lock, [this]() { return signal_->inIndexQueue_.size() > 0; });
292
293 if (!signal_->isRunning_.load()) {
294 break;
295 }
296 uint32_t index = signal_->inIndexQueue_.front();
297 std::shared_ptr<AVMemoryMock> buffer = signal_->inBufferQueue_.front();
298 UNITTEST_CHECK_AND_RETURN_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
299 UNITTEST_CHECK_AND_RETURN_LOG(testFile_ != nullptr && testFile_->is_open(), "Fatal: open file fail");
300
301 uint32_t bufferSize = 0;
302
303 if (frameCount_ < esLength_) {
304 bufferSize = es_[frameCount_];
305 char *fileBuffer = static_cast<char *>(malloc(sizeof(char) * bufferSize + 1));
306 UNITTEST_CHECK_AND_RETURN_LOG(fileBuffer != nullptr, "Fatal: malloc fail.");
307 (void)testFile_->read(fileBuffer, bufferSize);
308 if (testFile_->eof()) {
309 cout << "Finish" << endl;
310 free(fileBuffer);
311 break;
312 }
313
314 if (memcpy_s(buffer->GetAddr(), buffer->GetSize(), fileBuffer, bufferSize) != EOK) {
315 cout << "Fatal: memcpy fail" << endl;
316 free(fileBuffer);
317 break;
318 }
319 free(fileBuffer);
320 }
321 if (PushInputDataMock(index, bufferSize) != MSERR_OK) {
322 cout << "Fatal: PushInputData fail, exit" << endl;
323 }
324 timestamp_ += FRAME_DURATION_US;
325 frameCount_++;
326 signal_->inIndexQueue_.pop();
327 signal_->inBufferQueue_.pop();
328 }
329 }
330
OutLoopFunc()331 void VDecMock::OutLoopFunc()
332 {
333 if (signal_ == nullptr || videoDec_ == nullptr) {
334 return;
335 }
336 while (true) {
337 if (!signal_->isRunning_.load()) {
338 break;
339 }
340 unique_lock<mutex> lock(signal_->outMutex_);
341 signal_->outCond_.wait(lock, [this]() { return signal_->outIndexQueue_.size() > 0; });
342 if (!signal_->isRunning_.load()) {
343 break;
344 }
345 uint32_t index = signal_->outIndexQueue_.front();
346 if (index != EOS_INDEX && videoDec_->RenderOutputData(index) != MSERR_OK) {
347 cout << "Fatal: ReleaseOutputBuffer fail index" << index << endl;
348 break;
349 }
350 signal_->outIndexQueue_.pop();
351 signal_->outSizeQueue_.pop();
352 }
353 }
354 } // namespace Media
355 } // namespace OHOS
356