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