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