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