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