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 "iconsumer_surface.h"
19 #include "native_buffer_inner.h"
20 #include "videoenc_api11_sample.h"
21 using namespace OHOS;
22 using namespace OHOS::Media;
23 using namespace std;
24 namespace {
25 constexpr int64_t NANOS_IN_SECOND = 1000000000L;
26 constexpr int64_t NANOS_IN_MICRO = 1000L;
27 constexpr uint32_t FRAME_INTERVAL = 16666;
28 constexpr uint32_t DEFAULT_BITRATE = 10000000;
29 constexpr uint32_t DOUBLE = 2;
30 constexpr uint32_t THREE = 3;
31 sptr<Surface> cs = nullptr;
32 sptr<Surface> ps = nullptr;
33 VEncAPI11FuzzSample *g_vEncSample = nullptr;
34
35 } // namespace
36
~VEncAPI11FuzzSample()37 VEncAPI11FuzzSample::~VEncAPI11FuzzSample()
38 {
39 if (surfInput && nativeWindow) {
40 OH_NativeWindow_DestroyNativeWindow(nativeWindow);
41 nativeWindow = nullptr;
42 }
43 Release();
44 }
45
VencError(OH_AVCodec * codec,int32_t errorCode,void * userData)46 static void VencError(OH_AVCodec *codec, int32_t errorCode, void *userData)
47 {
48 cout << "Error errorCode=" << errorCode << endl;
49 g_vEncSample->isRunning_.store(false);
50 g_vEncSample->signal_->inCond_.notify_all();
51 }
52
VencFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)53 static void VencFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
54 {
55 cout << "Format Changed" << endl;
56 }
57
onEncInputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * buffer,void * userData)58 static void onEncInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
59 {
60 VEncSignal *signal = static_cast<VEncSignal *>(userData);
61 unique_lock<mutex> lock(signal->inMutex_);
62 signal->inIdxQueue_.push(index);
63 signal->inBufferQueue_.push(buffer);
64 signal->inCond_.notify_all();
65 }
66
onEncOutputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * buffer,void * userData)67 static void onEncOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
68 {
69 OH_VideoEncoder_FreeOutputBuffer(codec, index);
70 }
71
onEncInputParam(OH_AVCodec * codec,uint32_t index,OH_AVFormat * parameter,void * userData)72 static void onEncInputParam(OH_AVCodec *codec, uint32_t index, OH_AVFormat *parameter, void *userData)
73 {
74 OH_AVFormat_SetIntValue(parameter, OH_MD_KEY_BITRATE, DEFAULT_BITRATE);
75 OH_VideoEncoder_PushInputParameter(codec, index);
76 return;
77 }
78
GetSystemTimeUs()79 int64_t VEncAPI11FuzzSample::GetSystemTimeUs()
80 {
81 struct timespec now;
82 (void)clock_gettime(CLOCK_BOOTTIME, &now);
83 int64_t nanoTime = reinterpret_cast<int64_t>(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec;
84
85 return nanoTime / NANOS_IN_MICRO;
86 }
87
ConfigureVideoEncoder()88 int32_t VEncAPI11FuzzSample::ConfigureVideoEncoder()
89 {
90 OH_AVFormat *format = OH_AVFormat_Create();
91 if (format == nullptr) {
92 return AV_ERR_UNKNOWN;
93 }
94 OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, HEVC_PROFILE_MAIN_10);
95 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, defaultWidth);
96 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, defaultHeight);
97 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, defaultPixFmt);
98 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, defaultFrameRate);
99 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, defaultKeyFrameInterval);
100 if (defaultBitRate == CQ) {
101 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_QUALITY, defaultQuality);
102 } else {
103 (void)OH_AVFormat_SetLongValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, defaultBitRate);
104 }
105 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, defaultBitrateMode);
106 if (enableRepeat) {
107 OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_REPEAT_PREVIOUS_FRAME_AFTER, 1);
108 if (setMaxCount) {
109 OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_REPEAT_PREVIOUS_MAX_COUNT, 1);
110 }
111 }
112 int ret = OH_VideoEncoder_Configure(venc_, format);
113 OH_AVFormat_Destroy(format);
114 return ret;
115 }
SetVideoEncoderCallback()116 int32_t VEncAPI11FuzzSample::SetVideoEncoderCallback()
117 {
118 signal_ = new VEncSignal();
119 if (signal_ == nullptr) {
120 cout << "Failed to new VEncSignal" << endl;
121 return AV_ERR_UNKNOWN;
122 }
123 if (surfInput) {
124 int32_t ret = OH_VideoEncoder_RegisterParameterCallback(venc_, onEncInputParam, static_cast<void *>(this));
125 if (ret != AV_ERR_OK) {
126 return ret;
127 }
128 }
129 cb_.onError = VencError;
130 cb_.onStreamChanged = VencFormatChanged;
131 cb_.onNeedInputBuffer = onEncInputBufferAvailable;
132 cb_.onNewOutputBuffer = onEncOutputBufferAvailable;
133 return OH_VideoEncoder_RegisterCallback(venc_, cb_, static_cast<void *>(signal_));
134 }
135
CreateSurface()136 int32_t VEncAPI11FuzzSample::CreateSurface()
137 {
138 int32_t ret = 0;
139 ret = OH_VideoEncoder_GetSurface(venc_, &nativeWindow);
140 if (ret != AV_ERR_OK) {
141 cout << "OH_VideoEncoder_GetSurface fail" << endl;
142 return ret;
143 }
144 ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_FORMAT, GRAPHIC_PIXEL_FMT_YCBCR_420_SP);
145 if (ret != AV_ERR_OK) {
146 cout << "NativeWindowHandleOpt SET_FORMAT fail" << endl;
147 return ret;
148 }
149 ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_BUFFER_GEOMETRY, defaultWidth, defaultHeight);
150 if (ret != AV_ERR_OK) {
151 cout << "NativeWindowHandleOpt SET_BUFFER_GEOMETRY fail" << endl;
152 return ret;
153 }
154 return AV_ERR_OK;
155 }
156
OpenFile()157 int32_t VEncAPI11FuzzSample::OpenFile()
158 {
159 if (fuzzMode) {
160 return AV_ERR_OK;
161 }
162 int32_t ret = AV_ERR_OK;
163 inFile_ = make_unique<ifstream>();
164 if (inFile_ == nullptr) {
165 isRunning_.store(false);
166 (void)OH_VideoEncoder_Stop(venc_);
167 return AV_ERR_UNKNOWN;
168 }
169 inFile_->open(inpDir, ios::in | ios::binary);
170 if (!inFile_->is_open()) {
171 cout << "file open fail" << endl;
172 isRunning_.store(false);
173 (void)OH_VideoEncoder_Stop(venc_);
174 inFile_->close();
175 inFile_.reset();
176 inFile_ = nullptr;
177 return AV_ERR_UNKNOWN;
178 }
179 return ret;
180 }
181
GetStride()182 void VEncAPI11FuzzSample::GetStride()
183 {
184 OH_AVFormat *format = OH_VideoEncoder_GetInputDescription(venc_);
185 int32_t inputStride = 0;
186 OH_AVFormat_GetIntValue(format, "stride", &inputStride);
187 stride_ = inputStride;
188 OH_AVFormat_Destroy(format);
189 }
190
StartVideoEncoder()191 int32_t VEncAPI11FuzzSample::StartVideoEncoder()
192 {
193 isRunning_.store(true);
194 int32_t ret = 0;
195 if (surfInput) {
196 ret = CreateSurface();
197 if (ret != AV_ERR_OK) {
198 return ret;
199 }
200 }
201 if (OpenFile() != AV_ERR_OK) {
202 return AV_ERR_UNKNOWN;
203 }
204 ret = OH_VideoEncoder_Start(venc_);
205 GetStride();
206 if (ret != AV_ERR_OK) {
207 isRunning_.store(false);
208 signal_->inCond_.notify_all();
209 return ret;
210 }
211 if (surfInput) {
212 inputLoop_ = make_unique<thread>(&VEncAPI11FuzzSample::InputFuncSurface, this);
213 } else {
214 inputLoop_ = make_unique<thread>(&VEncAPI11FuzzSample::InputFunc, this);
215 }
216 if (inputLoop_ == nullptr) {
217 isRunning_.store(false);
218 (void)OH_VideoEncoder_Stop(venc_);
219 return AV_ERR_UNKNOWN;
220 }
221 return AV_ERR_OK;
222 }
223
CreateVideoEncoder()224 int32_t VEncAPI11FuzzSample::CreateVideoEncoder()
225 {
226 venc_ = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
227 g_vEncSample = this;
228 return venc_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
229 }
230
WaitForEOS()231 void VEncAPI11FuzzSample::WaitForEOS()
232 {
233 if (inputLoop_)
234 inputLoop_->join();
235 inputLoop_ = nullptr;
236 }
237
FlushSurf(OHNativeWindowBuffer * ohNativeWindowBuffer,OH_NativeBuffer * nativeBuffer)238 uint32_t VEncAPI11FuzzSample::FlushSurf(OHNativeWindowBuffer *ohNativeWindowBuffer, OH_NativeBuffer *nativeBuffer)
239 {
240 struct Region region;
241 struct Region::Rect *rect = new Region::Rect();
242 rect->x = 0;
243 rect->y = 0;
244 rect->w = defaultWidth;
245 rect->h = defaultHeight;
246 region.rects = rect;
247 NativeWindowHandleOpt(nativeWindow, SET_UI_TIMESTAMP, GetSystemTimeUs());
248 int32_t err = OH_NativeBuffer_Unmap(nativeBuffer);
249 if (err != 0) {
250 return 1;
251 }
252 err = OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, ohNativeWindowBuffer, -1, region);
253 delete rect;
254 if (err != 0) {
255 return 1;
256 }
257 return 0;
258 }
259
InputFuncSurface()260 void VEncAPI11FuzzSample::InputFuncSurface()
261 {
262 while (isRunning_.load()) {
263 OHNativeWindowBuffer *ohNativeWindowBuffer;
264 int fenceFd = -1;
265 if (nativeWindow == nullptr) {
266 cout << "nativeWindow == nullptr" << endl;
267 isRunning_.store(false);
268 break;
269 }
270 int32_t err = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &ohNativeWindowBuffer, &fenceFd);
271 if (err != 0) {
272 cout << "RequestBuffer failed, GSError=" << err << endl;
273 isRunning_.store(false);
274 break;
275 }
276 if (fenceFd > 0) {
277 close(fenceFd);
278 }
279 OH_NativeBuffer *nativeBuffer = OH_NativeBufferFromNativeWindowBuffer(ohNativeWindowBuffer);
280 void *virAddr = nullptr;
281 OH_NativeBuffer_Config config;
282 OH_NativeBuffer_GetConfig (nativeBuffer, &config);
283 err = OH_NativeBuffer_Map(nativeBuffer, &virAddr);
284 if (err != 0) {
285 cout << "OH_NativeBuffer_Map failed, GSError=" << err << endl;
286 isRunning_.store(false);
287 break;
288 }
289 uint8_t *dst = (uint8_t *)virAddr;
290 if (dst == nullptr) {
291 break;
292 }
293 if (memcpy_s(dst, (config.stride * config.height * THREE) / DOUBLE, fuzzData, fuzzSize) != EOK) {
294 break;
295 }
296 if (frameCount == maxFrameInput) {
297 err = OH_VideoEncoder_NotifyEndOfStream(venc_);
298 if (err != 0) {
299 cout << "OH_VideoEncoder_NotifyEndOfStream failed" << endl;
300 isRunning_.store(false);
301 }
302 break;
303 }
304 if (FlushSurf(ohNativeWindowBuffer, nativeBuffer)) {
305 break;
306 }
307 usleep(FRAME_INTERVAL);
308 frameCount++;
309 }
310 }
311
SetEOS(uint32_t index,OH_AVBuffer * buffer)312 void VEncAPI11FuzzSample::SetEOS(uint32_t index, OH_AVBuffer *buffer)
313 {
314 OH_AVCodecBufferAttr attr;
315 attr.pts = 0;
316 attr.size = 0;
317 attr.offset = 0;
318 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
319 OH_AVBuffer_SetBufferAttr(buffer, &attr);
320 int32_t res = OH_VideoEncoder_PushInputBuffer(venc_, index);
321 cout << "OH_VideoEncoder_PushInputBuffer EOS res: " << res << endl;
322 unique_lock<mutex> lock(signal_->inMutex_);
323 }
324
InputFunc()325 void VEncAPI11FuzzSample::InputFunc()
326 {
327 errCount = 0;
328 while (isRunning_.load()) {
329 unique_lock<mutex> lock(signal_->inMutex_);
330 signal_->inCond_.wait(lock, [this]() {
331 if (!isRunning_.load()) {
332 return true;
333 }
334 return signal_->inIdxQueue_.size() > 0;
335 });
336 if (!isRunning_.load()) {
337 break;
338 }
339 uint32_t index = signal_->inIdxQueue_.front();
340 auto buffer = signal_->inBufferQueue_.front();
341
342 signal_->inIdxQueue_.pop();
343 signal_->inBufferQueue_.pop();
344
345 lock.unlock();
346 OH_AVCodecBufferAttr attr;
347 int32_t bufferSize = OH_AVBuffer_GetCapacity(buffer);
348 uint8_t *fileBuffer = OH_AVBuffer_GetAddr(buffer);
349 if (fileBuffer == nullptr) {
350 break;
351 }
352 if (memcpy_s(fileBuffer, bufferSize, fuzzData, fuzzSize) != EOK) {
353 cout << "Fatal: memcpy fail" << endl;
354 break;
355 }
356 attr.size = fuzzSize;
357 if (frameCount == maxFrameInput) {
358 SetEOS(index, buffer);
359 break;
360 }
361 attr.pts = GetSystemTimeUs();
362 attr.offset = 0;
363 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
364 OH_AVBuffer_SetBufferAttr(buffer, &attr);
365 OH_VideoEncoder_PushInputBuffer(venc_, index);
366 frameCount++;
367 if (sleepOnFPS) {
368 usleep(FRAME_INTERVAL);
369 }
370 }
371 }
372
Release()373 int32_t VEncAPI11FuzzSample::Release()
374 {
375 int ret = OH_VideoEncoder_Destroy(venc_);
376 venc_ = nullptr;
377 if (signal_ != nullptr) {
378 delete signal_;
379 signal_ = nullptr;
380 }
381 return ret;
382 }
383
SetParameter(int32_t data)384 int32_t VEncAPI11FuzzSample::SetParameter(int32_t data)
385 {
386 if (venc_) {
387 OH_AVFormat *format = OH_AVFormat_Create();
388 if (format == nullptr) {
389 return AV_ERR_UNKNOWN;
390 }
391 double frameRate = data;
392 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, frameRate);
393 OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, data);
394 int ret = OH_VideoEncoder_SetParameter(venc_, format);
395 OH_AVFormat_Destroy(format);
396 return ret;
397 }
398 return AV_ERR_UNKNOWN;
399 }