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 "vdec_sample.h"
17 #include <gtest/gtest.h>
18
19 using namespace std;
20 using namespace OHOS::MediaAVCodec::VCodecTestParam;
21 namespace OHOS {
22 namespace MediaAVCodec {
VDecCallbackTest(std::shared_ptr<VDecSignal> signal)23 VDecCallbackTest::VDecCallbackTest(std::shared_ptr<VDecSignal> signal) : signal_(signal) {}
24
~VDecCallbackTest()25 VDecCallbackTest::~VDecCallbackTest() {}
26
OnError(int32_t errorCode)27 void VDecCallbackTest::OnError(int32_t errorCode)
28 {
29 cout << "ADec Error errorCode=" << errorCode;
30 if (signal_ == nullptr) {
31 return;
32 }
33 signal_->errorNum_ += 1;
34 cout << ", errorNum=" << signal_->errorNum_ << endl;
35 }
36
OnStreamChanged(std::shared_ptr<FormatMock> format)37 void VDecCallbackTest::OnStreamChanged(std::shared_ptr<FormatMock> format)
38 {
39 (void)format;
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,OH_AVCodecBufferAttr attr)57 void VDecCallbackTest::OnNewOutputData(uint32_t index, std::shared_ptr<AVMemoryMock> data, OH_AVCodecBufferAttr 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 signal_->outBufferQueue_.push(data);
68 signal_->outAttrQueue_.push(attr);
69 signal_->outCond_.notify_all();
70 }
71
TestConsumerListener(sptr<Surface> cs,std::string_view name)72 TestConsumerListener::TestConsumerListener(sptr<Surface> cs, std::string_view name) : cs_(cs)
73 {
74 outFile_ = std::make_unique<std::ofstream>();
75 outFile_->open(name.data(), std::ios::out | std::ios::binary);
76 }
77
~TestConsumerListener()78 TestConsumerListener::~TestConsumerListener()
79 {
80 if (outFile_ != nullptr) {
81 outFile_->close();
82 }
83 }
84
OnBufferAvailable()85 void TestConsumerListener::OnBufferAvailable()
86 {
87 sptr<SurfaceBuffer> buffer;
88 int32_t flushFence;
89
90 cs_->AcquireBuffer(buffer, flushFence, timestamp_, damage_);
91
92 (void)outFile_->write(reinterpret_cast<char *>(buffer->GetVirAddr()), buffer->GetSize());
93 cs_->ReleaseBuffer(buffer, -1);
94 }
95
VideoDecSample(std::shared_ptr<VDecSignal> signal)96 VideoDecSample::VideoDecSample(std::shared_ptr<VDecSignal> signal) : signal_(signal) {}
97
~VideoDecSample()98 VideoDecSample::~VideoDecSample()
99 {
100 FlushInner();
101 if (videoDec_ != nullptr) {
102 (void)videoDec_->Release();
103 }
104 if (inFile_ != nullptr && inFile_->is_open()) {
105 inFile_->close();
106 }
107 if (outFile_ != nullptr && outFile_->is_open()) {
108 outFile_->close();
109 }
110 }
111
CreateVideoDecMockByMime(const std::string & mime)112 bool VideoDecSample::CreateVideoDecMockByMime(const std::string &mime)
113 {
114 videoDec_ = VCodecMockFactory::CreateVideoDecMockByMime(mime);
115 return videoDec_ != nullptr;
116 }
117
CreateVideoDecMockByName(const std::string & name)118 bool VideoDecSample::CreateVideoDecMockByName(const std::string &name)
119 {
120 videoDec_ = VCodecMockFactory::CreateVideoDecMockByName(name);
121 return videoDec_ != nullptr;
122 }
123
SetCallback(std::shared_ptr<AVCodecCallbackMock> cb)124 int32_t VideoDecSample::SetCallback(std::shared_ptr<AVCodecCallbackMock> cb)
125 {
126 if (videoDec_ == nullptr) {
127 return AV_ERR_INVALID_VAL;
128 }
129 return videoDec_->SetCallback(cb);
130 }
131
SetOutputSurface()132 int32_t VideoDecSample::SetOutputSurface()
133 {
134 if (videoDec_ == nullptr) {
135 return AV_ERR_INVALID_VAL;
136 }
137
138 consumer_ = Surface::CreateSurfaceAsConsumer();
139 sptr<IBufferConsumerListener> listener = new TestConsumerListener(consumer_, outSurfacePath_);
140 consumer_->RegisterConsumerListener(listener);
141 auto p = consumer_->GetProducer();
142 producer_ = Surface::CreateSurfaceAsProducer(p);
143 std::shared_ptr<SurfaceMock> surface = SurfaceMockFactory::CreateSurface(producer_);
144 int32_t ret = videoDec_->SetOutputSurface(surface);
145 isSurfaceMode_ = (ret == AV_ERR_OK);
146 return ret;
147 }
148
Configure(std::shared_ptr<FormatMock> format)149 int32_t VideoDecSample::Configure(std::shared_ptr<FormatMock> format)
150 {
151 if (videoDec_ == nullptr) {
152 return AV_ERR_INVALID_VAL;
153 }
154 return videoDec_->Configure(format);
155 }
156
Start()157 int32_t VideoDecSample::Start()
158 {
159 if (signal_ == nullptr || videoDec_ == nullptr) {
160 return AV_ERR_INVALID_VAL;
161 }
162 PrepareInner();
163 int32_t ret = videoDec_->Start();
164 UNITTEST_CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, ret, "Fatal: Start fail");
165 RunInner();
166 return ret;
167 }
168
Stop()169 int32_t VideoDecSample::Stop()
170 {
171 FlushInner();
172 if (videoDec_ == nullptr) {
173 return AV_ERR_INVALID_VAL;
174 }
175 return videoDec_->Stop();
176 }
177
Flush()178 int32_t VideoDecSample::Flush()
179 {
180 FlushInner();
181 if (videoDec_ == nullptr) {
182 return AV_ERR_INVALID_VAL;
183 }
184 return videoDec_->Flush();
185 }
186
Reset()187 int32_t VideoDecSample::Reset()
188 {
189 FlushInner();
190 if (videoDec_ == nullptr) {
191 return AV_ERR_INVALID_VAL;
192 }
193 return videoDec_->Reset();
194 }
195
Release()196 int32_t VideoDecSample::Release()
197 {
198 FlushInner();
199 if (videoDec_ == nullptr) {
200 return AV_ERR_INVALID_VAL;
201 }
202 return videoDec_->Release();
203 }
204
GetOutputDescription()205 std::shared_ptr<FormatMock> VideoDecSample::GetOutputDescription()
206 {
207 if (videoDec_ == nullptr) {
208 return nullptr;
209 }
210 return videoDec_->GetOutputDescription();
211 }
212
SetParameter(std::shared_ptr<FormatMock> format)213 int32_t VideoDecSample::SetParameter(std::shared_ptr<FormatMock> format)
214 {
215 if (videoDec_ == nullptr) {
216 return AV_ERR_INVALID_VAL;
217 }
218 return videoDec_->SetParameter(format);
219 }
220
PushInputData(uint32_t index,OH_AVCodecBufferAttr & attr)221 int32_t VideoDecSample::PushInputData(uint32_t index, OH_AVCodecBufferAttr &attr)
222 {
223 if (videoDec_ == nullptr) {
224 return AV_ERR_INVALID_VAL;
225 }
226 return videoDec_->PushInputData(index, attr);
227 }
228
RenderOutputData(uint32_t index)229 int32_t VideoDecSample::RenderOutputData(uint32_t index)
230 {
231 if (videoDec_ == nullptr) {
232 return AV_ERR_INVALID_VAL;
233 }
234 return videoDec_->RenderOutputData(index);
235 }
236
FreeOutputData(uint32_t index)237 int32_t VideoDecSample::FreeOutputData(uint32_t index)
238 {
239 if (videoDec_ == nullptr) {
240 return AV_ERR_INVALID_VAL;
241 }
242 return videoDec_->FreeOutputData(index);
243 }
244
IsValid()245 bool VideoDecSample::IsValid()
246 {
247 if (videoDec_ == nullptr) {
248 return false;
249 }
250 return videoDec_->IsValid();
251 }
252
SetOutPath(const std::string & path)253 void VideoDecSample::SetOutPath(const std::string &path)
254 {
255 outPath_ = path + ".yuv";
256 outSurfacePath_ = path + ".rgba";
257 }
258
SetSource(const std::string & path)259 void VideoDecSample::SetSource(const std::string &path)
260 {
261 inPath_ = path;
262 }
263
FlushInner()264 void VideoDecSample::FlushInner()
265 {
266 if (signal_ == nullptr) {
267 return;
268 }
269 signal_->isRunning_.store(false);
270 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
271 unique_lock<mutex> queueLock(signal_->inMutex_);
272 std::queue<uint32_t> tempIndex;
273 std::swap(tempIndex, signal_->inIndexQueue_);
274 std::queue<std::shared_ptr<AVMemoryMock>> tempInBufferr;
275 std::swap(tempInBufferr, signal_->inBufferQueue_);
276 queueLock.unlock();
277 signal_->inCond_.notify_all();
278 inputLoop_->join();
279
280 frameInputCount_ = frameOutputCount_ = 0;
281 inFile_ = std::make_unique<std::ifstream>();
282 ASSERT_NE(inFile_, nullptr);
283 inFile_->open(inPath_, std::ios::in | std::ios::binary);
284 ASSERT_TRUE(inFile_->is_open());
285 }
286 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
287 unique_lock<mutex> lock(signal_->outMutex_);
288 std::queue<uint32_t> tempIndex;
289 std::swap(tempIndex, signal_->outIndexQueue_);
290 std::queue<OH_AVCodecBufferAttr> tempOutAttr;
291 std::swap(tempOutAttr, signal_->outAttrQueue_);
292 std::queue<std::shared_ptr<AVMemoryMock>> tempOutBufferr;
293 std::swap(tempOutBufferr, signal_->outBufferQueue_);
294 lock.unlock();
295 signal_->outCond_.notify_all();
296 outputLoop_->join();
297 }
298 }
299
RunInner()300 void VideoDecSample::RunInner()
301 {
302 if (signal_ == nullptr) {
303 return;
304 }
305 unique_lock<mutex> lock(signal_->mutex_);
306 auto lck = [this]() { return !signal_->isRunning_.load(); };
307 bool isNotTimeout = signal_->cond_.wait_for(lock, chrono::seconds(SAMPLE_TIMEOUT), lck);
308 lock.unlock();
309 int64_t tempTime =
310 chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now()).time_since_epoch().count();
311 EXPECT_TRUE(isNotTimeout);
312 if (!isNotTimeout) {
313 cout << "Run func timeout, time used: " << tempTime - time_ << "ms" << endl;
314 } else {
315 cout << "Run func finish, time used: " << tempTime - time_ << "ms" << endl;
316 }
317 FlushInner();
318 }
319
PrepareInner()320 void VideoDecSample::PrepareInner()
321 {
322 if (signal_ == nullptr) {
323 return;
324 }
325 FlushInner();
326 signal_->isRunning_.store(true);
327 inFile_ = std::make_unique<std::ifstream>();
328 ASSERT_NE(inFile_, nullptr);
329 inFile_->open(inPath_, std::ios::in | std::ios::binary);
330 ASSERT_TRUE(inFile_->is_open());
331 time_ = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now()).time_since_epoch().count();
332 inputLoop_ = make_unique<thread>(&VideoDecSample::InputLoopFunc, this);
333 ASSERT_NE(inputLoop_, nullptr);
334 outputLoop_ = make_unique<thread>(&VideoDecSample::OutputLoopFunc, this);
335 ASSERT_NE(outputLoop_, nullptr);
336 }
337
InputLoopFunc()338 void VideoDecSample::InputLoopFunc()
339 {
340 ASSERT_NE(signal_, nullptr);
341 ASSERT_NE(videoDec_, nullptr);
342 inFile_->read(reinterpret_cast<char *>(&datSize_), sizeof(int64_t));
343 frameInputCount_ = 0;
344 isFirstFrame_ = true;
345 while (true) {
346 UNITTEST_CHECK_AND_BREAK_LOG(signal_->isRunning_.load(), "InputLoopFunc stop running");
347 unique_lock<mutex> lock(signal_->inMutex_);
348 signal_->inCond_.wait(
349 lock, [this]() { return (signal_->inIndexQueue_.size() > 0) || (!signal_->isRunning_.load()); });
350 UNITTEST_CHECK_AND_BREAK_LOG(signal_->isRunning_.load(), "InputLoopFunc stop running");
351 UNITTEST_CHECK_AND_BREAK_LOG(inFile_ != nullptr && inFile_->is_open(), "inFile_ is closed");
352
353 int32_t ret = InputLoopInner();
354 EXPECT_EQ(ret, AV_ERR_OK);
355 UNITTEST_CHECK_AND_BREAK_LOG(ret == AV_ERR_OK, "Fatal: PushInputData fail, exit");
356
357 frameInputCount_++;
358 signal_->inIndexQueue_.pop();
359 signal_->inBufferQueue_.pop();
360 }
361 }
362
InputLoopInner()363 int32_t VideoDecSample::InputLoopInner()
364 {
365 uint32_t index = signal_->inIndexQueue_.front();
366 std::shared_ptr<AVMemoryMock> buffer = signal_->inBufferQueue_.front();
367 UNITTEST_CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AV_ERR_INVALID_VAL, "Fatal: GetInputBuffer fail");
368
369 uint64_t bufferSize = 0;
370 uint64_t bufferPts = 0;
371 struct OH_AVCodecBufferAttr attr = {0, 0, 0, AVCODEC_BUFFER_FLAG_NONE};
372 bool isOutOfLength = (frameInputCount_ >= datSize_ || frameInputCount_ >= EOS_COUNT);
373 if (!isOutOfLength) {
374 inFile_->read(reinterpret_cast<char *>(&bufferSize), sizeof(int64_t));
375 inFile_->read(reinterpret_cast<char *>(&bufferPts), sizeof(int64_t));
376 char *fileBuffer = static_cast<char *>(malloc(sizeof(char) * bufferSize + 1));
377 UNITTEST_CHECK_AND_RETURN_RET_LOG(fileBuffer != nullptr, AV_ERR_INVALID_VAL, "Fatal: malloc fail.");
378 (void)inFile_->read(fileBuffer, bufferSize);
379 if (inFile_->eof() || memcpy_s(buffer->GetAddr(), buffer->GetSize(), fileBuffer, bufferSize) != EOK) {
380 attr.flags = AVCODEC_BUFFER_FLAG_EOS;
381 }
382 free(fileBuffer);
383 }
384 if (isOutOfLength || attr.flags == AVCODEC_BUFFER_FLAG_EOS) {
385 attr.flags = AVCODEC_BUFFER_FLAG_EOS;
386 cout << "Input EOS Frame, frameCount = " << frameInputCount_ << endl;
387 int32_t ret = videoDec_->PushInputData(index, attr);
388 if (inFile_ != nullptr && inFile_->is_open()) {
389 inFile_->close();
390 }
391 return ret;
392 }
393 if (isFirstFrame_) {
394 attr.flags = AVCODEC_BUFFER_FLAG_CODEC_DATA;
395 isFirstFrame_ = false;
396 } else {
397 attr.flags = AVCODEC_BUFFER_FLAG_NONE;
398 }
399 attr.size = bufferSize;
400 attr.pts = bufferPts;
401 return videoDec_->PushInputData(index, attr);
402 }
403
OutputLoopFunc()404 void VideoDecSample::OutputLoopFunc()
405 {
406 ASSERT_NE(signal_, nullptr);
407 ASSERT_NE(videoDec_, nullptr);
408 if (isDump_) {
409 outFile_ = std::make_unique<std::ofstream>();
410 ASSERT_NE(outFile_, nullptr) << "Fatal: No memory";
411 outFile_->open(outPath_, std::ios::out | std::ios::binary | std::ios::ate);
412 ASSERT_TRUE(outFile_->is_open()) << "outFile_ can not find";
413 }
414 frameOutputCount_ = 0;
415 while (true) {
416 UNITTEST_CHECK_AND_BREAK_LOG(signal_->isRunning_.load(), "OutputLoopFunc stop running");
417 unique_lock<mutex> lock(signal_->outMutex_);
418 signal_->outCond_.wait(
419 lock, [this]() { return (signal_->outIndexQueue_.size() > 0) || (!signal_->isRunning_.load()); });
420 UNITTEST_CHECK_AND_BREAK_LOG(signal_->isRunning_.load(), "OutputLoopFunc stop running");
421
422 int32_t ret = OutputLoopInner();
423 EXPECT_EQ(ret, AV_ERR_OK);
424 UNITTEST_CHECK_AND_BREAK_LOG(ret == AV_ERR_OK, "Fatal: OutputLoopInner fail, exit");
425
426 signal_->outIndexQueue_.pop();
427 signal_->outAttrQueue_.pop();
428 signal_->outBufferQueue_.pop();
429 }
430 unique_lock<mutex> lock(signal_->mutex_);
431 signal_->isRunning_.store(false);
432 signal_->cond_.notify_all();
433 }
434
OutputLoopInner()435 int32_t VideoDecSample::OutputLoopInner()
436 {
437 struct OH_AVCodecBufferAttr attr = signal_->outAttrQueue_.front();
438 uint32_t index = signal_->outIndexQueue_.front();
439 uint32_t ret = AV_ERR_OK;
440 auto buffer = signal_->outBufferQueue_.front();
441
442 ++frameOutputCount_;
443 if (frameOutputCount_ != EOS_COUNT) {
444 if (outFile_ != nullptr && isDump_ && !isSurfaceMode_) {
445 if (!outFile_->is_open()) {
446 cout << "output data fail" << endl;
447 } else {
448 UNITTEST_CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AV_ERR_INVALID_VAL,
449 "Fatal: GetOutputBuffer fail, exit");
450 outFile_->write(reinterpret_cast<char *>(buffer->GetAddr()), attr.size);
451 }
452 }
453 if (!isSurfaceMode_) {
454 ret = videoDec_->FreeOutputData(index);
455 UNITTEST_CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, ret, "Fatal: FreeOutputData fail index: %d", index);
456 } else {
457 ret = videoDec_->RenderOutputData(index);
458 UNITTEST_CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, ret, "Fatal: RenderOutputData fail index: %d", index);
459 }
460 } else {
461 cout << "Output EOS Frame, frameCount = " << frameOutputCount_ << endl;
462 }
463 if (attr.flags == AVCODEC_BUFFER_FLAG_EOS) {
464 if (!isSurfaceMode_ && outFile_ != nullptr && outFile_->is_open()) {
465 outFile_->close();
466 }
467 cout << "Get EOS Frame, output func exit" << endl;
468 unique_lock<mutex> lock(signal_->mutex_);
469 signal_->isRunning_.store(false);
470 signal_->cond_.notify_all();
471 return AV_ERR_OK;
472 }
473 return AV_ERR_OK;
474 }
475 } // namespace MediaAVCodec
476 } // namespace OHOS
477