1 /*
2 * Copyright (C) 2025 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 constexpr int64_t NANOS_IN_SECOND = 1000000000L;
24 constexpr int64_t NANOS_IN_MICRO = 1000L;
25
26 constexpr int32_t EIGHT = 8;
27 constexpr int32_t SIXTEEN = 16;
28 constexpr int32_t TWENTY_FOUR = 24;
29 constexpr uint8_t SEI = 6;
30 constexpr uint8_t SPS = 7;
31 constexpr uint8_t PPS = 8;
32 constexpr uint32_t START_CODE_SIZE = 4;
33 constexpr uint8_t START_CODE[START_CODE_SIZE] = {0, 0, 0, 1};
34 VDecFuzzSample *g_decSample = nullptr;
35 constexpr uint8_t H264_NALU_TYPE = 0x1f;
36
37 bool g_fuzzError = false;
38
clearIntqueue(std::queue<uint32_t> & q)39 void clearIntqueue(std::queue<uint32_t> &q)
40 {
41 std::queue<uint32_t> empty;
42 swap(empty, q);
43 }
44
clearBufferqueue(std::queue<OH_AVCodecBufferAttr> & q)45 void clearBufferqueue(std::queue<OH_AVCodecBufferAttr> &q)
46 {
47 std::queue<OH_AVCodecBufferAttr> empty;
48 swap(empty, q);
49 }
50
clearAvBufferQueue(std::queue<OH_AVMemory * > & q)51 void clearAvBufferQueue(std::queue<OH_AVMemory *> &q)
52 {
53 std::queue<OH_AVMemory *> empty;
54 swap(empty, q);
55 }
56 } // namespace
57
58 class TestConsumerListener : public IBufferConsumerListener {
59 public:
TestConsumerListener(sptr<Surface> cs)60 TestConsumerListener(sptr<Surface> cs) : cs(cs) {};
~TestConsumerListener()61 ~TestConsumerListener() {}
OnBufferAvailable()62 void OnBufferAvailable() override
63 {
64 sptr<SurfaceBuffer> buffer;
65 int32_t flushFence;
66 cs->AcquireBuffer(buffer, flushFence, timestamp, damage);
67
68 cs->ReleaseBuffer(buffer, -1);
69 }
70
71 private:
72 int64_t timestamp = 0;
73 Rect damage = {};
74 sptr<Surface> cs {nullptr};
75 };
76
~VDecFuzzSample()77 VDecFuzzSample::~VDecFuzzSample()
78 {
79 Release();
80 }
81
VdecError(OH_AVCodec * codec,int32_t errorCode,void * userData)82 void VdecError(OH_AVCodec *codec, int32_t errorCode, void *userData)
83 {
84 VDecSignal *signal = static_cast<VDecSignal *>(userData);
85 if (signal == nullptr) {
86 return;
87 }
88 cout << "Error errorCode=" << errorCode << endl;
89 g_fuzzError = true;
90 g_decSample->isRunning_.store(false);
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 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_DECODER_BLANK_FRAME_ON_SHUTDOWN, enbleBlankFrame);
166 int ret = OH_VideoDecoder_Configure(vdec_, format);
167 OH_AVFormat_Destroy(format);
168 return ret;
169 }
170
RunVideoDec(string codeName)171 int32_t VDecFuzzSample::RunVideoDec(string codeName)
172 {
173 int err = CreateVideoDecoder(codeName);
174 if (err != AV_ERR_OK) {
175 cout << "Failed to create video decoder" << endl;
176 return err;
177 }
178 err = ConfigureVideoDecoder();
179 if (err != AV_ERR_OK) {
180 cout << "Failed to configure video decoder" << endl;
181 Release();
182 return err;
183 }
184 err = SetVideoDecoderCallback();
185 if (err != AV_ERR_OK) {
186 cout << "Failed to setCallback" << endl;
187 Release();
188 return err;
189 }
190 err = StartVideoDecoder();
191 if (err != AV_ERR_OK) {
192 cout << "Failed to start video decoder" << endl;
193 Release();
194 return err;
195 }
196 return err;
197 }
198
SetVideoDecoderCallback()199 int32_t VDecFuzzSample::SetVideoDecoderCallback()
200 {
201 signal_ = new VDecSignal();
202 if (signal_ == nullptr) {
203 cout << "Failed to new VDecSignal" << endl;
204 return AV_ERR_UNKNOWN;
205 }
206
207 cb_.onError = VdecError;
208 cb_.onStreamChanged = VdecFormatChanged;
209 cb_.onNeedInputData = VdecInputDataReady;
210 cb_.onNeedOutputData = VdecOutputDataReady;
211 return OH_VideoDecoder_SetCallback(vdec_, cb_, static_cast<void *>(signal_));
212 }
213
ReleaseInFile()214 void VDecFuzzSample::ReleaseInFile()
215 {
216 if (inFile_ != nullptr) {
217 if (inFile_->is_open()) {
218 inFile_->close();
219 }
220 inFile_.reset();
221 inFile_ = nullptr;
222 }
223 }
224
StopInloop()225 void VDecFuzzSample::StopInloop()
226 {
227 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
228 unique_lock<mutex> lock(signal_->inMutex_);
229 clearIntqueue(signal_->inIdxQueue_);
230 signal_->inCond_.notify_all();
231 lock.unlock();
232
233 inputLoop_->join();
234 inputLoop_.reset();
235 }
236 }
237
StartVideoDecoder()238 int32_t VDecFuzzSample::StartVideoDecoder()
239 {
240 int ret = OH_VideoDecoder_Start(vdec_);
241 if (ret != AV_ERR_OK) {
242 cout << "Failed to start codec" << endl;
243 return ret;
244 }
245
246 isRunning_.store(true);
247
248 inFile_ = make_unique<ifstream>();
249 if (inFile_ == nullptr) {
250 isRunning_.store(false);
251 (void)OH_VideoDecoder_Stop(vdec_);
252 return AV_ERR_UNKNOWN;
253 }
254 inFile_->open(inpDir, ios::in | ios::binary);
255 if (!inFile_->is_open()) {
256 cout << "open input file failed" << endl;
257 isRunning_.store(false);
258 (void)OH_VideoDecoder_Stop(vdec_);
259 inFile_->close();
260 inFile_.reset();
261 inFile_ = nullptr;
262 return AV_ERR_UNKNOWN;
263 }
264
265 inputLoop_ = make_unique<thread>(&VDecFuzzSample::InputFuncAVCC, this);
266 if (inputLoop_ == nullptr) {
267 cout << "Failed to create input loop" << endl;
268 isRunning_.store(false);
269 (void)OH_VideoDecoder_Stop(vdec_);
270 ReleaseInFile();
271 return AV_ERR_UNKNOWN;
272 }
273 return AV_ERR_OK;
274 }
275
CreateVideoDecoder(string codeName)276 int32_t VDecFuzzSample::CreateVideoDecoder(string codeName)
277 {
278 vdec_ = OH_VideoDecoder_CreateByName(randomName.c_str());
279 if (vdec_) {
280 OH_VideoDecoder_Destroy(vdec_);
281 vdec_ = nullptr;
282 }
283 OH_AVCodec *tmpDec = OH_VideoDecoder_CreateByMime(randomMime.c_str());
284 if (tmpDec) {
285 OH_VideoDecoder_Destroy(tmpDec);
286 tmpDec = nullptr;
287 }
288 tmpDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_H263);
289 if (tmpDec) {
290 OH_VideoDecoder_Destroy(tmpDec);
291 tmpDec = nullptr;
292 }
293 vdec_ = OH_VideoDecoder_CreateByName(codeName.c_str());
294 g_decSample = this;
295 return vdec_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
296 }
297
WaitForEOS()298 void VDecFuzzSample::WaitForEOS()
299 {
300 if (inputLoop_ && inputLoop_->joinable()) {
301 inputLoop_->join();
302 }
303 }
304
CopyStartCode(uint8_t * frameBuffer,uint32_t bufferSize,OH_AVCodecBufferAttr & attr)305 void VDecFuzzSample::CopyStartCode(uint8_t *frameBuffer, uint32_t bufferSize, OH_AVCodecBufferAttr &attr)
306 {
307 switch (frameBuffer[START_CODE_SIZE] & H264_NALU_TYPE) {
308 case SPS:
309 case PPS:
310 case SEI:
311 if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
312 cout << "Fatal: memory copy failed" << endl;
313 }
314 attr.pts = GetSystemTimeUs();
315 attr.size = bufferSize + START_CODE_SIZE;
316 attr.offset = 0;
317 attr.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
318 break;
319 default: {
320 if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
321 cout << "Fatal: memory copy failed" << endl;
322 }
323 attr.pts = GetSystemTimeUs();
324 attr.size = bufferSize + START_CODE_SIZE;
325 attr.offset = 0;
326 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
327 }
328 }
329 }
330
ReadData(uint32_t index,OH_AVMemory * buffer)331 int32_t VDecFuzzSample::ReadData(uint32_t index, OH_AVMemory *buffer)
332 {
333 uint8_t ch[4] = {};
334 (void)inFile_->read(reinterpret_cast<char *>(ch), START_CODE_SIZE);
335 if (repeatRun && inFile_->eof()) {
336 inFile_->clear();
337 inFile_->seekg(0, ios::beg);
338 cout << "repeat" << endl;
339 return 0;
340 } else if (inFile_->eof()) {
341 SetEOS(index);
342 return 1;
343 }
344 uint32_t bufferSize = static_cast<uint32_t>(((ch[3] & 0xFF)) | ((ch[2] & 0xFF) << EIGHT) |
345 ((ch[1] & 0xFF) << SIXTEEN) | ((ch[0] & 0xFF) << TWENTY_FOUR));
346 return SendData(bufferSize, index, buffer);
347 }
348
SendData(uint32_t bufferSize,uint32_t index,OH_AVMemory * buffer)349 uint32_t VDecFuzzSample::SendData(uint32_t bufferSize, uint32_t index, OH_AVMemory *buffer)
350 {
351 OH_AVCodecBufferAttr attr;
352 uint8_t *frameBuffer = nullptr;
353 if (bufferSize > 0) {
354 frameBuffer = new uint8_t[bufferSize];
355 } else {
356 delete[] frameBuffer;
357 return 0;
358 }
359 (void)inFile_->read(reinterpret_cast<char *>(frameBuffer), bufferSize);
360 attr.flags = (bufferSize != 0) ?
361 (AVCODEC_BUFFER_FLAGS_SYNC_FRAME + AVCODEC_BUFFER_FLAGS_CODEC_DATA) : AVCODEC_BUFFER_FLAGS_EOS;
362 int32_t size = OH_AVMemory_GetSize(buffer);
363 if (size < attr.size) {
364 delete[] frameBuffer;
365 cout << "ERROR:AVMemory not enough, buffer size" << attr.size << " AVMemory Size " << size << endl;
366 isRunning_.store(false);
367 return 1;
368 }
369 uint8_t *bufferAddr = OH_AVMemory_GetAddr(buffer);
370 if (memcpy_s(bufferAddr, size, frameBuffer, attr.size) != EOK) {
371 delete[] frameBuffer;
372 cout << "Fatal: memcpy fail" << endl;
373 isRunning_.store(false);
374 return 1;
375 }
376 delete[] frameBuffer;
377 attr.pts = GetSystemTimeUs();
378 attr.size = bufferSize;
379 attr.offset = 0;
380 int32_t ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
381 if (ret != AV_ERR_OK) {
382 errCount++;
383 cout << "push input data failed, error:" << ret << endl;
384 }
385 frameCount_ = frameCount_ + 1;
386 if (inFile_->eof()) {
387 isRunning_.store(false);
388 }
389 return 0;
390 }
391
InputFuncAVCC()392 void VDecFuzzSample::InputFuncAVCC()
393 {
394 frameCount_ = 1;
395 errCount = 0;
396 while (true) {
397 if (!isRunning_.load()) {
398 break;
399 }
400 unique_lock<mutex> lock(signal_->inMutex_);
401 signal_->inCond_.wait(lock, [this]() {
402 if (!isRunning_.load()) {
403 cout << "quit signal" << endl;
404 return true;
405 }
406 return signal_->inIdxQueue_.size() > 0;
407 });
408 if (!isRunning_.load()) {
409 break;
410 }
411 uint32_t index = signal_->inIdxQueue_.front();
412 auto buffer = signal_->inBufferQueue_.front();
413 signal_->inIdxQueue_.pop();
414 signal_->inBufferQueue_.pop();
415 lock.unlock();
416 if (!inFile_->eof()) {
417 int ret = ReadData(index, buffer);
418 if (ret == 1) {
419 break;
420 }
421 }
422 }
423 }
424
InputFuncFUZZ(const uint8_t * data,size_t size)425 OH_AVErrCode VDecFuzzSample::InputFuncFUZZ(const uint8_t *data, size_t size)
426 {
427 uint32_t index;
428 unique_lock<mutex> lock(signal_->inMutex_);
429 signal_->inCond_.wait(lock, [this]() {
430 if (!isRunning_.load() && g_fuzzError) {
431 return true;
432 }
433 return signal_->inIdxQueue_.size() > 0;
434 });
435 if (g_fuzzError)
436 return AV_ERR_TIMEOUT;
437 index = signal_->inIdxQueue_.front();
438 auto buffer = signal_->inBufferQueue_.front();
439 signal_->inIdxQueue_.pop();
440 signal_->inBufferQueue_.pop();
441 lock.unlock();
442 int32_t bufferSize = OH_AVMemory_GetSize(buffer);
443 uint8_t *bufferAddr = OH_AVMemory_GetAddr(buffer);
444
445 if (memcpy_s(bufferAddr, bufferSize, data, size) != EOK) {
446 cout << "Fatal: memcpy fail" << endl;
447 return AV_ERR_NO_MEMORY;
448 }
449 OH_AVCodecBufferAttr attr;
450 attr.pts = GetSystemTimeUs();
451 attr.size = bufferSize;
452 attr.offset = 0;
453 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
454 OH_AVErrCode ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
455 return ret;
456 }
457
SetEOS(uint32_t index)458 void VDecFuzzSample::SetEOS(uint32_t index)
459 {
460 OH_AVCodecBufferAttr attr;
461 attr.pts = 0;
462 attr.size = 0;
463 attr.offset = 0;
464 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
465 int32_t res = OH_VideoDecoder_PushInputData(vdec_, index, attr);
466 cout << "OH_VideoDecoder_PushInputData EOS res: " << res << endl;
467 }
468
Flush()469 int32_t VDecFuzzSample::Flush()
470 {
471 unique_lock<mutex> inLock(signal_->inMutex_);
472 clearIntqueue(signal_->inIdxQueue_);
473 signal_->inCond_.notify_all();
474 inLock.unlock();
475 unique_lock<mutex> outLock(signal_->outMutex_);
476 clearIntqueue(signal_->outIdxQueue_);
477 clearBufferqueue(signal_->attrQueue_);
478 signal_->outCond_.notify_all();
479 isRunning_.store(false);
480 outLock.unlock();
481
482 return OH_VideoDecoder_Flush(vdec_);
483 }
484
Reset()485 int32_t VDecFuzzSample::Reset()
486 {
487 isRunning_.store(false);
488 StopInloop();
489 ReleaseInFile();
490 return OH_VideoDecoder_Reset(vdec_);
491 }
492
Release()493 int32_t VDecFuzzSample::Release()
494 {
495 int ret = 0;
496 if (vdec_ != nullptr) {
497 ret = OH_VideoDecoder_Destroy(vdec_);
498 vdec_ = nullptr;
499 }
500 if (signal_ != nullptr) {
501 clearAvBufferQueue(signal_->inBufferQueue_);
502 clearAvBufferQueue(signal_->outBufferQueue_);
503 delete signal_;
504 signal_ = nullptr;
505 }
506 return ret;
507 }
508
Stop()509 int32_t VDecFuzzSample::Stop()
510 {
511 StopInloop();
512 clearIntqueue(signal_->outIdxQueue_);
513 clearBufferqueue(signal_->attrQueue_);
514 ReleaseInFile();
515 return OH_VideoDecoder_Stop(vdec_);
516 }
517
Start()518 int32_t VDecFuzzSample::Start()
519 {
520 int32_t ret = 0;
521 ret = OH_VideoDecoder_Start(vdec_);
522 if (ret == AV_ERR_OK) {
523 isRunning_.store(true);
524 }
525 return ret;
526 }
527
SetParameter(OH_AVFormat * format)528 int32_t VDecFuzzSample::SetParameter(OH_AVFormat *format)
529 {
530 return OH_VideoDecoder_SetParameter(vdec_, format);
531 }