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