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 }