• 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_api11_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 DEFAULT_BITRATE = 10000000;
29 constexpr uint32_t DOUBLE = 2;
30 constexpr uint32_t THREE = 3;
31 sptr<Surface> cs = nullptr;
32 sptr<Surface> ps = nullptr;
33 VEncAPI11FuzzSample *g_vEncSample = nullptr;
34 
clearIntqueue(std::queue<uint32_t> & q)35 void clearIntqueue(std::queue<uint32_t> &q)
36 {
37     std::queue<uint32_t> empty;
38     swap(empty, q);
39 }
40 } // namespace
41 
~VEncAPI11FuzzSample()42 VEncAPI11FuzzSample::~VEncAPI11FuzzSample()
43 {
44     if (surfInput && nativeWindow) {
45         OH_NativeWindow_DestroyNativeWindow(nativeWindow);
46         nativeWindow = nullptr;
47     }
48     Release();
49 }
50 
VencError(OH_AVCodec * codec,int32_t errorCode,void * userData)51 static void VencError(OH_AVCodec *codec, int32_t errorCode, void *userData)
52 {
53     cout << "Error errorCode=" << errorCode << endl;
54     g_vEncSample->isRunning_.store(false);
55     g_vEncSample->signal_->inCond_.notify_all();
56 }
57 
VencFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)58 static void VencFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
59 {
60     cout << "Format Changed" << endl;
61 }
62 
onEncInputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * buffer,void * userData)63 static void onEncInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
64 {
65     VEncSignal *signal = static_cast<VEncSignal *>(userData);
66     unique_lock<mutex> lock(signal->inMutex_);
67     signal->inIdxQueue_.push(index);
68     signal->inBufferQueue_.push(buffer);
69     signal->inCond_.notify_all();
70 }
71 
onEncOutputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * buffer,void * userData)72 static void onEncOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
73 {
74     OH_VideoEncoder_FreeOutputBuffer(codec, index);
75 }
76 
onEncInputParam(OH_AVCodec * codec,uint32_t index,OH_AVFormat * parameter,void * userData)77 static void onEncInputParam(OH_AVCodec *codec, uint32_t index, OH_AVFormat *parameter, void *userData)
78 {
79     OH_AVFormat_SetIntValue(parameter, OH_MD_KEY_BITRATE, DEFAULT_BITRATE);
80     OH_VideoEncoder_PushInputParameter(codec, index);
81     return;
82 }
83 
GetSystemTimeUs()84 int64_t VEncAPI11FuzzSample::GetSystemTimeUs()
85 {
86     struct timespec now;
87     (void)clock_gettime(CLOCK_BOOTTIME, &now);
88     int64_t nanoTime = reinterpret_cast<int64_t>(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec;
89 
90     return nanoTime / NANOS_IN_MICRO;
91 }
92 
ConfigureVideoEncoder()93 int32_t VEncAPI11FuzzSample::ConfigureVideoEncoder()
94 {
95     OH_AVFormat *format = OH_AVFormat_Create();
96     if (format == nullptr) {
97         return AV_ERR_UNKNOWN;
98     }
99     OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, HEVC_PROFILE_MAIN);
100     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, defaultWidth);
101     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, defaultHeight);
102     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, defaultPixFmt);
103     (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, defaultFrameRate);
104     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, defaultKeyFrameInterval);
105     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_ENABLE_B_FRAME, 1);
106     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY, 1);
107     if (defaultBitRate == CQ) {
108         (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_QUALITY, defaultQuality);
109     } else {
110         (void)OH_AVFormat_SetLongValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, defaultBitRate);
111     }
112     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, defaultBitrateMode);
113     if (enableRepeat) {
114         OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_REPEAT_PREVIOUS_FRAME_AFTER, 1);
115         if (setMaxCount) {
116             OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_REPEAT_PREVIOUS_MAX_COUNT, 1);
117         }
118     }
119     int ret = OH_VideoEncoder_Configure(venc_, format);
120     OH_AVFormat_Destroy(format);
121     return ret;
122 }
SetVideoEncoderCallback()123 int32_t VEncAPI11FuzzSample::SetVideoEncoderCallback()
124 {
125     signal_ = new VEncSignal();
126     if (signal_ == nullptr) {
127         cout << "Failed to new VEncSignal" << endl;
128         return AV_ERR_UNKNOWN;
129     }
130     if (surfInput) {
131         int32_t ret = OH_VideoEncoder_RegisterParameterCallback(venc_, onEncInputParam, static_cast<void *>(this));
132         if (ret != AV_ERR_OK) {
133             return ret;
134         }
135     }
136     cb_.onError = VencError;
137     cb_.onStreamChanged = VencFormatChanged;
138     cb_.onNeedInputBuffer = onEncInputBufferAvailable;
139     cb_.onNewOutputBuffer = onEncOutputBufferAvailable;
140     return OH_VideoEncoder_RegisterCallback(venc_, cb_, static_cast<void *>(signal_));
141 }
142 
StopInloop()143 void VEncAPI11FuzzSample::StopInloop()
144 {
145     if (inputLoop_ != nullptr && inputLoop_->joinable()) {
146         unique_lock<mutex> lock(signal_->inMutex_);
147         clearIntqueue(signal_->inIdxQueue_);
148         isRunning_.store(false);
149         signal_->inCond_.notify_all();
150         lock.unlock();
151 
152         inputLoop_->join();
153         inputLoop_ = nullptr;
154     }
155 }
156 
CreateSurface()157 int32_t VEncAPI11FuzzSample::CreateSurface()
158 {
159     int32_t ret = 0;
160     ret = OH_VideoEncoder_GetSurface(venc_, &nativeWindow);
161     if (ret != AV_ERR_OK) {
162         cout << "OH_VideoEncoder_GetSurface fail" << endl;
163         return ret;
164     }
165     ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_FORMAT, GRAPHIC_PIXEL_FMT_YCBCR_420_SP);
166     if (ret != AV_ERR_OK) {
167         cout << "NativeWindowHandleOpt SET_FORMAT fail" << endl;
168         return ret;
169     }
170     ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_BUFFER_GEOMETRY, defaultWidth, defaultHeight);
171     if (ret != AV_ERR_OK) {
172         cout << "NativeWindowHandleOpt SET_BUFFER_GEOMETRY fail" << endl;
173         return ret;
174     }
175     return AV_ERR_OK;
176 }
177 
OpenFile()178 int32_t VEncAPI11FuzzSample::OpenFile()
179 {
180     if (fuzzMode) {
181         return AV_ERR_OK;
182     }
183     int32_t ret = AV_ERR_OK;
184     inFile_ = make_unique<ifstream>();
185     if (inFile_ == nullptr) {
186         isRunning_.store(false);
187         (void)OH_VideoEncoder_Stop(venc_);
188         return AV_ERR_UNKNOWN;
189     }
190     inFile_->open(inpDir, ios::in | ios::binary);
191     if (!inFile_->is_open()) {
192         cout << "file open fail" << endl;
193         isRunning_.store(false);
194         (void)OH_VideoEncoder_Stop(venc_);
195         inFile_->close();
196         inFile_.reset();
197         inFile_ = nullptr;
198         return AV_ERR_UNKNOWN;
199     }
200     return ret;
201 }
202 
GetStride()203 void VEncAPI11FuzzSample::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 
StartVideoEncoder()212 int32_t VEncAPI11FuzzSample::StartVideoEncoder()
213 {
214     isRunning_.store(true);
215     int32_t ret = 0;
216     if (surfInput) {
217         ret = CreateSurface();
218         if (ret != AV_ERR_OK) {
219             return ret;
220         }
221     }
222     if (OpenFile() != AV_ERR_OK) {
223         return AV_ERR_UNKNOWN;
224     }
225     ret = OH_VideoEncoder_Start(venc_);
226     GetStride();
227     if (ret != AV_ERR_OK) {
228         isRunning_.store(false);
229         signal_->inCond_.notify_all();
230         return ret;
231     }
232     if (surfInput) {
233         inputLoop_ = make_unique<thread>(&VEncAPI11FuzzSample::InputFuncSurface, this);
234     } else {
235         inputLoop_ = make_unique<thread>(&VEncAPI11FuzzSample::InputFunc, this);
236     }
237     if (inputLoop_ == nullptr) {
238         isRunning_.store(false);
239         (void)OH_VideoEncoder_Stop(venc_);
240         return AV_ERR_UNKNOWN;
241     }
242     return AV_ERR_OK;
243 }
244 
CreateVideoEncoder()245 int32_t VEncAPI11FuzzSample::CreateVideoEncoder()
246 {
247     venc_ = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
248     g_vEncSample = this;
249     return venc_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
250 }
251 
WaitForEOS()252 void VEncAPI11FuzzSample::WaitForEOS()
253 {
254     if (inputLoop_)
255         inputLoop_->join();
256     inputLoop_ = nullptr;
257 }
258 
PushData(OH_AVBuffer * buffer,uint32_t index,int32_t & result)259 int32_t VEncAPI11FuzzSample::PushData(OH_AVBuffer *buffer, uint32_t index, int32_t &result)
260 {
261     int32_t res = -2;
262     OH_AVCodecBufferAttr attr;
263     uint8_t *fileBuffer = OH_AVBuffer_GetAddr(buffer);
264     if (fileBuffer == nullptr) {
265         cout << "Fatal: no memory" << endl;
266         return -1;
267     }
268     int32_t size = OH_AVBuffer_GetCapacity(buffer);
269     if (size < (defaultWidth * stride_ + (defaultWidth * stride_ / DOUBLE))) {
270         return -1;
271     }
272     attr.size = ReadOneFrameYUV420SP(fileBuffer);
273     if (inFile_->eof()) {
274         SetEOS(index, buffer);
275         return 0;
276     }
277     attr.pts = GetSystemTimeUs();
278     attr.offset = 0;
279     attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
280     OH_AVBuffer_SetBufferAttr(buffer, &attr);
281     result = OH_VideoEncoder_PushInputBuffer(venc_, index);
282     frameCount++;
283     unique_lock<mutex> lock(signal_->inMutex_);
284     signal_->inIdxQueue_.pop();
285     signal_->inBufferQueue_.pop();
286     return res;
287 }
288 
ReadOneFrameYUV420SP(uint8_t * dst)289 uint32_t VEncAPI11FuzzSample::ReadOneFrameYUV420SP(uint8_t *dst)
290 {
291     uint8_t *start = dst;
292     // copy Y
293     for (uint32_t i = 0; i < defaultWidth; i++) {
294         inFile_->read(reinterpret_cast<char *>(dst), defaultWidth);
295         if (!ReturnZeroIfEOS(defaultWidth)) {
296             return 0;
297         }
298         dst += stride_;
299     }
300     // copy UV
301     for (uint32_t i = 0; i < defaultWidth / DOUBLE; i++) {
302         inFile_->read(reinterpret_cast<char *>(dst), defaultWidth);
303         if (!ReturnZeroIfEOS(defaultWidth)) {
304             return 0;
305         }
306         dst += stride_;
307     }
308     return dst - start;
309 }
310 
ReturnZeroIfEOS(uint32_t expectedSize)311 uint32_t VEncAPI11FuzzSample::ReturnZeroIfEOS(uint32_t expectedSize)
312 {
313     if (inFile_->gcount() != (expectedSize)) {
314         cout << "no more data" << endl;
315         return 0;
316     }
317     return 1;
318 }
319 
FlushSurf(OHNativeWindowBuffer * ohNativeWindowBuffer,OH_NativeBuffer * nativeBuffer)320 uint32_t VEncAPI11FuzzSample::FlushSurf(OHNativeWindowBuffer *ohNativeWindowBuffer, OH_NativeBuffer *nativeBuffer)
321 {
322     struct Region region;
323     struct Region::Rect *rect = new Region::Rect();
324     rect->x = 0;
325     rect->y = 0;
326     rect->w = defaultWidth;
327     rect->h = defaultHeight;
328     region.rects = rect;
329     NativeWindowHandleOpt(nativeWindow, SET_UI_TIMESTAMP, GetSystemTimeUs());
330     int32_t err = OH_NativeBuffer_Unmap(nativeBuffer);
331     if (err != 0) {
332         return 1;
333     }
334     err = OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, ohNativeWindowBuffer, -1, region);
335     delete rect;
336     if (err != 0) {
337         return 1;
338     }
339     return 0;
340 }
341 
InputFuncSurface()342 void VEncAPI11FuzzSample::InputFuncSurface()
343 {
344     while (isRunning_.load()) {
345         OHNativeWindowBuffer *ohNativeWindowBuffer;
346         int fenceFd = -1;
347         if (nativeWindow == nullptr) {
348             cout << "nativeWindow == nullptr" << endl;
349             isRunning_.store(false);
350             break;
351         }
352         int32_t err = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &ohNativeWindowBuffer, &fenceFd);
353         if (err != 0) {
354             cout << "RequestBuffer failed, GSError=" << err << endl;
355             isRunning_.store(false);
356             break;
357         }
358         if (fenceFd > 0) {
359             close(fenceFd);
360         }
361         OH_NativeBuffer *nativeBuffer = OH_NativeBufferFromNativeWindowBuffer(ohNativeWindowBuffer);
362         void *virAddr = nullptr;
363         OH_NativeBuffer_Config config;
364         OH_NativeBuffer_GetConfig (nativeBuffer, &config);
365         err = OH_NativeBuffer_Map(nativeBuffer, &virAddr);
366         if (err != 0) {
367             cout << "OH_NativeBuffer_Map failed, GSError=" << err << endl;
368             isRunning_.store(false);
369             break;
370         }
371         uint8_t *dst = (uint8_t *)virAddr;
372         if (dst == nullptr) {
373             break;
374         }
375         if (memcpy_s(dst, (config.stride * config.height * THREE) / DOUBLE, fuzzData, fuzzSize) != EOK) {
376             break;
377         }
378         if (frameCount == maxFrameInput) {
379             err = OH_VideoEncoder_NotifyEndOfStream(venc_);
380             if (err != 0) {
381                 cout << "OH_VideoEncoder_NotifyEndOfStream failed" << endl;
382                 isRunning_.store(false);
383             }
384             break;
385         }
386         if (FlushSurf(ohNativeWindowBuffer, nativeBuffer)) {
387             break;
388         }
389         usleep(FRAME_INTERVAL);
390         frameCount++;
391     }
392 }
393 
SetEOS(uint32_t index,OH_AVBuffer * buffer)394 void VEncAPI11FuzzSample::SetEOS(uint32_t index, OH_AVBuffer *buffer)
395 {
396     OH_AVCodecBufferAttr attr;
397     attr.pts = 0;
398     attr.size = 0;
399     attr.offset = 0;
400     attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
401     OH_AVBuffer_SetBufferAttr(buffer, &attr);
402     int32_t res = OH_VideoEncoder_PushInputBuffer(venc_, index);
403     cout << "OH_VideoEncoder_PushInputBuffer    EOS   res: " << res << endl;
404     unique_lock<mutex> lock(signal_->inMutex_);
405 }
406 
InputFunc()407 void VEncAPI11FuzzSample::InputFunc()
408 {
409     errCount = 0;
410     while (isRunning_.load()) {
411         unique_lock<mutex> lock(signal_->inMutex_);
412         signal_->inCond_.wait(lock, [this]() {
413             if (!isRunning_.load()) {
414                 return true;
415             }
416             return signal_->inIdxQueue_.size() > 0;
417         });
418         if (!isRunning_.load()) {
419             break;
420         }
421         uint32_t index = signal_->inIdxQueue_.front();
422         auto buffer = signal_->inBufferQueue_.front();
423         signal_->inIdxQueue_.pop();
424         signal_->inBufferQueue_.pop();
425 
426         lock.unlock();
427         OH_AVCodecBufferAttr attr;
428         int32_t bufferSize = OH_AVBuffer_GetCapacity(buffer);
429         uint8_t *fileBuffer = OH_AVBuffer_GetAddr(buffer);
430         if (fileBuffer == nullptr) {
431             break;
432         }
433         if (memcpy_s(fileBuffer, bufferSize, fuzzData, fuzzSize) != EOK) {
434             cout << "Fatal: memcpy fail" << endl;
435             break;
436         }
437         attr.size = fuzzSize;
438         if (frameCount == maxFrameInput) {
439             SetEOS(index, buffer);
440             break;
441         }
442         attr.pts = GetSystemTimeUs();
443         attr.offset = 0;
444         attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
445         OH_AVBuffer_SetBufferAttr(buffer, &attr);
446         OH_VideoEncoder_PushInputBuffer(venc_, index);
447         frameCount++;
448 
449         if (sleepOnFPS) {
450             usleep(FRAME_INTERVAL);
451         }
452     }
453 }
454 
Reset()455 int32_t VEncAPI11FuzzSample::Reset()
456 {
457     isRunning_.store(false);
458     StopInloop();
459     return OH_VideoEncoder_Reset(venc_);
460 }
461 
Release()462 int32_t VEncAPI11FuzzSample::Release()
463 {
464     int ret = OH_VideoEncoder_Destroy(venc_);
465     venc_ = nullptr;
466     if (signal_ != nullptr) {
467         delete signal_;
468         signal_ = nullptr;
469     }
470     return ret;
471 }
472 
SetParameter(int32_t data)473 int32_t VEncAPI11FuzzSample::SetParameter(int32_t data)
474 {
475     if (venc_) {
476         OH_AVFormat *format = OH_AVFormat_Create();
477         if (format == nullptr) {
478             return AV_ERR_UNKNOWN;
479         }
480         double frameRate = data;
481         (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, frameRate);
482         OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, data);
483         int ret = OH_VideoEncoder_SetParameter(venc_, format);
484         OH_AVFormat_Destroy(format);
485         return ret;
486     }
487     return AV_ERR_UNKNOWN;
488 }