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