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