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