• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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