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