• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 "native_buffer_inner.h"
20 #include "videoenc_sample.h"
21 #include "native_avcapability.h"
22 using namespace OHOS;
23 using namespace OHOS::Media;
24 using namespace std;
25 namespace {
26 constexpr int64_t NANOS_IN_SECOND = 1000000000L;
27 constexpr int64_t NANOS_IN_MICRO = 1000L;
28 constexpr uint32_t FRAME_INTERVAL = 16666;
29 constexpr uint8_t RGBA_SIZE = 4;
30 constexpr uint32_t IDR_FRAME_INTERVAL = 10;
31 constexpr uint32_t DOUBLE = 2;
32 constexpr uint32_t THREE = 3;
33 sptr<Surface> cs = nullptr;
34 sptr<Surface> ps = nullptr;
35 VEncNdkFuzzSample *g_encSample = nullptr;
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 
clearBufferqueue(std::queue<OH_AVCodecBufferAttr> & q)43 void clearBufferqueue(std::queue<OH_AVCodecBufferAttr> &q)
44 {
45     std::queue<OH_AVCodecBufferAttr> empty;
46     swap(empty, q);
47 }
48 } // namespace
49 
~VEncNdkFuzzSample()50 VEncNdkFuzzSample::~VEncNdkFuzzSample()
51 {
52     if (surfInput && nativeWindow) {
53         OH_NativeWindow_DestroyNativeWindow(nativeWindow);
54         nativeWindow = nullptr;
55     }
56     Release();
57 }
58 
VencError(OH_AVCodec * codec,int32_t errorCode,void * userData)59 static void VencError(OH_AVCodec *codec, int32_t errorCode, void *userData)
60 {
61     cout << "Error errorCode=" << errorCode << endl;
62     g_encSample->isRunning_.store(false);
63     g_encSample->signal_->inCond_.notify_all();
64 }
65 
VencFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)66 static void VencFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
67 {
68     cout << "Format Changed" << endl;
69 }
70 
VencInputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)71 static void VencInputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
72 {
73     if (g_encSample->isFlushing_) {
74         return;
75     }
76     if (g_encSample->inputCallbackFlush) {
77         g_encSample->Flush();
78         cout << "OH_VideoEncoder_Flush end" << endl;
79         g_encSample->isRunning_.store(false);
80         g_encSample->signal_->inCond_.notify_all();
81         g_encSample->signal_->outCond_.notify_all();
82         return;
83     }
84     if (g_encSample->inputCallbackStop) {
85         OH_VideoEncoder_Stop(codec);
86         cout << "OH_VideoEncoder_Stop end" << endl;
87         g_encSample->isRunning_.store(false);
88         g_encSample->signal_->inCond_.notify_all();
89         g_encSample->signal_->outCond_.notify_all();
90         return;
91     }
92     VEncSignal *signal = static_cast<VEncSignal *>(userData);
93     unique_lock<mutex> lock(signal->inMutex_);
94     signal->inIdxQueue_.push(index);
95     signal->inBufferQueue_.push(data);
96     signal->inCond_.notify_all();
97 }
98 
VencOutputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)99 static void VencOutputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
100                                 void *userData)
101 {
102     if (g_encSample->isFlushing_) {
103         return;
104     }
105     if (g_encSample->outputCallbackFlush) {
106         g_encSample->Flush();
107         cout << "OH_VideoEncoder_Flush end" << endl;
108         g_encSample->isRunning_.store(false);
109         g_encSample->signal_->inCond_.notify_all();
110         g_encSample->signal_->outCond_.notify_all();
111         return;
112     }
113     if (g_encSample->outputCallbackStop) {
114         OH_VideoEncoder_Stop(codec);
115         cout << "OH_VideoEncoder_Stop end" << endl;
116         g_encSample->isRunning_.store(false);
117         g_encSample->signal_->inCond_.notify_all();
118         g_encSample->signal_->outCond_.notify_all();
119         return;
120     }
121     OH_VideoEncoder_FreeOutputData(codec, index);
122 }
GetSystemTimeUs()123 int64_t VEncNdkFuzzSample::GetSystemTimeUs()
124 {
125     struct timespec now;
126     (void)clock_gettime(CLOCK_BOOTTIME, &now);
127     int64_t nanoTime = static_cast<int64_t>(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec;
128 
129     return nanoTime / NANOS_IN_MICRO;
130 }
131 
ConfigureVideoEncoder()132 int32_t VEncNdkFuzzSample::ConfigureVideoEncoder()
133 {
134     OH_AVFormat *format = OH_AVFormat_Create();
135     if (format == nullptr) {
136         cout << "Fatal: Failed to create format" << endl;
137         return AV_ERR_UNKNOWN;
138     }
139     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, HEVC_PROFILE_MAIN);
140     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, defaultWidth);
141     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, defaultHeight);
142     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, DEFAULT_PIX_FMT);
143     (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, defaultFrameRate);
144     (void)OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, defaultBitrate);
145     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, defaultKeyFrameInterval);
146     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_RANGE_FLAG, 1);
147     if (defaultBitrateMode == CQ) {
148         (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_QUALITY, defaultQuality);
149     }
150     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, defaultBitrateMode);
151     int ret = OH_VideoEncoder_Configure(venc_, format);
152     OH_AVFormat_Destroy(format);
153     return ret;
154 }
155 
SetVideoEncoderCallback()156 int32_t VEncNdkFuzzSample::SetVideoEncoderCallback()
157 {
158     signal_ = new VEncSignal();
159     if (signal_ == nullptr) {
160         cout << "Failed to new VEncSignal" << endl;
161         return AV_ERR_UNKNOWN;
162     }
163 
164     cb_.onError = VencError;
165     cb_.onStreamChanged = VencFormatChanged;
166     cb_.onNeedInputData = VencInputDataReady;
167     cb_.onNeedOutputData = VencOutputDataReady;
168     return OH_VideoEncoder_SetCallback(venc_, cb_, static_cast<void *>(signal_));
169 }
170 
ReleaseInFile()171 void VEncNdkFuzzSample::ReleaseInFile()
172 {
173     if (inFile_ != nullptr) {
174         if (inFile_->is_open()) {
175             inFile_->close();
176         }
177         inFile_.reset();
178         inFile_ = nullptr;
179     }
180 }
181 
CreateSurface()182 int32_t VEncNdkFuzzSample::CreateSurface()
183 {
184     int32_t ret = 0;
185     ret = OH_VideoEncoder_GetSurface(venc_, &nativeWindow);
186     if (ret != AV_ERR_OK) {
187         cout << "OH_VideoEncoder_GetSurface fail" << endl;
188         return ret;
189     }
190     ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_FORMAT, GRAPHIC_PIXEL_FMT_YCBCR_420_SP);
191     if (ret != AV_ERR_OK) {
192         cout << "NativeWindowHandleOpt SET_FORMAT fail" << endl;
193         return ret;
194     }
195     ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_BUFFER_GEOMETRY, defaultWidth, defaultHeight);
196     if (ret != AV_ERR_OK) {
197         cout << "NativeWindowHandleOpt SET_BUFFER_GEOMETRY fail" << endl;
198         return ret;
199     }
200     return AV_ERR_OK;
201 }
202 
GetStride()203 void VEncNdkFuzzSample::GetStride()
204 {
205     OH_AVFormat *format = OH_VideoEncoder_GetInputDescription(venc_);
206     int32_t inputStride = 0;
207     OH_AVFormat_GetIntValue(format, "stride", &inputStride);
208     stride_ = inputStride;
209     OH_AVFormat_Destroy(format);
210 }
211 
OpenFile()212 int32_t VEncNdkFuzzSample::OpenFile()
213 {
214     if (fuzzMode) {
215         return AV_ERR_OK;
216     }
217     int32_t ret = AV_ERR_OK;
218     inFile_ = make_unique<ifstream>();
219     if (inFile_ == nullptr) {
220         isRunning_.store(false);
221         (void)OH_VideoEncoder_Stop(venc_);
222         return AV_ERR_UNKNOWN;
223     }
224     inFile_->open(inpDir, ios::in | ios::binary);
225     if (!inFile_->is_open()) {
226         cout << "file open fail" << endl;
227         isRunning_.store(false);
228         (void)OH_VideoEncoder_Stop(venc_);
229         inFile_->close();
230         inFile_.reset();
231         inFile_ = nullptr;
232         return AV_ERR_UNKNOWN;
233     }
234     return ret;
235 }
236 
StartVideoEncoder()237 int32_t VEncNdkFuzzSample::StartVideoEncoder()
238 {
239     isRunning_.store(true);
240     int32_t ret = 0;
241     if (surfInput) {
242         ret = CreateSurface();
243         if (ret != AV_ERR_OK) {
244             return ret;
245         }
246     }
247     if (venc_ == nullptr) {
248         cout << "codec is nullptr" << endl;
249     }
250     ret = OH_VideoEncoder_Start(venc_);
251     GetStride();
252     if (ret != AV_ERR_OK) {
253         cout << "Failed to start codec" << endl;
254         isRunning_.store(false);
255         signal_->inCond_.notify_all();
256         signal_->outCond_.notify_all();
257         return ret;
258     }
259     if (OpenFile() != AV_ERR_OK) {
260         return AV_ERR_UNKNOWN;
261     }
262     if (surfInput) {
263         inputLoop_ = make_unique<thread>(&VEncNdkFuzzSample::InputFuncSurface, this);
264     } else {
265         inputLoop_ = make_unique<thread>(&VEncNdkFuzzSample::InputFunc, this);
266     }
267     if (inputLoop_ == nullptr) {
268         isRunning_.store(false);
269         (void)OH_VideoEncoder_Stop(venc_);
270         ReleaseInFile();
271         return AV_ERR_UNKNOWN;
272     }
273     return AV_ERR_OK;
274 }
275 
CreateVideoEncoder()276 int32_t VEncNdkFuzzSample::CreateVideoEncoder()
277 {
278     OH_AVCapability *cap = OH_AVCodec_GetCapabilityByCategory(OH_AVCODEC_MIMETYPE_VIDEO_HEVC, true, HARDWARE);
279     const char *tmpCodecName = OH_AVCapability_GetName(cap);
280     char gCodecName[128] = {};
281     if (memcpy_s(gCodecName, sizeof(gCodecName), tmpCodecName, strlen(tmpCodecName)) != 0) {
282         cout << "memcpy failed" << endl;
283     }
284 
285     venc_ = OH_VideoEncoder_CreateByName(gCodecName);
286     if (!venc_) {
287         cout << "create codec failed" << endl;
288     }
289     g_encSample = this;
290     return venc_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
291 }
292 
WaitForEOS()293 void VEncNdkFuzzSample::WaitForEOS()
294 {
295     if (inputLoop_)
296         inputLoop_->join();
297     if (outputLoop_)
298         outputLoop_->join();
299     inputLoop_ = nullptr;
300     outputLoop_ = nullptr;
301 }
302 
ReturnZeroIfEOS(uint32_t expectedSize)303 uint32_t VEncNdkFuzzSample::ReturnZeroIfEOS(uint32_t expectedSize)
304 {
305     if (inFile_->gcount() != (expectedSize)) {
306         cout << "no more data" << endl;
307         return 0;
308     }
309     return 1;
310 }
311 
ReadOneFrameYUV420SP(uint8_t * dst)312 uint32_t VEncNdkFuzzSample::ReadOneFrameYUV420SP(uint8_t *dst)
313 {
314     uint8_t *start = dst;
315     // copy Y
316     for (uint32_t i = 0; i < defaultHeight; i++) {
317         inFile_->read(reinterpret_cast<char *>(dst), defaultWidth);
318         if (!ReturnZeroIfEOS(defaultWidth)) {
319             return 0;
320         }
321         dst += stride_;
322     }
323     // copy UV
324     for (uint32_t i = 0; i < defaultHeight / sampleRatio; i++) {
325         inFile_->read(reinterpret_cast<char *>(dst), defaultWidth);
326         if (!ReturnZeroIfEOS(defaultWidth)) {
327             return 0;
328         }
329         dst += stride_;
330     }
331     return dst - start;
332 }
333 
ReadOneFrameRGBA8888(uint8_t * dst)334 void VEncNdkFuzzSample::ReadOneFrameRGBA8888(uint8_t *dst)
335 {
336     for (uint32_t i = 0; i < defaultHeight; i++) {
337         inFile_->read(reinterpret_cast<char *>(dst), defaultWidth * RGBA_SIZE);
338         dst += stride_;
339     }
340 }
341 
FlushSurf(OHNativeWindowBuffer * ohNativeWindowBuffer,OH_NativeBuffer * nativeBuffer)342 uint32_t VEncNdkFuzzSample::FlushSurf(OHNativeWindowBuffer *ohNativeWindowBuffer, OH_NativeBuffer *nativeBuffer)
343 {
344     struct Region region;
345     struct Region::Rect *rect = new Region::Rect();
346     rect->x = 0;
347     rect->y = 0;
348     rect->w = defaultWidth;
349     rect->h = defaultHeight;
350     region.rects = rect;
351     NativeWindowHandleOpt(nativeWindow, SET_UI_TIMESTAMP, GetSystemTimeUs());
352     int32_t err = OH_NativeBuffer_Unmap(nativeBuffer);
353     if (err != 0) {
354         cout << "OH_NativeBuffer_Unmap failed" << endl;
355         return 1;
356     }
357     err = OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, ohNativeWindowBuffer, -1, region);
358     delete rect;
359     if (err != 0) {
360         cout << "FlushBuffer failed" << endl;
361         return 1;
362     }
363     return 0;
364 }
365 
ProcessNativeWindowBuffer(OHNativeWindowBuffer * ohNativeWindowBuffer,OH_NativeBuffer * nativeBuffer)366 bool VEncNdkFuzzSample::ProcessNativeWindowBuffer(OHNativeWindowBuffer *ohNativeWindowBuffer,
367     OH_NativeBuffer *nativeBuffer)
368 {
369     if (nativeWindow == nullptr) {
370         cout << "nativeWindow == nullptr" << endl;
371         return false;
372     }
373 
374     int fenceFd = -1;
375     int32_t err = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &ohNativeWindowBuffer, &fenceFd);
376     if (err != 0) {
377         cout << "RequestBuffer failed, GSError=" << err << endl;
378         return false;
379     }
380     if (fenceFd > 0) {
381         close(fenceFd);
382     }
383 
384     nativeBuffer = OH_NativeBufferFromNativeWindowBuffer(ohNativeWindowBuffer);
385     void *virAddr = nullptr;
386     OH_NativeBuffer_Config config;
387     OH_NativeBuffer_GetConfig(nativeBuffer, &config);
388     err = OH_NativeBuffer_Map(nativeBuffer, &virAddr);
389     if (err != 0) {
390         cout << "OH_NativeBuffer_Map failed, GSError=" << err << endl;
391         isRunning_.store(false);
392         return false;
393     }
394 
395     uint8_t *dst = (uint8_t *)virAddr;
396     if (fuzzMode) {
397         if (dst == nullptr) {
398             return false;
399         }
400         if (memcpy_s(dst, (config.stride * config.height * THREE) / DOUBLE, fuzzData, fuzzSize) != EOK) {
401             cout << "Fatal: memcpy fail" << endl;
402             return false;
403         }
404     } else {
405         const SurfaceBuffer *sbuffer = SurfaceBuffer::NativeBufferToSurfaceBuffer(nativeBuffer);
406         int stride = sbuffer->GetStride();
407         if (dst == nullptr || stride < defaultWidth) {
408             cout << "invalid va or stride=" << stride << endl;
409             err = NativeWindowCancelBuffer(nativeWindow, ohNativeWindowBuffer);
410             isRunning_.store(false);
411             return false;
412         }
413         stride_ = stride;
414         if (!ReadOneFrameYUV420SP(dst)) {
415             return false;
416         }
417     }
418 
419     return true;
420 }
421 
InputFuncSurface()422 void VEncNdkFuzzSample::InputFuncSurface()
423 {
424     bool enableInput = true;
425     while (enableInput) {
426         OH_NativeBuffer *nativeBuffer = nullptr;
427         if (outputCallbackFlush || outputCallbackStop) {
428             OH_VideoEncoder_NotifyEndOfStream(venc_);
429             enableInput = false;
430             break;
431         }
432 
433         OHNativeWindowBuffer *ohNativeWindowBuffer = nullptr;
434         if (!ProcessNativeWindowBuffer(ohNativeWindowBuffer, nativeBuffer)) {
435             break;
436         }
437 
438         if (fuzzMode && frameCount == defaultFuzzTime) {
439             int32_t err = OH_VideoEncoder_NotifyEndOfStream(venc_);
440             if (err != 0) {
441                 cout << "OH_VideoEncoder_NotifyEndOfStream failed" << endl;
442             }
443             break;
444         }
445         if (FlushSurf(ohNativeWindowBuffer, nativeBuffer)) {
446             break;
447         }
448 
449         usleep(FRAME_INTERVAL);
450         frameCount++;
451     }
452 }
453 
FlushBuffer()454 void VEncNdkFuzzSample::FlushBuffer()
455 {
456     unique_lock<mutex> inLock(signal_->inMutex_);
457     clearIntqueue(signal_->inIdxQueue_);
458     std::queue<OH_AVMemory *> empty;
459     swap(empty, signal_->inBufferQueue_);
460     signal_->inCond_.notify_all();
461     inLock.unlock();
462     unique_lock<mutex> outLock(signal_->outMutex_);
463     clearIntqueue(signal_->outIdxQueue_);
464     clearBufferqueue(signal_->attrQueue_);
465     signal_->outCond_.notify_all();
466     outLock.unlock();
467 }
468 
RepeatStartBeforeEOS()469 void VEncNdkFuzzSample::RepeatStartBeforeEOS()
470 {
471     if (repeatStartFlushBeforeEos > 0) {
472         repeatStartFlushBeforeEos--;
473         OH_VideoEncoder_Flush(venc_);
474         FlushBuffer();
475         OH_VideoEncoder_Start(venc_);
476     }
477 
478     if (repeatStartStopBeforeEos > 0) {
479         repeatStartStopBeforeEos--;
480         OH_VideoEncoder_Stop(venc_);
481         FlushBuffer();
482         OH_VideoEncoder_Start(venc_);
483     }
484 }
485 
RandomEOS(uint32_t index)486 bool VEncNdkFuzzSample::RandomEOS(uint32_t index)
487 {
488     if (enableRandomEos && randomEos == frameCount) {
489         OH_AVCodecBufferAttr attr;
490         attr.pts = 0;
491         attr.size = 0;
492         attr.offset = 0;
493         attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
494         OH_VideoEncoder_PushInputData(venc_, index, attr);
495         cout << "random eos" << endl;
496         frameCount++;
497         unique_lock<mutex> lock(signal_->inMutex_);
498         signal_->inIdxQueue_.pop();
499         signal_->inBufferQueue_.pop();
500         return true;
501     }
502     return false;
503 }
504 
AutoSwitchParam()505 void VEncNdkFuzzSample::AutoSwitchParam()
506 {
507     int64_t currentBitrate = defaultBitrate;
508     double currentFrameRate = defaultFrameRate;
509     if (frameCount == switchParamsTimeSec * static_cast<int32_t>(defaultFrameRate)) {
510         OH_AVFormat *format = OH_AVFormat_Create();
511         if (needResetBitrate) {
512             currentBitrate = defaultBitrate >> 1;
513             cout<<"switch bitrate "<< currentBitrate;
514             (void)OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, currentBitrate);
515             SetParameter(format) == AV_ERR_OK ? (0) : (errCount++);
516         }
517         if (needResetFrameRate) {
518             currentFrameRate = defaultFrameRate * DOUBLE;
519             cout<< "switch framerate" << currentFrameRate << endl;
520             (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, currentFrameRate);
521             SetParameter(format) == AV_ERR_OK ? (0) : (errCount++);
522         }
523         OH_AVFormat_Destroy(format);
524     }
525     if (frameCount == switchParamsTimeSec * static_cast<int32_t>(defaultFrameRate) * DOUBLE) {
526         OH_AVFormat *format = OH_AVFormat_Create();
527         if (needResetBitrate) {
528             currentBitrate = defaultBitrate << 1;
529             cout<<"switch bitrate "<< currentBitrate;
530             (void)OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, currentBitrate);
531         }
532         if (needResetFrameRate) {
533             currentFrameRate = defaultFrameRate / DOUBLE;
534             cout<< "switch framerate" << currentFrameRate << endl;
535             (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, currentFrameRate);
536             SetParameter(format) == AV_ERR_OK ? (0) : (errCount++);
537         }
538         SetParameter(format) == AV_ERR_OK ? (0) : (errCount++);
539         OH_AVFormat_Destroy(format);
540     }
541 }
542 
SetEOS(uint32_t index)543 void VEncNdkFuzzSample::SetEOS(uint32_t index)
544 {
545     OH_AVCodecBufferAttr attr;
546     attr.pts = 0;
547     attr.size = 0;
548     attr.offset = 0;
549     attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
550     int32_t res = OH_VideoEncoder_PushInputData(venc_, index, attr);
551     cout << "OH_VideoEncoder_PushInputData    EOS   res: " << res << endl;
552     unique_lock<mutex> lock(signal_->inMutex_);
553     signal_->inIdxQueue_.pop();
554     signal_->inBufferQueue_.pop();
555 }
556 
SetForceIDR()557 void VEncNdkFuzzSample::SetForceIDR()
558 {
559     OH_AVFormat *format = OH_AVFormat_Create();
560     OH_AVFormat_SetIntValue(format, OH_MD_KEY_REQUEST_I_FRAME, 1);
561     OH_VideoEncoder_SetParameter(venc_, format);
562     OH_AVFormat_Destroy(format);
563 }
564 
PushData(OH_AVMemory * buffer,uint32_t index,int32_t & result)565 int32_t VEncNdkFuzzSample::PushData(OH_AVMemory *buffer, uint32_t index, int32_t &result)
566 {
567     int32_t res = -2;
568     OH_AVCodecBufferAttr attr;
569     uint8_t *fileBuffer = OH_AVMemory_GetAddr(buffer);
570     if (fileBuffer == nullptr) {
571         cout << "Fatal: no memory" << endl;
572         return -1;
573     }
574     int32_t size = OH_AVMemory_GetSize(buffer);
575     if (DEFAULT_PIX_FMT == AV_PIXEL_FORMAT_RGBA) {
576         if (size < defaultHeight * stride_) {
577             return -1;
578         }
579         ReadOneFrameRGBA8888(fileBuffer);
580         attr.size = stride_ * defaultHeight;
581     } else {
582         if (size < (defaultHeight * stride_ + (defaultHeight * stride_ / DOUBLE))) {
583             return -1;
584         }
585         attr.size = ReadOneFrameYUV420SP(fileBuffer);
586     }
587     if (repeatRun && inFile_->eof()) {
588         inFile_->clear();
589         inFile_->seekg(0, ios::beg);
590         encodeCount++;
591         cout << "repeat"<< "   encodeCount:" << encodeCount << endl;
592         return -1;
593     }
594     if (inFile_->eof()) {
595         SetEOS(index);
596         return 0;
597     }
598     attr.pts = GetSystemTimeUs();
599     attr.offset = 0;
600     attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
601     if (enableForceIDR && (frameCount % IDR_FRAME_INTERVAL == 0)) {
602         SetForceIDR();
603     }
604     result = OH_VideoEncoder_PushInputData(venc_, index, attr);
605     unique_lock<mutex> lock(signal_->inMutex_);
606     signal_->inIdxQueue_.pop();
607     signal_->inBufferQueue_.pop();
608     return res;
609 }
610 
CheckResult(bool isRandomEosSuccess,int32_t pushResult)611 int32_t VEncNdkFuzzSample::CheckResult(bool isRandomEosSuccess, int32_t pushResult)
612 {
613     if (isRandomEosSuccess) {
614         if (pushResult == 0) {
615             errCount = errCount + 1;
616             cout << "push input after eos should be failed!  pushResult:" << pushResult << endl;
617         }
618         return -1;
619     } else if (pushResult != 0) {
620         errCount = errCount + 1;
621         cout << "push input data failed, error:" << pushResult << endl;
622         return -1;
623     }
624     return 0;
625 }
626 
InputDataNormal(bool & runningFlag,uint32_t index,OH_AVMemory * buffer)627 void VEncNdkFuzzSample::InputDataNormal(bool &runningFlag, uint32_t index, OH_AVMemory *buffer)
628 {
629     if (!inFile_->eof()) {
630         bool isRandomEosSuccess = RandomEOS(index);
631         if (isRandomEosSuccess) {
632             runningFlag = false;
633             return;
634         }
635         int32_t pushResult = 0;
636         int32_t ret = PushData(buffer, index, pushResult);
637         if (ret == 0) {
638             runningFlag = false;
639             return;
640         } else if (ret == -1) {
641             return;
642         }
643         if (CheckResult(isRandomEosSuccess, pushResult) == -1) {
644             runningFlag = false;
645             isRunning_.store(false);
646             signal_->inCond_.notify_all();
647             signal_->outCond_.notify_all();
648             return;
649         }
650         frameCount++;
651         if (enableAutoSwitchParam) {
652             AutoSwitchParam();
653         }
654     }
655 }
656 
InputDataFuzz(bool & runningFlag,uint32_t index)657 void VEncNdkFuzzSample::InputDataFuzz(bool &runningFlag, uint32_t index)
658 {
659     frameCount++;
660     if (frameCount == defaultFuzzTime) {
661         SetEOS(index);
662         runningFlag = false;
663         return;
664     }
665     OH_AVCodecBufferAttr attr;
666     attr.size = fuzzSize;
667     attr.pts = GetSystemTimeUs();
668     attr.offset = 0;
669     attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
670     OH_VideoEncoder_PushInputData(venc_, index, attr);
671     unique_lock<mutex> lock(signal_->inMutex_);
672     signal_->inIdxQueue_.pop();
673     signal_->inBufferQueue_.pop();
674 }
675 
InputFunc()676 void VEncNdkFuzzSample::InputFunc()
677 {
678     errCount = 0;
679     bool runningFlag = true;
680     while (runningFlag) {
681         if (!isRunning_.load()) {
682             break;
683         }
684         RepeatStartBeforeEOS();
685         unique_lock<mutex> lock(signal_->inMutex_);
686         signal_->inCond_.wait(lock, [this]() {
687             if (!isRunning_.load()) {
688                 return true;
689             }
690             return signal_->inIdxQueue_.size() > 0 && !isFlushing_.load();
691         });
692         if (!isRunning_.load()) {
693             break;
694         }
695         uint32_t index = signal_->inIdxQueue_.front();
696         auto buffer = signal_->inBufferQueue_.front();
697         lock.unlock();
698         unique_lock<mutex> flushlock(signal_->flushMutex_);
699         if (isFlushing_) {
700             continue;
701         }
702         if (fuzzMode == false) {
703             InputDataNormal(runningFlag, index, buffer);
704         } else {
705             InputDataFuzz(runningFlag, index);
706         }
707         flushlock.unlock();
708         if (sleepOnFPS) {
709             usleep(FRAME_INTERVAL);
710         }
711     }
712 }
713 
Flush()714 int32_t VEncNdkFuzzSample::Flush()
715 {
716     isFlushing_.store(true);
717     unique_lock<mutex> flushLock(signal_->flushMutex_);
718     unique_lock<mutex> inLock(signal_->inMutex_);
719     clearIntqueue(signal_->inIdxQueue_);
720     signal_->inCond_.notify_all();
721     inLock.unlock();
722     unique_lock<mutex> outLock(signal_->outMutex_);
723     clearIntqueue(signal_->outIdxQueue_);
724     clearBufferqueue(signal_->attrQueue_);
725     signal_->outCond_.notify_all();
726     outLock.unlock();
727     int32_t ret = OH_VideoEncoder_Flush(venc_);
728     isFlushing_.store(false);
729     flushLock.unlock();
730     return ret;
731 }
732 
Reset()733 int32_t VEncNdkFuzzSample::Reset()
734 {
735     isRunning_.store(false);
736     StopInloop();
737     StopOutloop();
738     ReleaseInFile();
739     return OH_VideoEncoder_Reset(venc_);
740 }
741 
Release()742 int32_t VEncNdkFuzzSample::Release()
743 {
744     int ret = OH_VideoEncoder_Destroy(venc_);
745     venc_ = nullptr;
746     if (signal_ != nullptr) {
747         delete signal_;
748         signal_ = nullptr;
749     }
750     return ret;
751 }
752 
StopOutloop()753 void VEncNdkFuzzSample::StopOutloop()
754 {
755     if (outputLoop_ != nullptr && outputLoop_->joinable()) {
756         unique_lock<mutex> lock(signal_->outMutex_);
757         clearIntqueue(signal_->outIdxQueue_);
758         clearBufferqueue(signal_->attrQueue_);
759         signal_->outCond_.notify_all();
760         lock.unlock();
761     }
762 }
763 
SetParameter(OH_AVFormat * format)764 int32_t VEncNdkFuzzSample::SetParameter(OH_AVFormat *format)
765 {
766     if (venc_) {
767         return OH_VideoEncoder_SetParameter(venc_, format);
768     }
769     return AV_ERR_UNKNOWN;
770 }
771 
SetParameterFuzz(int32_t data)772 int32_t VEncNdkFuzzSample::SetParameterFuzz(int32_t data)
773 {
774     if (venc_) {
775         OH_AVFormat *format = OH_AVFormat_Create();
776         if (format == nullptr) {
777             return AV_ERR_UNKNOWN;
778         }
779         double frameRate = data;
780         (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, frameRate);
781         OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, data);
782         int ret = OH_VideoEncoder_SetParameter(venc_, format);
783         OH_AVFormat_Destroy(format);
784         return ret;
785     }
786     return AV_ERR_UNKNOWN;
787 }
788