• 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 const string MIME_TYPE = "video/hevc";
24 constexpr int64_t NANOS_IN_SECOND = 1000000000L;
25 constexpr int64_t NANOS_IN_MICRO = 1000L;
26 VDecFuzzSample *g_decSample = nullptr;
27 bool g_fuzzError = false;
28 
clearAvBufferQueue(std::queue<OH_AVMemory * > & q)29 void clearAvBufferQueue(std::queue<OH_AVMemory *> &q)
30 {
31     std::queue<OH_AVMemory *> empty;
32     swap(empty, q);
33 }
34 } // namespace
35 
36 class TestConsumerListener : public IBufferConsumerListener {
37 public:
TestConsumerListener(sptr<Surface> cs)38     TestConsumerListener(sptr<Surface> cs) : cs(cs) {};
~TestConsumerListener()39     ~TestConsumerListener() {}
OnBufferAvailable()40     void OnBufferAvailable() override
41     {
42         sptr<SurfaceBuffer> buffer;
43         int32_t flushFence;
44         cs->AcquireBuffer(buffer, flushFence, timestamp, damage);
45 
46         cs->ReleaseBuffer(buffer, -1);
47     }
48 
49 private:
50     int64_t timestamp = 0;
51     Rect damage = {};
52     sptr<Surface> cs {nullptr};
53 };
54 
~VDecFuzzSample()55 VDecFuzzSample::~VDecFuzzSample()
56 {
57     Release();
58 }
59 
VdecError(OH_AVCodec * codec,int32_t errorCode,void * userData)60 void VdecError(OH_AVCodec *codec, int32_t errorCode, void *userData)
61 {
62     VDecSignal *signal = static_cast<VDecSignal *>(userData);
63     if (signal == nullptr) {
64         return;
65     }
66     cout << "Error errorCode=" << errorCode << endl;
67     g_fuzzError = true;
68     signal->inCond_.notify_all();
69 }
70 
VdecFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)71 void VdecFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
72 {
73     cout << "Format Changed" << endl;
74     int32_t currentWidth = 0;
75     int32_t currentHeight = 0;
76     OH_AVFormat_GetIntValue(format, OH_MD_KEY_WIDTH, &currentWidth);
77     OH_AVFormat_GetIntValue(format, OH_MD_KEY_HEIGHT, &currentHeight);
78     g_decSample->defaultWidth = currentWidth;
79     g_decSample->defaultHeight = currentHeight;
80 }
81 
VdecInputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)82 void VdecInputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
83 {
84     VDecSignal *signal = static_cast<VDecSignal *>(userData);
85     if (signal == nullptr) {
86         return;
87     }
88     unique_lock<mutex> lock(signal->inMutex_);
89     signal->inIdxQueue_.push(index);
90     signal->inBufferQueue_.push(data);
91     signal->inCond_.notify_all();
92 }
93 
VdecOutputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)94 void VdecOutputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
95                          void *userData)
96 {
97     VDecSignal *signal = static_cast<VDecSignal *>(userData);
98     if (signal == nullptr) {
99         return;
100     }
101     unique_lock<mutex> lock(signal->outMutex_);
102     signal->outIdxQueue_.push(index);
103     signal->attrQueue_.push(*attr);
104     signal->outBufferQueue_.push(data);
105     signal->outCond_.notify_all();
106     if (g_decSample->isSurfMode) {
107         OH_VideoDecoder_RenderOutputData(codec, index);
108     } else {
109         OH_VideoDecoder_FreeOutputData(codec, index);
110     }
111 }
112 
GetSystemTimeUs()113 int64_t VDecFuzzSample::GetSystemTimeUs()
114 {
115     struct timespec now;
116     (void)clock_gettime(CLOCK_BOOTTIME, &now);
117     int64_t nanoTime = static_cast<int64_t>(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec;
118     return nanoTime / NANOS_IN_MICRO;
119 }
120 
ConfigureVideoDecoder()121 int32_t VDecFuzzSample::ConfigureVideoDecoder()
122 {
123     if (isSurfMode) {
124         cs = Surface::CreateSurfaceAsConsumer();
125         sptr<IBufferConsumerListener> listener = new TestConsumerListener(cs);
126         cs->RegisterConsumerListener(listener);
127         auto p = cs->GetProducer();
128         ps = Surface::CreateSurfaceAsProducer(p);
129         nativeWindow = CreateNativeWindowFromSurface(&ps);
130         OH_VideoDecoder_SetSurface(vdec_, nativeWindow);
131     }
132     OH_AVFormat *format = OH_AVFormat_Create();
133     if (format == nullptr) {
134         cout << "Fatal: Failed to create format" << endl;
135         return AV_ERR_UNKNOWN;
136     }
137     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, defaultWidth);
138     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, defaultHeight);
139     (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, defaultFrameRate);
140     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_NV12);
141     int ret = OH_VideoDecoder_Configure(vdec_, format);
142     OH_AVFormat_Destroy(format);
143     return ret;
144 }
145 
SetVideoDecoderCallback()146 int32_t VDecFuzzSample::SetVideoDecoderCallback()
147 {
148     signal_ = new VDecSignal();
149     if (signal_ == nullptr) {
150         cout << "Failed to new VDecSignal" << endl;
151         return AV_ERR_UNKNOWN;
152     }
153 
154     cb_.onError = VdecError;
155     cb_.onStreamChanged = VdecFormatChanged;
156     cb_.onNeedInputData = VdecInputDataReady;
157     cb_.onNeedOutputData = VdecOutputDataReady;
158     return OH_VideoDecoder_SetCallback(vdec_, cb_, static_cast<void *>(signal_));
159 }
160 
ReleaseInFile()161 void VDecFuzzSample::ReleaseInFile()
162 {
163     if (inFile_ != nullptr) {
164         if (inFile_->is_open()) {
165             inFile_->close();
166         }
167         inFile_.reset();
168         inFile_ = nullptr;
169     }
170 }
171 
StartVideoDecoder()172 int32_t VDecFuzzSample::StartVideoDecoder()
173 {
174     int ret = OH_VideoDecoder_Start(vdec_);
175     if (ret != AV_ERR_OK) {
176         cout << "Failed to start codec" << endl;
177         return ret;
178     }
179 
180     isRunning_.store(true);
181 
182     inFile_ = make_unique<ifstream>();
183     if (inFile_ == nullptr) {
184         isRunning_.store(false);
185         (void)OH_VideoDecoder_Stop(vdec_);
186         return AV_ERR_UNKNOWN;
187     }
188     inFile_->open(inpDir, ios::in | ios::binary);
189     if (!inFile_->is_open()) {
190         cout << "open input file failed" << endl;
191         isRunning_.store(false);
192         (void)OH_VideoDecoder_Stop(vdec_);
193         inFile_->close();
194         inFile_.reset();
195         inFile_ = nullptr;
196         return AV_ERR_UNKNOWN;
197     }
198 
199     inputLoop_ = make_unique<std::thread>([this]() {
200         this->InputFuncFUZZ(fuzzData, fuzzSize);
201     });
202     if (inputLoop_ == nullptr) {
203         cout << "Failed to create input loop" << endl;
204         isRunning_.store(false);
205         (void)OH_VideoDecoder_Stop(vdec_);
206         ReleaseInFile();
207         return AV_ERR_UNKNOWN;
208     }
209     return AV_ERR_OK;
210 }
211 
CreateVideoDecoder(string codeName)212 int32_t VDecFuzzSample::CreateVideoDecoder(string codeName)
213 {
214     vdec_ = OH_VideoDecoder_CreateByName(codeName.c_str());
215     g_decSample = this;
216     return vdec_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
217 }
218 
WaitForEOS()219 void VDecFuzzSample::WaitForEOS()
220 {
221     if (inputLoop_ && inputLoop_->joinable()) {
222         inputLoop_->join();
223     }
224 }
225 
InputFuncFUZZ(const uint8_t * data,size_t size)226 OH_AVErrCode VDecFuzzSample::InputFuncFUZZ(const uint8_t *data, size_t size)
227 {
228     uint32_t index;
229     unique_lock<mutex> lock(signal_->inMutex_);
230     signal_->inCond_.wait(lock, [this]() {
231         if (!isRunning_.load() && g_fuzzError) {
232             return true;
233         }
234         return signal_->inIdxQueue_.size() > 0;
235     });
236     if (g_fuzzError)
237         return AV_ERR_TIMEOUT;
238     index = signal_->inIdxQueue_.front();
239     auto buffer = signal_->inBufferQueue_.front();
240     lock.unlock();
241     uint8_t *bufferAddr = OH_AVMemory_GetAddr(buffer);
242 
243     if (memcpy_s(bufferAddr, fuzzSize, fuzzData, fuzzSize) != EOK) {
244         cout << "Fatal: memcpy fail" << endl;
245         return AV_ERR_NO_MEMORY;
246     }
247     OH_AVCodecBufferAttr attr;
248     attr.pts = GetSystemTimeUs();
249     attr.size = fuzzSize;
250     attr.offset = 0;
251     attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
252     OH_AVErrCode ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
253     signal_->inIdxQueue_.pop();
254     signal_->inBufferQueue_.pop();
255     return ret;
256 }
257 
Release()258 int32_t VDecFuzzSample::Release()
259 {
260     int ret = 0;
261     if (vdec_ != nullptr) {
262         ret = OH_VideoDecoder_Destroy(vdec_);
263         vdec_ = nullptr;
264     }
265     if (signal_ != nullptr) {
266         clearAvBufferQueue(signal_->inBufferQueue_);
267         clearAvBufferQueue(signal_->outBufferQueue_);
268         delete signal_;
269         signal_ = nullptr;
270     }
271     return ret;
272 }
273 
SetParameter(OH_AVFormat * format)274 int32_t VDecFuzzSample::SetParameter(OH_AVFormat *format)
275 {
276     return OH_VideoDecoder_SetParameter(vdec_, format);
277 }