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