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