• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }