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