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