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, ¤tWidth);
77 OH_AVFormat_GetIntValue(format, OH_MD_KEY_HEIGHT, ¤tHeight);
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 }