1 /*
2 * Copyright (C) 2024 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 "openssl/crypto.h"
20 #include "openssl/sha.h"
21 #include "native_buffer_inner.h"
22 #include "videoenc_api11_sample.h"
23 using namespace OHOS;
24 using namespace OHOS::Media;
25 using namespace std;
26 namespace {
27 constexpr int64_t NANOS_IN_SECOND = 1000000000L;
28 constexpr int64_t NANOS_IN_MICRO = 1000L;
29 constexpr uint32_t FRAME_INTERVAL = 16666;
30 constexpr uint32_t MAX_PIXEL_FMT = 5;
31 constexpr uint32_t DEFAULT_BITRATE = 10000000;
32 constexpr uint32_t DOUBLE = 2;
33 sptr<Surface> cs = nullptr;
34 sptr<Surface> ps = nullptr;
35
36
clearIntqueue(std::queue<uint32_t> & q)37 void clearIntqueue(std::queue<uint32_t> &q)
38 {
39 std::queue<uint32_t> empty;
40 swap(empty, q);
41 }
42 } // namespace
43
~VEncAPI11FuzzSample()44 VEncAPI11FuzzSample::~VEncAPI11FuzzSample()
45 {
46 if (surfInput && nativeWindow) {
47 OH_NativeWindow_DestroyNativeWindow(nativeWindow);
48 nativeWindow = nullptr;
49 }
50 Release();
51 }
52
VencError(OH_AVCodec * codec,int32_t errorCode,void * userData)53 static void VencError(OH_AVCodec *codec, int32_t errorCode, void *userData)
54 {
55 cout << "Error errorCode=" << errorCode << endl;
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
ConfigureVideoEncoderFuzz(int32_t data)93 int32_t VEncAPI11FuzzSample::ConfigureVideoEncoderFuzz(int32_t data)
94 {
95 OH_AVFormat *format = OH_AVFormat_Create();
96 if (format == nullptr) {
97 cout << "Fatal: Failed to create format" << endl;
98 return AV_ERR_UNKNOWN;
99 }
100 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, data);
101 defaultWidth = data;
102 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, data);
103 defaultHeight = data;
104 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, data % MAX_PIXEL_FMT);
105 double frameRate = data;
106 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, frameRate);
107
108 OH_AVFormat_SetIntValue(format, OH_MD_KEY_RANGE_FLAG, data);
109 OH_AVFormat_SetIntValue(format, OH_MD_KEY_COLOR_PRIMARIES, data);
110 OH_AVFormat_SetIntValue(format, OH_MD_KEY_TRANSFER_CHARACTERISTICS, data);
111 OH_AVFormat_SetIntValue(format, OH_MD_KEY_MATRIX_COEFFICIENTS, data);
112 OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, data);
113 OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, data);
114 OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, data);
115 OH_AVFormat_SetIntValue(format, OH_MD_KEY_QUALITY, data);
116
117 int ret = OH_VideoEncoder_Configure(venc_, format);
118 OH_AVFormat_Destroy(format);
119 return ret;
120 }
121
ConfigureVideoEncoder()122 int32_t VEncAPI11FuzzSample::ConfigureVideoEncoder()
123 {
124 OH_AVFormat *format = OH_AVFormat_Create();
125 if (format == nullptr) {
126 return AV_ERR_UNKNOWN;
127 }
128 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, defaultWidth);
129 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, defaultHeight);
130 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, defaultPixFmt);
131 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, defaultFrameRate);
132 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, defaultKeyFrameInterval);
133 if (defaultBitRate == CQ) {
134 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_QUALITY, defaultQuality);
135 } else {
136 (void)OH_AVFormat_SetLongValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, defaultBitRate);
137 }
138 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, defaultBitrateMode);
139 int ret = OH_VideoEncoder_Configure(venc_, format);
140 OH_AVFormat_Destroy(format);
141 return ret;
142 }
SetVideoEncoderCallback()143 int32_t VEncAPI11FuzzSample::SetVideoEncoderCallback()
144 {
145 signal_ = new VEncSignal();
146 if (signal_ == nullptr) {
147 cout << "Failed to new VEncSignal" << endl;
148 return AV_ERR_UNKNOWN;
149 }
150 if (surfInput) {
151 int32_t ret = OH_VideoEncoder_RegisterParameterCallback(venc_, onEncInputParam, static_cast<void *>(this));
152 if (ret != AV_ERR_OK) {
153 return ret;
154 }
155 }
156 cb_.onError = VencError;
157 cb_.onStreamChanged = VencFormatChanged;
158 cb_.onNeedInputBuffer = onEncInputBufferAvailable;
159 cb_.onNewOutputBuffer = onEncOutputBufferAvailable;
160 return OH_VideoEncoder_RegisterCallback(venc_, cb_, static_cast<void *>(signal_));
161 }
162
StopInloop()163 void VEncAPI11FuzzSample::StopInloop()
164 {
165 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
166 unique_lock<mutex> lock(signal_->inMutex_);
167 clearIntqueue(signal_->inIdxQueue_);
168 isRunning_.store(false);
169 signal_->inCond_.notify_all();
170 lock.unlock();
171
172 inputLoop_->join();
173 inputLoop_ = nullptr;
174 }
175 }
176
ReleaseInFile()177 void VEncAPI11FuzzSample::ReleaseInFile()
178 {
179 if (inFile_ != nullptr) {
180 if (inFile_->is_open()) {
181 inFile_->close();
182 }
183 inFile_.reset();
184 inFile_ = nullptr;
185 }
186 }
187
CreateSurface()188 int32_t VEncAPI11FuzzSample::CreateSurface()
189 {
190 int32_t ret = 0;
191 ret = OH_VideoEncoder_GetSurface(venc_, &nativeWindow);
192 if (ret != AV_ERR_OK) {
193 cout << "OH_VideoEncoder_GetSurface fail" << endl;
194 return ret;
195 }
196 ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_FORMAT, GRAPHIC_PIXEL_FMT_YCBCR_420_SP);
197 if (ret != AV_ERR_OK) {
198 cout << "NativeWindowHandleOpt SET_FORMAT fail" << endl;
199 return ret;
200 }
201 ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_BUFFER_GEOMETRY, defaultWidth, defaultHeight);
202 if (ret != AV_ERR_OK) {
203 cout << "NativeWindowHandleOpt SET_BUFFER_GEOMETRY fail" << endl;
204 return ret;
205 }
206 return AV_ERR_OK;
207 }
208
OpenFile()209 int32_t VEncAPI11FuzzSample::OpenFile()
210 {
211 int32_t ret = AV_ERR_OK;
212 inFile_ = make_unique<ifstream>();
213 if (inFile_ == nullptr) {
214 isRunning_.store(false);
215 (void)OH_VideoEncoder_Stop(venc_);
216 return AV_ERR_UNKNOWN;
217 }
218 inFile_->open(inpDir, ios::in | ios::binary);
219 if (!inFile_->is_open()) {
220 cout << "file open fail" << endl;
221 isRunning_.store(false);
222 (void)OH_VideoEncoder_Stop(venc_);
223 inFile_->close();
224 inFile_.reset();
225 inFile_ = nullptr;
226 return AV_ERR_UNKNOWN;
227 }
228 return ret;
229 }
230
GetStride()231 void VEncAPI11FuzzSample::GetStride()
232 {
233 OH_AVFormat *format = OH_VideoEncoder_GetInputDescription(venc_);
234 int32_t inputStride = 0;
235 OH_AVFormat_GetIntValue(format, "stride", &inputStride);
236 stride_ = inputStride;
237 OH_AVFormat_Destroy(format);
238 }
239
StartVideoEncoder()240 int32_t VEncAPI11FuzzSample::StartVideoEncoder()
241 {
242 isRunning_.store(true);
243 int32_t ret = 0;
244 if (surfInput) {
245 ret = CreateSurface();
246 if (ret != AV_ERR_OK) {
247 return ret;
248 }
249 }
250 if (OpenFile() != AV_ERR_OK) {
251 return AV_ERR_UNKNOWN;
252 }
253 ret = OH_VideoEncoder_Start(venc_);
254 GetStride();
255 if (ret != AV_ERR_OK) {
256 isRunning_.store(false);
257 signal_->inCond_.notify_all();
258 return ret;
259 }
260 if (surfInput) {
261 inputLoop_ = make_unique<thread>(&VEncAPI11FuzzSample::InputFuncSurface, this);
262 } else {
263 inputLoop_ = make_unique<thread>(&VEncAPI11FuzzSample::InputFunc, this);
264 }
265 if (inputLoop_ == nullptr) {
266 isRunning_.store(false);
267 (void)OH_VideoEncoder_Stop(venc_);
268 return AV_ERR_UNKNOWN;
269 }
270 return AV_ERR_OK;
271 }
272
CreateVideoEncoder()273 int32_t VEncAPI11FuzzSample::CreateVideoEncoder()
274 {
275 venc_ = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
276 return venc_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
277 }
278
WaitForEOS()279 void VEncAPI11FuzzSample::WaitForEOS()
280 {
281 if (inputLoop_)
282 inputLoop_->join();
283 inputLoop_ = nullptr;
284 }
285
PushData(OH_AVBuffer * buffer,uint32_t index,int32_t & result)286 int32_t VEncAPI11FuzzSample::PushData(OH_AVBuffer *buffer, uint32_t index, int32_t &result)
287 {
288 int32_t res = -2;
289 OH_AVCodecBufferAttr attr;
290 uint8_t *fileBuffer = OH_AVBuffer_GetAddr(buffer);
291 if (fileBuffer == nullptr) {
292 cout << "Fatal: no memory" << endl;
293 return -1;
294 }
295 int32_t size = OH_AVBuffer_GetCapacity(buffer);
296 if (size < (defaultWidth * stride_ + (defaultWidth * stride_ / DOUBLE))) {
297 return -1;
298 }
299 attr.size = ReadOneFrameYUV420SP(fileBuffer);
300 if (inFile_->eof()) {
301 SetEOS(index, buffer);
302 return 0;
303 }
304 attr.pts = GetSystemTimeUs();
305 attr.offset = 0;
306 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
307 OH_AVBuffer_SetBufferAttr(buffer, &attr);
308 result = OH_VideoEncoder_PushInputBuffer(venc_, index);
309 frameCount++;
310 unique_lock<mutex> lock(signal_->inMutex_);
311 signal_->inIdxQueue_.pop();
312 signal_->inBufferQueue_.pop();
313 return res;
314 }
315
ReadOneFrameYUV420SP(uint8_t * dst)316 uint32_t VEncAPI11FuzzSample::ReadOneFrameYUV420SP(uint8_t *dst)
317 {
318 uint8_t *start = dst;
319 // copy Y
320 for (uint32_t i = 0; i < defaultWidth; i++) {
321 inFile_->read(reinterpret_cast<char *>(dst), defaultWidth);
322 if (!ReturnZeroIfEOS(defaultWidth)) {
323 return 0;
324 }
325 dst += stride_;
326 }
327 // copy UV
328 for (uint32_t i = 0; i < defaultWidth / DOUBLE; i++) {
329 inFile_->read(reinterpret_cast<char *>(dst), defaultWidth);
330 if (!ReturnZeroIfEOS(defaultWidth)) {
331 return 0;
332 }
333 dst += stride_;
334 }
335 return dst - start;
336 }
337
ReturnZeroIfEOS(uint32_t expectedSize)338 uint32_t VEncAPI11FuzzSample::ReturnZeroIfEOS(uint32_t expectedSize)
339 {
340 if (inFile_->gcount() != (expectedSize)) {
341 cout << "no more data" << endl;
342 return 0;
343 }
344 return 1;
345 }
346
FlushSurf(OHNativeWindowBuffer * ohNativeWindowBuffer,OH_NativeBuffer * nativeBuffer)347 uint32_t VEncAPI11FuzzSample::FlushSurf(OHNativeWindowBuffer *ohNativeWindowBuffer, OH_NativeBuffer *nativeBuffer)
348 {
349 struct Region region;
350 struct Region::Rect *rect = new Region::Rect();
351 rect->x = 0;
352 rect->y = 0;
353 rect->w = defaultWidth;
354 rect->h = defaultHeight;
355 region.rects = rect;
356 NativeWindowHandleOpt(nativeWindow, SET_UI_TIMESTAMP, GetSystemTimeUs());
357 int32_t err = OH_NativeBuffer_Unmap(nativeBuffer);
358 if (err != 0) {
359 return 1;
360 }
361 err = OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, ohNativeWindowBuffer, -1, region);
362 delete rect;
363 if (err != 0) {
364 return 1;
365 }
366 return 0;
367 }
368
InputFuncSurface()369 void VEncAPI11FuzzSample::InputFuncSurface()
370 {
371 while (isRunning_.load()) {
372 OHNativeWindowBuffer *ohNativeWindowBuffer;
373 int fenceFd = -1;
374 if (nativeWindow == nullptr) {
375 cout << "nativeWindow == nullptr" << endl;
376 isRunning_.store(false);
377 break;
378 }
379 int32_t err = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &ohNativeWindowBuffer, &fenceFd);
380 if (err != 0) {
381 cout << "RequestBuffer failed, GSError=" << err << endl;
382 isRunning_.store(false);
383 break;
384 }
385 if (fenceFd > 0) {
386 close(fenceFd);
387 }
388 OH_NativeBuffer *nativeBuffer = OH_NativeBufferFromNativeWindowBuffer(ohNativeWindowBuffer);
389 void *virAddr = nullptr;
390 err = OH_NativeBuffer_Map(nativeBuffer, &virAddr);
391 if (err != 0) {
392 cout << "OH_NativeBuffer_Map failed, GSError=" << err << endl;
393 isRunning_.store(false);
394 break;
395 }
396 if (frameCount == maxFrameInput) {
397 err = OH_VideoEncoder_NotifyEndOfStream(venc_);
398 if (err != 0) {
399 cout << "OH_VideoEncoder_NotifyEndOfStream failed" << endl;
400 isRunning_.store(false);
401 }
402 break;
403 }
404 if (FlushSurf(ohNativeWindowBuffer, nativeBuffer)) {
405 break;
406 }
407 usleep(FRAME_INTERVAL);
408 frameCount++;
409 }
410 }
411
SetEOS(uint32_t index,OH_AVBuffer * buffer)412 void VEncAPI11FuzzSample::SetEOS(uint32_t index, OH_AVBuffer *buffer)
413 {
414 OH_AVCodecBufferAttr attr;
415 attr.pts = 0;
416 attr.size = 0;
417 attr.offset = 0;
418 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
419 OH_AVBuffer_SetBufferAttr(buffer, &attr);
420 int32_t res = OH_VideoEncoder_PushInputBuffer(venc_, index);
421 cout << "OH_VideoEncoder_PushInputBuffer EOS res: " << res << endl;
422 unique_lock<mutex> lock(signal_->inMutex_);
423 signal_->inIdxQueue_.pop();
424 signal_->inBufferQueue_.pop();
425 }
426
InputFunc()427 void VEncAPI11FuzzSample::InputFunc()
428 {
429 errCount = 0;
430 while (isRunning_.load()) {
431 unique_lock<mutex> lock(signal_->inMutex_);
432 signal_->inCond_.wait(lock, [this]() {
433 if (!isRunning_.load()) {
434 return true;
435 }
436 return signal_->inIdxQueue_.size() > 0;
437 });
438 if (!isRunning_.load()) {
439 break;
440 }
441 uint32_t index = signal_->inIdxQueue_.front();
442 auto buffer = signal_->inBufferQueue_.front();
443
444 lock.unlock();
445 OH_AVCodecBufferAttr attr;
446 uint8_t *fileBuffer = OH_AVBuffer_GetAddr(buffer);
447 if (fileBuffer == nullptr) {
448 break;
449 }
450 attr.size = OH_AVBuffer_GetCapacity(buffer);
451 if (frameCount == maxFrameInput) {
452 SetEOS(index, buffer);
453 break;
454 }
455 attr.pts = GetSystemTimeUs();
456 attr.offset = 0;
457 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
458 OH_AVBuffer_SetBufferAttr(buffer, &attr);
459 OH_VideoEncoder_PushInputBuffer(venc_, index);
460 frameCount++;
461 signal_->inIdxQueue_.pop();
462 signal_->inBufferQueue_.pop();
463 if (sleepOnFPS) {
464 usleep(FRAME_INTERVAL);
465 }
466 }
467 }
468
CheckAttrFlag(OH_AVCodecBufferAttr attr)469 int32_t VEncAPI11FuzzSample::CheckAttrFlag(OH_AVCodecBufferAttr attr)
470 {
471 if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) {
472 cout << "attr.flags == AVCODEC_BUFFER_FLAGS_EOS" << endl;
473 unique_lock<mutex> inLock(signal_->inMutex_);
474 isRunning_.store(false);
475 signal_->inCond_.notify_all();
476 inLock.unlock();
477 return -1;
478 }
479 if (attr.flags == AVCODEC_BUFFER_FLAGS_CODEC_DATA) {
480 cout << "enc AVCODEC_BUFFER_FLAGS_CODEC_DATA" << attr.pts << endl;
481 }
482 return 0;
483 }
484
Flush()485 int32_t VEncAPI11FuzzSample::Flush()
486 {
487 unique_lock<mutex> inLock(signal_->inMutex_);
488 clearIntqueue(signal_->inIdxQueue_);
489 signal_->inCond_.notify_all();
490 inLock.unlock();
491 return OH_VideoEncoder_Flush(venc_);
492 }
493
Reset()494 int32_t VEncAPI11FuzzSample::Reset()
495 {
496 isRunning_.store(false);
497 StopInloop();
498 return OH_VideoEncoder_Reset(venc_);
499 }
500
Release()501 int32_t VEncAPI11FuzzSample::Release()
502 {
503 int ret = OH_VideoEncoder_Destroy(venc_);
504 venc_ = nullptr;
505 if (signal_ != nullptr) {
506 delete signal_;
507 signal_ = nullptr;
508 }
509 return ret;
510 }
511
Stop()512 int32_t VEncAPI11FuzzSample::Stop()
513 {
514 StopInloop();
515 return OH_VideoEncoder_Stop(venc_);
516 }
517
Start()518 int32_t VEncAPI11FuzzSample::Start()
519 {
520 return OH_VideoEncoder_Start(venc_);
521 }
522
SetParameter(int32_t data)523 int32_t VEncAPI11FuzzSample::SetParameter(int32_t data)
524 {
525 if (venc_) {
526 OH_AVFormat *format = OH_AVFormat_Create();
527 if (format == nullptr) {
528 return AV_ERR_UNKNOWN;
529 }
530 double frameRate = data;
531 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, frameRate);
532 OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, data);
533 int ret = OH_VideoEncoder_SetParameter(venc_, format);
534 OH_AVFormat_Destroy(format);
535 return ret;
536 }
537 return AV_ERR_UNKNOWN;
538 }