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