1 /*
2 * Copyright (C) 2024 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 #include <arpa/inet.h>
16 #include <sys/time.h>
17 #include <utility>
18 #include "videodec_sample.h"
19 using namespace OHOS;
20 using namespace OHOS::Media;
21 using namespace std;
22 namespace {
23 const string MIME_TYPE = "video/hevc";
24 constexpr int64_t NANOS_IN_SECOND = 1000000000L;
25 constexpr int64_t NANOS_IN_MICRO = 1000L;
26
27 constexpr int32_t EIGHT = 8;
28 constexpr int32_t SIXTEEN = 16;
29 constexpr int32_t TWENTY_FOUR = 24;
30 constexpr uint8_t SEI = 6;
31 constexpr uint8_t SPS = 7;
32 constexpr uint8_t PPS = 8;
33 constexpr uint32_t START_CODE_SIZE = 4;
34 constexpr uint8_t START_CODE[START_CODE_SIZE] = {0, 0, 0, 1};
35 VDecFuzzSample *g_decSample = nullptr;
36 constexpr uint8_t H264_NALU_TYPE = 0x1f;
37
38 bool g_fuzzError = false;
39
clearIntqueue(std::queue<uint32_t> & q)40 void clearIntqueue(std::queue<uint32_t> &q)
41 {
42 std::queue<uint32_t> empty;
43 swap(empty, q);
44 }
45
clearBufferqueue(std::queue<OH_AVCodecBufferAttr> & q)46 void clearBufferqueue(std::queue<OH_AVCodecBufferAttr> &q)
47 {
48 std::queue<OH_AVCodecBufferAttr> empty;
49 swap(empty, q);
50 }
51
clearAvBufferQueue(std::queue<OH_AVMemory * > & q)52 void clearAvBufferQueue(std::queue<OH_AVMemory *> &q)
53 {
54 std::queue<OH_AVMemory *> empty;
55 swap(empty, q);
56 }
57 } // namespace
58
59 class TestConsumerListener : public IBufferConsumerListener {
60 public:
TestConsumerListener(sptr<Surface> cs)61 TestConsumerListener(sptr<Surface> cs) : cs(cs) {};
~TestConsumerListener()62 ~TestConsumerListener() {}
OnBufferAvailable()63 void OnBufferAvailable() override
64 {
65 sptr<SurfaceBuffer> buffer;
66 int32_t flushFence;
67 cs->AcquireBuffer(buffer, flushFence, timestamp, damage);
68
69 cs->ReleaseBuffer(buffer, -1);
70 }
71
72 private:
73 int64_t timestamp = 0;
74 Rect damage = {};
75 sptr<Surface> cs {nullptr};
76 };
77
~VDecFuzzSample()78 VDecFuzzSample::~VDecFuzzSample()
79 {
80 Release();
81 }
82
VdecError(OH_AVCodec * codec,int32_t errorCode,void * userData)83 void VdecError(OH_AVCodec *codec, int32_t errorCode, void *userData)
84 {
85 VDecSignal *signal = static_cast<VDecSignal *>(userData);
86 if (signal == nullptr) {
87 return;
88 }
89 cout << "Error errorCode=" << errorCode << endl;
90 g_fuzzError = true;
91 signal->inCond_.notify_all();
92 }
93
VdecFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)94 void VdecFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
95 {
96 cout << "Format Changed" << endl;
97 int32_t currentWidth = 0;
98 int32_t currentHeight = 0;
99 OH_AVFormat_GetIntValue(format, OH_MD_KEY_WIDTH, ¤tWidth);
100 OH_AVFormat_GetIntValue(format, OH_MD_KEY_HEIGHT, ¤tHeight);
101 g_decSample->defaultWidth = currentWidth;
102 g_decSample->defaultHeight = currentHeight;
103 }
104
VdecInputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)105 void VdecInputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
106 {
107 VDecSignal *signal = static_cast<VDecSignal *>(userData);
108 if (signal == nullptr) {
109 return;
110 }
111 unique_lock<mutex> lock(signal->inMutex_);
112 signal->inIdxQueue_.push(index);
113 signal->inBufferQueue_.push(data);
114 signal->inCond_.notify_all();
115 }
116
VdecOutputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)117 void VdecOutputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
118 void *userData)
119 {
120 VDecSignal *signal = static_cast<VDecSignal *>(userData);
121 if (signal == nullptr) {
122 return;
123 }
124 unique_lock<mutex> lock(signal->outMutex_);
125 signal->outIdxQueue_.push(index);
126 signal->attrQueue_.push(*attr);
127 signal->outBufferQueue_.push(data);
128 signal->outCond_.notify_all();
129 if (g_decSample->isSurfMode) {
130 OH_VideoDecoder_RenderOutputData(codec, index);
131 } else {
132 OH_VideoDecoder_FreeOutputData(codec, index);
133 }
134 }
135
GetSystemTimeUs()136 int64_t VDecFuzzSample::GetSystemTimeUs()
137 {
138 struct timespec now;
139 (void)clock_gettime(CLOCK_BOOTTIME, &now);
140 int64_t nanoTime = static_cast<int64_t>(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec;
141 return nanoTime / NANOS_IN_MICRO;
142 }
143
ConfigureVideoDecoder()144 int32_t VDecFuzzSample::ConfigureVideoDecoder()
145 {
146 if (isSurfMode) {
147 cs = Surface::CreateSurfaceAsConsumer();
148 sptr<IBufferConsumerListener> listener = new TestConsumerListener(cs);
149 cs->RegisterConsumerListener(listener);
150 auto p = cs->GetProducer();
151 ps = Surface::CreateSurfaceAsProducer(p);
152 nativeWindow = CreateNativeWindowFromSurface(&ps);
153 OH_VideoDecoder_SetSurface(vdec_, nativeWindow);
154 }
155 OH_AVFormat *format = OH_AVFormat_Create();
156 if (format == nullptr) {
157 cout << "Fatal: Failed to create format" << endl;
158 return AV_ERR_UNKNOWN;
159 }
160 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, defaultWidth);
161 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, defaultHeight);
162 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, defaultFrameRate);
163 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, defaultRotation);
164 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, defaultPixelFormat);
165 int ret = OH_VideoDecoder_Configure(vdec_, format);
166 OH_AVFormat_Destroy(format);
167 return ret;
168 }
169
RunVideoDec(string codeName)170 int32_t VDecFuzzSample::RunVideoDec(string codeName)
171 {
172 int err = CreateVideoDecoder(codeName);
173 if (err != AV_ERR_OK) {
174 cout << "Failed to create video decoder" << endl;
175 return err;
176 }
177 err = ConfigureVideoDecoder();
178 if (err != AV_ERR_OK) {
179 cout << "Failed to configure video decoder" << endl;
180 Release();
181 return err;
182 }
183 err = SetVideoDecoderCallback();
184 if (err != AV_ERR_OK) {
185 cout << "Failed to setCallback" << endl;
186 Release();
187 return err;
188 }
189 err = StartVideoDecoder();
190 if (err != AV_ERR_OK) {
191 cout << "Failed to start video decoder" << endl;
192 Release();
193 return err;
194 }
195 return err;
196 }
197
SetVideoDecoderCallback()198 int32_t VDecFuzzSample::SetVideoDecoderCallback()
199 {
200 signal_ = new VDecSignal();
201 if (signal_ == nullptr) {
202 cout << "Failed to new VDecSignal" << endl;
203 return AV_ERR_UNKNOWN;
204 }
205
206 cb_.onError = VdecError;
207 cb_.onStreamChanged = VdecFormatChanged;
208 cb_.onNeedInputData = VdecInputDataReady;
209 cb_.onNeedOutputData = VdecOutputDataReady;
210 return OH_VideoDecoder_SetCallback(vdec_, cb_, static_cast<void *>(signal_));
211 }
212
ReleaseInFile()213 void VDecFuzzSample::ReleaseInFile()
214 {
215 if (inFile_ != nullptr) {
216 if (inFile_->is_open()) {
217 inFile_->close();
218 }
219 inFile_.reset();
220 inFile_ = nullptr;
221 }
222 }
223
StopInloop()224 void VDecFuzzSample::StopInloop()
225 {
226 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
227 unique_lock<mutex> lock(signal_->inMutex_);
228 clearIntqueue(signal_->inIdxQueue_);
229 signal_->inCond_.notify_all();
230 lock.unlock();
231
232 inputLoop_->join();
233 inputLoop_.reset();
234 }
235 }
236
StartVideoDecoder()237 int32_t VDecFuzzSample::StartVideoDecoder()
238 {
239 int ret = OH_VideoDecoder_Start(vdec_);
240 if (ret != AV_ERR_OK) {
241 cout << "Failed to start codec" << endl;
242 return ret;
243 }
244
245 isRunning_.store(true);
246
247 inFile_ = make_unique<ifstream>();
248 if (inFile_ == nullptr) {
249 isRunning_.store(false);
250 (void)OH_VideoDecoder_Stop(vdec_);
251 return AV_ERR_UNKNOWN;
252 }
253 inFile_->open(inpDir, ios::in | ios::binary);
254 if (!inFile_->is_open()) {
255 cout << "open input file failed" << endl;
256 isRunning_.store(false);
257 (void)OH_VideoDecoder_Stop(vdec_);
258 inFile_->close();
259 inFile_.reset();
260 inFile_ = nullptr;
261 return AV_ERR_UNKNOWN;
262 }
263
264 inputLoop_ = make_unique<thread>(&VDecFuzzSample::InputFuncAVCC, this);
265 if (inputLoop_ == nullptr) {
266 cout << "Failed to create input loop" << endl;
267 isRunning_.store(false);
268 (void)OH_VideoDecoder_Stop(vdec_);
269 ReleaseInFile();
270 return AV_ERR_UNKNOWN;
271 }
272 return AV_ERR_OK;
273 }
274
CreateVideoDecoder(string codeName)275 int32_t VDecFuzzSample::CreateVideoDecoder(string codeName)
276 {
277 vdec_ = OH_VideoDecoder_CreateByName(codeName.c_str());
278 g_decSample = this;
279 return vdec_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
280 }
281
WaitForEOS()282 void VDecFuzzSample::WaitForEOS()
283 {
284 if (inputLoop_ && inputLoop_->joinable()) {
285 inputLoop_->join();
286 }
287 }
288
CopyStartCode(uint8_t * frameBuffer,uint32_t bufferSize,OH_AVCodecBufferAttr & attr)289 void VDecFuzzSample::CopyStartCode(uint8_t *frameBuffer, uint32_t bufferSize, OH_AVCodecBufferAttr &attr)
290 {
291 switch (frameBuffer[START_CODE_SIZE] & H264_NALU_TYPE) {
292 case SPS:
293 case PPS:
294 case SEI:
295 if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
296 cout << "Fatal: memory copy failed" << endl;
297 }
298 attr.pts = GetSystemTimeUs();
299 attr.size = bufferSize + START_CODE_SIZE;
300 attr.offset = 0;
301 attr.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
302 break;
303 default: {
304 if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
305 cout << "Fatal: memory copy failed" << endl;
306 }
307 attr.pts = GetSystemTimeUs();
308 attr.size = bufferSize + START_CODE_SIZE;
309 attr.offset = 0;
310 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
311 }
312 }
313 }
314
ReadData(uint32_t index,OH_AVMemory * buffer)315 int32_t VDecFuzzSample::ReadData(uint32_t index, OH_AVMemory *buffer)
316 {
317 uint8_t ch[4] = {};
318 (void)inFile_->read(reinterpret_cast<char *>(ch), START_CODE_SIZE);
319 if (repeatRun && inFile_->eof()) {
320 inFile_->clear();
321 inFile_->seekg(0, ios::beg);
322 cout << "repeat" << endl;
323 return 0;
324 } else if (inFile_->eof()) {
325 SetEOS(index);
326 return 1;
327 }
328 uint32_t bufferSize = static_cast<uint32_t>(((ch[3] & 0xFF)) | ((ch[2] & 0xFF) << EIGHT) |
329 ((ch[1] & 0xFF) << SIXTEEN) | ((ch[0] & 0xFF) << TWENTY_FOUR));
330 return SendData(bufferSize, index, buffer);
331 }
332
SendData(uint32_t bufferSize,uint32_t index,OH_AVMemory * buffer)333 uint32_t VDecFuzzSample::SendData(uint32_t bufferSize, uint32_t index, OH_AVMemory *buffer)
334 {
335 OH_AVCodecBufferAttr attr;
336 uint8_t *frameBuffer = new uint8_t[bufferSize + START_CODE_SIZE];
337 (void)inFile_->read(reinterpret_cast<char *>(frameBuffer + START_CODE_SIZE), bufferSize);
338 CopyStartCode(frameBuffer, bufferSize, attr);
339 int32_t size = OH_AVMemory_GetSize(buffer);
340 if (size < attr.size) {
341 delete[] frameBuffer;
342 cout << "ERROR:AVMemory not enough, buffer size" << attr.size << " AVMemory Size " << size << endl;
343 isRunning_.store(false);
344 return 1;
345 }
346 uint8_t *bufferAddr = OH_AVMemory_GetAddr(buffer);
347 if (memcpy_s(bufferAddr, size, frameBuffer, attr.size) != EOK) {
348 delete[] frameBuffer;
349 cout << "Fatal: memcpy fail" << endl;
350 isRunning_.store(false);
351 return 1;
352 }
353 delete[] frameBuffer;
354 int32_t ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
355 if (ret != AV_ERR_OK) {
356 errCount++;
357 cout << "push input data failed, error:" << ret << endl;
358 }
359 frameCount_ = frameCount_ + 1;
360 if (inFile_->eof()) {
361 isRunning_.store(false);
362 }
363 return 0;
364 }
365
InputFuncAVCC()366 void VDecFuzzSample::InputFuncAVCC()
367 {
368 frameCount_ = 1;
369 errCount = 0;
370 while (true) {
371 if (!isRunning_.load()) {
372 break;
373 }
374 unique_lock<mutex> lock(signal_->inMutex_);
375 signal_->inCond_.wait(lock, [this]() {
376 if (!isRunning_.load()) {
377 cout << "quit signal" << endl;
378 return true;
379 }
380 return signal_->inIdxQueue_.size() > 0;
381 });
382 if (!isRunning_.load()) {
383 break;
384 }
385 uint32_t index = signal_->inIdxQueue_.front();
386 auto buffer = signal_->inBufferQueue_.front();
387 signal_->inIdxQueue_.pop();
388 signal_->inBufferQueue_.pop();
389 lock.unlock();
390 if (!inFile_->eof()) {
391 int ret = ReadData(index, buffer);
392 if (ret == 1) {
393 break;
394 }
395 }
396 }
397 }
398
InputFuncFUZZ(const uint8_t * data,size_t size)399 OH_AVErrCode VDecFuzzSample::InputFuncFUZZ(const uint8_t *data, size_t size)
400 {
401 uint32_t index;
402 unique_lock<mutex> lock(signal_->inMutex_);
403 signal_->inCond_.wait(lock, [this]() {
404 if (!isRunning_.load() && g_fuzzError) {
405 return true;
406 }
407 return signal_->inIdxQueue_.size() > 0;
408 });
409 if (g_fuzzError)
410 return AV_ERR_TIMEOUT;
411 index = signal_->inIdxQueue_.front();
412 auto buffer = signal_->inBufferQueue_.front();
413 lock.unlock();
414 int32_t bufferSize = OH_AVMemory_GetSize(buffer);
415 uint8_t *bufferAddr = OH_AVMemory_GetAddr(buffer);
416
417 if (memcpy_s(bufferAddr, bufferSize, data, size) != EOK) {
418 cout << "Fatal: memcpy fail" << endl;
419 return AV_ERR_NO_MEMORY;
420 }
421 OH_AVCodecBufferAttr attr;
422 attr.pts = GetSystemTimeUs();
423 attr.size = bufferSize;
424 attr.offset = 0;
425 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
426 OH_AVErrCode ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
427 signal_->inIdxQueue_.pop();
428 signal_->inBufferQueue_.pop();
429 return ret;
430 }
431
SetEOS(uint32_t index)432 void VDecFuzzSample::SetEOS(uint32_t index)
433 {
434 OH_AVCodecBufferAttr attr;
435 attr.pts = 0;
436 attr.size = 0;
437 attr.offset = 0;
438 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
439 int32_t res = OH_VideoDecoder_PushInputData(vdec_, index, attr);
440 cout << "OH_VideoDecoder_PushInputData EOS res: " << res << endl;
441 }
442
Flush()443 int32_t VDecFuzzSample::Flush()
444 {
445 unique_lock<mutex> inLock(signal_->inMutex_);
446 clearIntqueue(signal_->inIdxQueue_);
447 signal_->inCond_.notify_all();
448 inLock.unlock();
449 unique_lock<mutex> outLock(signal_->outMutex_);
450 clearIntqueue(signal_->outIdxQueue_);
451 clearBufferqueue(signal_->attrQueue_);
452 signal_->outCond_.notify_all();
453 isRunning_.store(false);
454 outLock.unlock();
455
456 return OH_VideoDecoder_Flush(vdec_);
457 }
458
Reset()459 int32_t VDecFuzzSample::Reset()
460 {
461 isRunning_.store(false);
462 StopInloop();
463 ReleaseInFile();
464 return OH_VideoDecoder_Reset(vdec_);
465 }
466
Release()467 int32_t VDecFuzzSample::Release()
468 {
469 int ret = 0;
470 if (vdec_ != nullptr) {
471 ret = OH_VideoDecoder_Destroy(vdec_);
472 vdec_ = nullptr;
473 }
474 if (signal_ != nullptr) {
475 clearAvBufferQueue(signal_->inBufferQueue_);
476 clearAvBufferQueue(signal_->outBufferQueue_);
477 delete signal_;
478 signal_ = nullptr;
479 }
480 return ret;
481 }
482
Stop()483 int32_t VDecFuzzSample::Stop()
484 {
485 StopInloop();
486 clearIntqueue(signal_->outIdxQueue_);
487 clearBufferqueue(signal_->attrQueue_);
488 ReleaseInFile();
489 return OH_VideoDecoder_Stop(vdec_);
490 }
491
Start()492 int32_t VDecFuzzSample::Start()
493 {
494 int32_t ret = 0;
495 ret = OH_VideoDecoder_Start(vdec_);
496 if (ret == AV_ERR_OK) {
497 isRunning_.store(true);
498 }
499 return ret;
500 }
501
SetParameter(OH_AVFormat * format)502 int32_t VDecFuzzSample::SetParameter(OH_AVFormat *format)
503 {
504 return OH_VideoDecoder_SetParameter(vdec_, format);
505 }