• 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_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, &currentWidth);
92     OH_AVFormat_GetIntValue(format, OH_MD_KEY_HEIGHT, &currentHeight);
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 }