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);
132 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, defaultWidth);
133 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, defaultHeight);
134 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, defaultRotation);
135 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, defaultPixelFormat);
136 int ret = OH_VideoDecoder_Configure(vdec_, format);
137 OH_AVFormat_Destroy(format);
138 if (isSurfMode) {
139 cs = Surface::CreateSurfaceAsConsumer();
140 sptr<IBufferConsumerListener> listener = new TestConsumerListener(cs);
141 cs->RegisterConsumerListener(listener);
142 auto p = cs->GetProducer();
143 ps = Surface::CreateSurfaceAsProducer(p);
144 nativeWindow = CreateNativeWindowFromSurface(&ps);
145 OH_VideoDecoder_SetSurface(vdec_, nativeWindow);
146 }
147 return ret;
148 }
149
RunVideoDec()150 int32_t VDecFuzzSample::RunVideoDec()
151 {
152 int err = CreateVideoDecoder();
153 if (err != AV_ERR_OK) {
154 cout << "Failed to create video decoder" << endl;
155 return err;
156 }
157
158 err = ConfigureVideoDecoder();
159 if (err != AV_ERR_OK) {
160 cout << "Failed to configure video decoder" << endl;
161 Release();
162 return err;
163 }
164
165 err = SetVideoDecoderCallback();
166 if (err != AV_ERR_OK) {
167 cout << "Failed to setCallback" << endl;
168 Release();
169 return err;
170 }
171
172 err = StartVideoDecoder();
173 if (err != AV_ERR_OK) {
174 cout << "Failed to start video decoder" << endl;
175 Release();
176 return err;
177 }
178 return err;
179 }
180
SetVideoDecoderCallback()181 int32_t VDecFuzzSample::SetVideoDecoderCallback()
182 {
183 signal_ = new VDecSignal();
184 if (signal_ == nullptr) {
185 cout << "Failed to new VDecSignal" << endl;
186 return AV_ERR_UNKNOWN;
187 }
188
189 cb_.onError = VdecError;
190 cb_.onStreamChanged = VdecFormatChanged;
191 cb_.onNeedInputData = VdecInputDataReady;
192 cb_.onNeedOutputData = VdecOutputDataReady;
193 return OH_VideoDecoder_SetCallback(vdec_, cb_, static_cast<void *>(signal_));
194 }
195
ReleaseInFile()196 void VDecFuzzSample::ReleaseInFile()
197 {
198 if (inFile_ != nullptr) {
199 if (inFile_->is_open()) {
200 inFile_->close();
201 }
202 inFile_.reset();
203 inFile_ = nullptr;
204 }
205 }
206
StopInLoop()207 void VDecFuzzSample::StopInLoop()
208 {
209 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
210 unique_lock<mutex> lock(signal_->inMutex_);
211 clearIntqueue(signal_->inIdxQueue_);
212 signal_->inCond_.notify_all();
213 lock.unlock();
214
215 inputLoop_->join();
216 inputLoop_.reset();
217 }
218 }
219
StartVideoDecoder()220 int32_t VDecFuzzSample::StartVideoDecoder()
221 {
222 int ret = OH_VideoDecoder_Start(vdec_);
223 if (ret != AV_ERR_OK) {
224 cout << "Failed to start codec" << endl;
225 return ret;
226 }
227 isRunning_.store(true);
228 inFile_ = make_unique<ifstream>();
229 if (inFile_ == nullptr) {
230 isRunning_.store(false);
231 (void)OH_VideoDecoder_Stop(vdec_);
232 return AV_ERR_UNKNOWN;
233 }
234 inFile_->open(inpDir, ios::in | ios::binary);
235 if (!inFile_->is_open()) {
236 cout << "failed open file " << endl;
237 isRunning_.store(false);
238 (void)OH_VideoDecoder_Stop(vdec_);
239 inFile_->close();
240 inFile_.reset();
241 inFile_ = nullptr;
242 return AV_ERR_UNKNOWN;
243 }
244
245 inputLoop_ = make_unique<thread>(&VDecFuzzSample::InputFuncAVCC, this);
246 if (inputLoop_ == nullptr) {
247 cout << "Failed to create input loop" << endl;
248 isRunning_.store(false);
249 (void)OH_VideoDecoder_Stop(vdec_);
250 ReleaseInFile();
251 return AV_ERR_UNKNOWN;
252 }
253 return AV_ERR_OK;
254 }
255
CreateVideoDecoder()256 int32_t VDecFuzzSample::CreateVideoDecoder()
257 {
258 OH_AVCapability *cap = OH_AVCodec_GetCapabilityByCategory(OH_AVCODEC_MIMETYPE_VIDEO_HEVC, false, HARDWARE);
259 string codecName = OH_AVCapability_GetName(cap);
260 vdec_ = OH_VideoDecoder_CreateByName("aabbcc");
261 if (vdec_) {
262 OH_VideoDecoder_Destroy(vdec_);
263 vdec_ = nullptr;
264 }
265 OH_AVCodec *tmpDec = OH_VideoDecoder_CreateByMime("aabbcc");
266 if (tmpDec) {
267 OH_VideoDecoder_Destroy(tmpDec);
268 tmpDec = nullptr;
269 }
270 tmpDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
271 if (tmpDec) {
272 OH_VideoDecoder_Destroy(tmpDec);
273 tmpDec = nullptr;
274 }
275 vdec_ = OH_VideoDecoder_CreateByName(codecName.c_str());
276 g_decSample = this;
277 return vdec_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
278 }
279
WaitForEOS()280 void VDecFuzzSample::WaitForEOS()
281 {
282 if (inputLoop_ && inputLoop_->joinable()) {
283 inputLoop_->join();
284 }
285 }
286
CopyStartCode(uint8_t * frameBuffer,uint32_t bufferSize,OH_AVCodecBufferAttr & attr)287 void VDecFuzzSample::CopyStartCode(uint8_t *frameBuffer, uint32_t bufferSize, OH_AVCodecBufferAttr &attr)
288 {
289 switch (frameBuffer[START_CODE_SIZE] & H264_NALU_TYPE) {
290 case SPS:
291 case PPS:
292 case SEI:
293 if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
294 cout << "Fatal: memory copy failed" << endl;
295 }
296 attr.pts = GetSystemTimeUs();
297 attr.size = bufferSize + START_CODE_SIZE;
298 attr.offset = 0;
299 attr.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
300 break;
301 default: {
302 if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
303 cout << "Fatal: memory copy failed" << endl;
304 }
305 attr.pts = GetSystemTimeUs();
306 attr.size = bufferSize + START_CODE_SIZE;
307 attr.offset = 0;
308 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
309 }
310 }
311 }
312
ReadData(uint32_t index,OH_AVMemory * buffer)313 int32_t VDecFuzzSample::ReadData(uint32_t index, OH_AVMemory *buffer)
314 {
315 uint8_t ch[4] = {};
316 (void)inFile_->read(reinterpret_cast<char *>(ch), START_CODE_SIZE);
317 if (inFile_->eof()) {
318 SetEOS(index);
319 return 1;
320 }
321 uint32_t bufferSize = static_cast<uint32_t>(((ch[3] & 0xFF)) | ((ch[2] & 0xFF) << EIGHT) |
322 ((ch[1] & 0xFF) << SIXTEEN) | ((ch[0] & 0xFF) << TWENTY_FOUR));
323
324 return SendData(bufferSize, index, buffer);
325 }
326
SendData(uint32_t bufferSize,uint32_t index,OH_AVMemory * buffer)327 uint32_t VDecFuzzSample::SendData(uint32_t bufferSize, uint32_t index, OH_AVMemory *buffer)
328 {
329 OH_AVCodecBufferAttr attr;
330 uint8_t *frameBuffer = new uint8_t[bufferSize + START_CODE_SIZE];
331 (void)inFile_->read(reinterpret_cast<char *>(frameBuffer + START_CODE_SIZE), bufferSize);
332 CopyStartCode(frameBuffer, bufferSize, attr);
333 int32_t size = OH_AVMemory_GetSize(buffer);
334 if (size < attr.size) {
335 delete[] frameBuffer;
336 isRunning_.store(false);
337 return 1;
338 }
339 uint8_t *bufferAddr = OH_AVMemory_GetAddr(buffer);
340 if (memcpy_s(bufferAddr, size, frameBuffer, attr.size) != EOK) {
341 delete[] frameBuffer;
342 isRunning_.store(false);
343 return 1;
344 }
345 delete[] frameBuffer;
346 int32_t ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
347 if (ret != AV_ERR_OK) {
348 errCount++;
349 }
350 frameCount_++;
351 if (inFile_->eof()) {
352 isRunning_.store(false);
353 }
354 return 0;
355 }
356
InputFuncAVCC()357 void VDecFuzzSample::InputFuncAVCC()
358 {
359 frameCount_ = 1;
360 errCount = 0;
361 while (true) {
362 if (!isRunning_.load()) {
363 break;
364 }
365 unique_lock<mutex> lock(signal_->inMutex_);
366 signal_->inCond_.wait(lock, [this]() {
367 if (!isRunning_.load()) {
368 cout << "quit signal" << endl;
369 return true;
370 }
371 return signal_->inIdxQueue_.size() > 0;
372 });
373 if (!isRunning_.load()) {
374 break;
375 }
376 uint32_t index = signal_->inIdxQueue_.front();
377 auto buffer = signal_->inBufferQueue_.front();
378 signal_->inIdxQueue_.pop();
379 signal_->inBufferQueue_.pop();
380 lock.unlock();
381 if (!inFile_->eof()) {
382 int ret = ReadData(index, buffer);
383 if (ret == 1) {
384 break;
385 }
386 }
387 }
388 }
389
InputFuncFUZZ(const uint8_t * data,size_t size)390 OH_AVErrCode VDecFuzzSample::InputFuncFUZZ(const uint8_t *data, size_t size)
391 {
392 uint32_t index;
393 unique_lock<mutex> lock(signal_->inMutex_);
394 signal_->inCond_.wait(lock, [this]() {
395 if (!isRunning_.load() && g_fuzzError) {
396 return true;
397 }
398 return signal_->inIdxQueue_.size() > 0;
399 });
400 if (g_fuzzError)
401 return AV_ERR_TIMEOUT;
402 index = signal_->inIdxQueue_.front();
403 auto buffer = signal_->inBufferQueue_.front();
404 signal_->inIdxQueue_.pop();
405 signal_->inBufferQueue_.pop();
406 lock.unlock();
407 int32_t bufferSize = OH_AVMemory_GetSize(buffer);
408 uint8_t *bufferAddr = OH_AVMemory_GetAddr(buffer);
409 OH_AVCodecBufferAttr attr;
410 attr.size = bufferSize;
411 attr.offset = 0;
412 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
413 if (memcpy_s(bufferAddr, bufferSize, data, size) != EOK) {
414 cout << "Fatal: memcpy fail" << endl;
415 OH_VideoDecoder_PushInputData(vdec_, index, attr);
416 return AV_ERR_NO_MEMORY;
417 }
418 attr.pts = GetSystemTimeUs();
419 OH_AVErrCode ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
420 return ret;
421 }
422
SetEOS(uint32_t index)423 void VDecFuzzSample::SetEOS(uint32_t index)
424 {
425 OH_AVCodecBufferAttr attr;
426 attr.pts = 0;
427 attr.size = 0;
428 attr.offset = 0;
429 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
430 int32_t res = OH_VideoDecoder_PushInputData(vdec_, index, attr);
431 cout << "OH_VideoDecoder_PushInputData EOS res: " << res << endl;
432 }
433
Flush()434 int32_t VDecFuzzSample::Flush()
435 {
436 unique_lock<mutex> inLock(signal_->inMutex_);
437 clearIntqueue(signal_->inIdxQueue_);
438 signal_->inCond_.notify_all();
439 inLock.unlock();
440 isRunning_.store(false);
441 return OH_VideoDecoder_Flush(vdec_);
442 }
443
Reset()444 int32_t VDecFuzzSample::Reset()
445 {
446 isRunning_.store(false);
447 StopInLoop();
448 ReleaseInFile();
449 return OH_VideoDecoder_Reset(vdec_);
450 }
451
Release()452 int32_t VDecFuzzSample::Release()
453 {
454 int ret = 0;
455 if (vdec_ != nullptr) {
456 ret = OH_VideoDecoder_Destroy(vdec_);
457 vdec_ = nullptr;
458 }
459
460 if (signal_ != nullptr) {
461 clearAvBufferQueue(signal_->inBufferQueue_);
462 delete signal_;
463 signal_ = nullptr;
464 }
465 return ret;
466 }
467
Stop()468 int32_t VDecFuzzSample::Stop()
469 {
470 StopInLoop();
471 ReleaseInFile();
472 return OH_VideoDecoder_Stop(vdec_);
473 }
474
Start()475 int32_t VDecFuzzSample::Start()
476 {
477 int32_t ret = OH_VideoDecoder_Start(vdec_);
478 if (ret == AV_ERR_OK) {
479 isRunning_.store(true);
480 }
481 return ret;
482 }
483
SetParameter(int32_t data)484 void VDecFuzzSample::SetParameter(int32_t data)
485 {
486 OH_AVFormat *format = OH_AVFormat_Create();
487 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, data);
488 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, data);
489 OH_VideoDecoder_SetParameter(vdec_, format);
490 OH_AVFormat_Destroy(format);
491 }