1 /*
2 * Copyright (C) 2023 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 "openssl/crypto.h"
19 #include "openssl/sha.h"
20 #include "videoenc_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 MAX_PIXEL_FMT = 5;
29 constexpr uint8_t RGBA_SIZE = 4;
30 constexpr uint32_t IDR_FRAME_INTERVAL = 10;
31 constexpr uint32_t DOUBLE = 2;
32 VEncFuzzSample *g_encSample = nullptr;
33
clearIntqueue(std::queue<uint32_t> & q)34 void clearIntqueue(std::queue<uint32_t> &q)
35 {
36 std::queue<uint32_t> empty;
37 swap(empty, q);
38 }
39
clearBufferqueue(std::queue<OH_AVCodecBufferAttr> & q)40 void clearBufferqueue(std::queue<OH_AVCodecBufferAttr> &q)
41 {
42 std::queue<OH_AVCodecBufferAttr> empty;
43 swap(empty, q);
44 }
45 } // namespace
46
~VEncFuzzSample()47 VEncFuzzSample::~VEncFuzzSample()
48 {
49 Release();
50 }
51
VencError(OH_AVCodec * codec,int32_t errorCode,void * userData)52 static void VencError(OH_AVCodec *codec, int32_t errorCode, void *userData)
53 {
54 cout << "Error errorCode=" << errorCode << endl;
55 }
56
VencFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)57 static void VencFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
58 {
59 cout << "Format Changed" << endl;
60 }
61
VencInputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)62 static void VencInputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
63 {
64 VEncSignal *signal = static_cast<VEncSignal *>(userData);
65 unique_lock<mutex> lock(signal->inMutex_);
66 signal->inIdxQueue_.push(index);
67 signal->inBufferQueue_.push(data);
68 signal->inCond_.notify_all();
69 }
70
VencOutputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)71 static void VencOutputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
72 void *userData)
73 {
74 VEncSignal *signal = static_cast<VEncSignal *>(userData);
75 unique_lock<mutex> lock(signal->outMutex_);
76 signal->outIdxQueue_.push(index);
77 signal->attrQueue_.push(*attr);
78 signal->outBufferQueue_.push(data);
79 signal->outCond_.notify_all();
80 }
GetSystemTimeUs()81 int64_t VEncFuzzSample::GetSystemTimeUs()
82 {
83 struct timespec now;
84 (void)clock_gettime(CLOCK_BOOTTIME, &now);
85 int64_t nanoTime = static_cast<int64_t>(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec;
86 return nanoTime / NANOS_IN_MICRO;
87 }
88
ConfigureVideoEncoder()89 int32_t VEncFuzzSample::ConfigureVideoEncoder()
90 {
91 OH_AVFormat *format = OH_AVFormat_Create();
92 if (format == nullptr) {
93 cout << "Fatal: Failed to create format" << endl;
94 return AV_ERR_UNKNOWN;
95 }
96 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, defaultWidth);
97 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, defaultHeight);
98 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, defaultPixFmt);
99 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, defaultFrameRate);
100 (void)OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, defaultBitrate);
101 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, defaultKeyFrameInterval);
102 if (defaultBitrateMode == CQ) {
103 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_QUALITY, defaultQuality);
104 }
105 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, defaultBitrateMode);
106 int ret = OH_VideoEncoder_Configure(venc_, format);
107 OH_AVFormat_Destroy(format);
108 return ret;
109 }
110
ConfigureVideoEncoderFuzz(int32_t data)111 int32_t VEncFuzzSample::ConfigureVideoEncoderFuzz(int32_t data)
112 {
113 OH_VideoEncoder_Reset(venc_);
114 OH_AVFormat *format = OH_AVFormat_Create();
115 if (format == nullptr) {
116 cout << "Fatal: Failed to create format" << endl;
117 return AV_ERR_UNKNOWN;
118 }
119 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, data);
120 defaultWidth = data;
121 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, data);
122 defaultHeight = data;
123 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, data % MAX_PIXEL_FMT);
124 double frameRate = data;
125 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, frameRate);
126
127 OH_AVFormat_SetIntValue(format, OH_MD_KEY_RANGE_FLAG, data);
128 OH_AVFormat_SetIntValue(format, OH_MD_KEY_COLOR_PRIMARIES, data);
129 OH_AVFormat_SetIntValue(format, OH_MD_KEY_TRANSFER_CHARACTERISTICS, data);
130 OH_AVFormat_SetIntValue(format, OH_MD_KEY_MATRIX_COEFFICIENTS, data);
131 OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, data);
132 OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, data);
133 OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, data);
134 OH_AVFormat_SetIntValue(format, OH_MD_KEY_QUALITY, data);
135
136 int ret = OH_VideoEncoder_Configure(venc_, format);
137 OH_AVFormat_Destroy(format);
138 return ret;
139 }
140
SetVideoEncoderCallback()141 int32_t VEncFuzzSample::SetVideoEncoderCallback()
142 {
143 signal_ = new VEncSignal();
144 if (signal_ == nullptr) {
145 cout << "Failed to new VEncSignal" << endl;
146 return AV_ERR_UNKNOWN;
147 }
148
149 cb_.onError = VencError;
150 cb_.onStreamChanged = VencFormatChanged;
151 cb_.onNeedInputData = VencInputDataReady;
152 cb_.onNeedOutputData = VencOutputDataReady;
153 return OH_VideoEncoder_SetCallback(venc_, cb_, static_cast<void *>(signal_));
154 }
155
ReleaseInFile()156 void VEncFuzzSample::ReleaseInFile()
157 {
158 if (inFile_ != nullptr) {
159 if (inFile_->is_open()) {
160 inFile_->close();
161 }
162 inFile_.reset();
163 inFile_ = nullptr;
164 }
165 }
166
StopInloop()167 void VEncFuzzSample::StopInloop()
168 {
169 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
170 unique_lock<mutex> lock(signal_->inMutex_);
171 clearIntqueue(signal_->inIdxQueue_);
172 isRunning_.store(false);
173 signal_->inCond_.notify_all();
174 lock.unlock();
175
176 inputLoop_->join();
177 inputLoop_ = nullptr;
178 }
179 }
180
GetStride()181 void VEncFuzzSample::GetStride()
182 {
183 OH_AVFormat *format = OH_VideoEncoder_GetInputDescription(venc_);
184 int32_t inputStride = 0;
185 OH_AVFormat_GetIntValue(format, "stride", &inputStride);
186 stride_ = inputStride;
187 OH_AVFormat_Destroy(format);
188 }
189
OpenFile()190 int32_t VEncFuzzSample::OpenFile()
191 {
192 if (fuzzMode) {
193 return AV_ERR_OK;
194 }
195 int32_t ret = AV_ERR_OK;
196 inFile_ = make_unique<ifstream>();
197 if (inFile_ == nullptr) {
198 isRunning_.store(false);
199 (void)OH_VideoEncoder_Stop(venc_);
200 return AV_ERR_UNKNOWN;
201 }
202 inFile_->open(inpDir, ios::in | ios::binary);
203 if (!inFile_->is_open()) {
204 cout << "file open fail" << endl;
205 isRunning_.store(false);
206 (void)OH_VideoEncoder_Stop(venc_);
207 inFile_->close();
208 inFile_.reset();
209 inFile_ = nullptr;
210 return AV_ERR_UNKNOWN;
211 }
212 return ret;
213 }
214
StartVideoEncoder()215 int32_t VEncFuzzSample::StartVideoEncoder()
216 {
217 isRunning_.store(true);
218 int32_t ret = 0;
219 OH_VideoEncoder_Stop(venc_);
220 Flush();
221 ret = OH_VideoEncoder_Start(venc_);
222 GetStride();
223 if (ret != AV_ERR_OK) {
224 cout << "Failed to start codec" << endl;
225 isRunning_.store(false);
226 signal_->inCond_.notify_all();
227 signal_->outCond_.notify_all();
228 return ret;
229 }
230 if (OpenFile() != AV_ERR_OK) {
231 return AV_ERR_UNKNOWN;
232 }
233
234 inputLoop_ = make_unique<thread>(&VEncFuzzSample::InputFunc, this);
235
236 if (inputLoop_ == nullptr) {
237 isRunning_.store(false);
238 (void)OH_VideoEncoder_Stop(venc_);
239 ReleaseInFile();
240 return AV_ERR_UNKNOWN;
241 }
242 outputLoop_ = make_unique<thread>(&VEncFuzzSample::OutputFunc, this);
243 if (outputLoop_ == nullptr) {
244 isRunning_.store(false);
245 (void)OH_VideoEncoder_Stop(venc_);
246 ReleaseInFile();
247 StopInloop();
248 Release();
249 return AV_ERR_UNKNOWN;
250 }
251 return AV_ERR_OK;
252 }
253
CreateVideoEncoder(const char * codecName)254 int32_t VEncFuzzSample::CreateVideoEncoder(const char *codecName)
255 {
256 venc_ = OH_VideoEncoder_CreateByMime("aabbcc");
257 if (venc_) {
258 OH_VideoEncoder_Destroy(venc_);
259 venc_ = nullptr;
260 }
261 venc_ = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
262 if (venc_) {
263 OH_VideoEncoder_Destroy(venc_);
264 venc_ = nullptr;
265 }
266 venc_ = OH_VideoEncoder_CreateByName("aabbcc");
267 if (venc_) {
268 OH_VideoEncoder_Destroy(venc_);
269 venc_ = nullptr;
270 }
271 venc_ = OH_VideoEncoder_CreateByName(codecName);
272 g_encSample = this;
273 return venc_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
274 }
275
WaitForEOS()276 void VEncFuzzSample::WaitForEOS()
277 {
278 if (inputLoop_)
279 inputLoop_->join();
280 if (outputLoop_)
281 outputLoop_->join();
282 inputLoop_ = nullptr;
283 outputLoop_ = nullptr;
284 }
285
ReturnZeroIfEOS(uint32_t expectedSize)286 uint32_t VEncFuzzSample::ReturnZeroIfEOS(uint32_t expectedSize)
287 {
288 if (inFile_->gcount() != (expectedSize)) {
289 cout << "no more data" << endl;
290 return 0;
291 }
292 return 1;
293 }
294
ReadOneFrameYUV420SP(uint8_t * dst)295 uint32_t VEncFuzzSample::ReadOneFrameYUV420SP(uint8_t *dst)
296 {
297 uint8_t *start = dst;
298 // copy Y
299 for (uint32_t i = 0; i < defaultHeight; i++) {
300 inFile_->read(reinterpret_cast<char *>(dst), defaultWidth);
301 if (!ReturnZeroIfEOS(defaultWidth)) {
302 return 0;
303 }
304 dst += stride_;
305 }
306 // copy UV
307 for (uint32_t i = 0; i < defaultHeight / sampleRatio; i++) {
308 inFile_->read(reinterpret_cast<char *>(dst), defaultWidth);
309 if (!ReturnZeroIfEOS(defaultWidth)) {
310 return 0;
311 }
312 dst += stride_;
313 }
314 return dst - start;
315 }
316
ReadOneFrameRGBA8888(uint8_t * dst)317 void VEncFuzzSample::ReadOneFrameRGBA8888(uint8_t *dst)
318 {
319 for (uint32_t i = 0; i < defaultHeight; i++) {
320 inFile_->read(reinterpret_cast<char *>(dst), defaultWidth * RGBA_SIZE);
321 dst += stride_;
322 }
323 }
324
SetEOS(uint32_t index)325 void VEncFuzzSample::SetEOS(uint32_t index)
326 {
327 OH_AVCodecBufferAttr attr;
328 attr.pts = 0;
329 attr.size = 0;
330 attr.offset = 0;
331 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
332 int32_t res = OH_VideoEncoder_PushInputData(venc_, index, attr);
333 cout << "OH_VideoEncoder_PushInputData EOS res: " << res << endl;
334 unique_lock<mutex> lock(signal_->inMutex_);
335 signal_->inIdxQueue_.pop();
336 signal_->inBufferQueue_.pop();
337 }
338
SetForceIDR()339 void VEncFuzzSample::SetForceIDR()
340 {
341 OH_AVFormat *format = OH_AVFormat_Create();
342 OH_AVFormat_SetIntValue(format, OH_MD_KEY_REQUEST_I_FRAME, 1);
343 OH_VideoEncoder_SetParameter(venc_, format);
344 OH_AVFormat_Destroy(format);
345 }
346
PushData(OH_AVMemory * buffer,uint32_t index,int32_t & result)347 int32_t VEncFuzzSample::PushData(OH_AVMemory *buffer, uint32_t index, int32_t &result)
348 {
349 int32_t res = -2;
350 OH_AVCodecBufferAttr attr;
351 uint8_t *fileBuffer = OH_AVMemory_GetAddr(buffer);
352 if (fileBuffer == nullptr) {
353 cout << "Fatal: no memory" << endl;
354 return -1;
355 }
356 int32_t size = OH_AVMemory_GetSize(buffer);
357 if (defaultPixFmt == AV_PIXEL_FORMAT_RGBA) {
358 if (size < defaultHeight * stride_) {
359 return -1;
360 }
361 ReadOneFrameRGBA8888(fileBuffer);
362 attr.size = stride_ * defaultHeight;
363 } else {
364 if (size < (defaultHeight * stride_ + (defaultHeight * stride_ / DOUBLE))) {
365 return -1;
366 }
367 attr.size = ReadOneFrameYUV420SP(fileBuffer);
368 }
369 if (inFile_->eof()) {
370 SetEOS(index);
371 return 0;
372 }
373 attr.pts = GetSystemTimeUs();
374 attr.offset = 0;
375 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
376 if (enableForceIDR && (frameCount % IDR_FRAME_INTERVAL == 0)) {
377 SetForceIDR();
378 }
379 result = OH_VideoEncoder_PushInputData(venc_, index, attr);
380 unique_lock<mutex> lock(signal_->inMutex_);
381 signal_->inIdxQueue_.pop();
382 signal_->inBufferQueue_.pop();
383 return res;
384 }
385
CheckResult(bool isRandomEosSuccess,int32_t pushResult)386 int32_t VEncFuzzSample::CheckResult(bool isRandomEosSuccess, int32_t pushResult)
387 {
388 if (isRandomEosSuccess) {
389 if (pushResult == 0) {
390 errCount = errCount + 1;
391 cout << "push input after eos should be failed! pushResult:" << pushResult << endl;
392 }
393 return -1;
394 } else if (pushResult != 0) {
395 errCount = errCount + 1;
396 cout << "push input data failed, error:" << pushResult << endl;
397 return -1;
398 }
399 return 0;
400 }
401
InputDataFuzz(bool & runningFlag,uint32_t index)402 void VEncFuzzSample::InputDataFuzz(bool &runningFlag, uint32_t index)
403 {
404 frameCount++;
405 if (frameCount == defaultFuzzTime) {
406 SetEOS(index);
407 runningFlag = false;
408 return;
409 }
410 OH_AVCodecBufferAttr attr;
411 attr.pts = GetSystemTimeUs();
412 attr.offset = 0;
413 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
414 OH_VideoEncoder_PushInputData(venc_, index, attr);
415 unique_lock<mutex> lock(signal_->inMutex_);
416 signal_->inIdxQueue_.pop();
417 signal_->inBufferQueue_.pop();
418 }
419
InputFunc()420 void VEncFuzzSample::InputFunc()
421 {
422 errCount = 0;
423 bool runningFlag = true;
424 while (runningFlag) {
425 if (!isRunning_.load()) {
426 break;
427 }
428 unique_lock<mutex> lock(signal_->inMutex_);
429 signal_->inCond_.wait(lock, [this]() {
430 if (!isRunning_.load()) {
431 return true;
432 }
433 return signal_->inIdxQueue_.size() > 0;
434 });
435 if (!isRunning_.load()) {
436 break;
437 }
438 uint32_t index = signal_->inIdxQueue_.front();
439 lock.unlock();
440 InputDataFuzz(runningFlag, index);
441 if (sleepOnFPS) {
442 usleep(FRAME_INTERVAL);
443 }
444 }
445 }
446
CheckAttrFlag(OH_AVCodecBufferAttr attr)447 int32_t VEncFuzzSample::CheckAttrFlag(OH_AVCodecBufferAttr attr)
448 {
449 if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) {
450 cout << "attr.flags == AVCODEC_BUFFER_FLAGS_EOS" << endl;
451 unique_lock<mutex> inLock(signal_->inMutex_);
452 isRunning_.store(false);
453 signal_->inCond_.notify_all();
454 signal_->outCond_.notify_all();
455 inLock.unlock();
456 return -1;
457 }
458 if (attr.flags == AVCODEC_BUFFER_FLAGS_CODEC_DATA) {
459 cout << "enc AVCODEC_BUFFER_FLAGS_CODEC_DATA" << attr.pts << endl;
460 }
461 outCount = outCount + 1;
462 return 0;
463 }
464
OutputFuncFail()465 void VEncFuzzSample::OutputFuncFail()
466 {
467 cout << "errCount > 0" << endl;
468 unique_lock<mutex> inLock(signal_->inMutex_);
469 isRunning_.store(false);
470 signal_->inCond_.notify_all();
471 signal_->outCond_.notify_all();
472 inLock.unlock();
473 (void)Stop();
474 Release();
475 }
476
OutputFunc()477 void VEncFuzzSample::OutputFunc()
478 {
479 FILE *outFile = fopen(outDir, "wb");
480
481 while (true) {
482 if (!isRunning_.load()) {
483 break;
484 }
485 OH_AVCodecBufferAttr attr;
486 uint32_t index;
487 unique_lock<mutex> lock(signal_->outMutex_);
488 signal_->outCond_.wait(lock, [this]() {
489 if (!isRunning_.load()) {
490 return true;
491 }
492 return signal_->outIdxQueue_.size() > 0;
493 });
494 if (!isRunning_.load()) {
495 break;
496 }
497 index = signal_->outIdxQueue_.front();
498 attr = signal_->attrQueue_.front();
499 OH_AVMemory *buffer = signal_->outBufferQueue_.front();
500 signal_->outBufferQueue_.pop();
501 signal_->outIdxQueue_.pop();
502 signal_->attrQueue_.pop();
503 lock.unlock();
504 if (CheckAttrFlag(attr) == -1) {
505 break;
506 }
507 int size = attr.size;
508
509 if (outFile == nullptr) {
510 cout << "dump data fail" << endl;
511 } else {
512 fwrite(OH_AVMemory_GetAddr(buffer), 1, size, outFile);
513 }
514
515 if (OH_VideoEncoder_FreeOutputData(venc_, index) != AV_ERR_OK) {
516 cout << "Fatal: ReleaseOutputBuffer fail" << endl;
517 errCount = errCount + 1;
518 }
519 if (errCount > 0) {
520 OutputFuncFail();
521 break;
522 }
523 }
524 if (outFile) {
525 (void)fclose(outFile);
526 }
527 }
528
Flush()529 int32_t VEncFuzzSample::Flush()
530 {
531 unique_lock<mutex> inLock(signal_->inMutex_);
532 clearIntqueue(signal_->inIdxQueue_);
533 signal_->inCond_.notify_all();
534 inLock.unlock();
535 unique_lock<mutex> outLock(signal_->outMutex_);
536 clearIntqueue(signal_->outIdxQueue_);
537 clearBufferqueue(signal_->attrQueue_);
538 signal_->outCond_.notify_all();
539 outLock.unlock();
540 return OH_VideoEncoder_Flush(venc_);
541 }
542
Reset()543 int32_t VEncFuzzSample::Reset()
544 {
545 isRunning_.store(false);
546 StopInloop();
547 StopOutloop();
548 ReleaseInFile();
549 return OH_VideoEncoder_Reset(venc_);
550 }
551
Release()552 int32_t VEncFuzzSample::Release()
553 {
554 int ret = OH_VideoEncoder_Destroy(venc_);
555 venc_ = nullptr;
556 if (signal_ != nullptr) {
557 delete signal_;
558 signal_ = nullptr;
559 }
560 return ret;
561 }
562
Stop()563 int32_t VEncFuzzSample::Stop()
564 {
565 StopInloop();
566 clearIntqueue(signal_->outIdxQueue_);
567 clearBufferqueue(signal_->attrQueue_);
568 ReleaseInFile();
569 return OH_VideoEncoder_Stop(venc_);
570 }
571
Start()572 int32_t VEncFuzzSample::Start()
573 {
574 return OH_VideoEncoder_Start(venc_);
575 }
576
StopOutloop()577 void VEncFuzzSample::StopOutloop()
578 {
579 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
580 unique_lock<mutex> lock(signal_->outMutex_);
581 clearIntqueue(signal_->outIdxQueue_);
582 clearBufferqueue(signal_->attrQueue_);
583 signal_->outCond_.notify_all();
584 lock.unlock();
585 }
586 }
587
SetParameter(OH_AVFormat * format)588 int32_t VEncFuzzSample::SetParameter(OH_AVFormat *format)
589 {
590 if (venc_) {
591 return OH_VideoEncoder_SetParameter(venc_, format);
592 }
593 return AV_ERR_UNKNOWN;
594 }