• 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 
16 #include "tester_capi.h"
17 #include "native_avcodec_videoencoder.h"
18 #include "native_avcodec_videodecoder.h"
19 #include "native_window.h"
20 #include "surface.h"
21 #include "hcodec_log.h"
22 
23 using namespace std;
24 using namespace OHOS::MediaAVCodec;
25 
OnError(OH_AVCodec * codec,int32_t errorCode,void * userData)26 void TesterCapi::OnError(OH_AVCodec *codec, int32_t errorCode, void *userData)
27 {
28     LOGI(">>");
29 }
30 
OnStreamChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)31 void TesterCapi::OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
32 {
33     LOGI(">>");
34 }
35 
OnNeedInputData(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)36 void TesterCapi::OnNeedInputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
37 {
38     TesterCapi* tester = static_cast<TesterCapi*>(userData);
39     if (tester == nullptr) {
40         return;
41     }
42     lock_guard<mutex> lk(tester->inputMtx_);
43     tester->inputList_.emplace_back(index, data);
44     tester->inputCond_.notify_all();
45 }
46 
OnNewOutputData(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)47 void TesterCapi::OnNewOutputData(
48     OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr, void *userData)
49 {
50     TesterCapi* tester = static_cast<TesterCapi*>(userData);
51     if (tester == nullptr || attr == nullptr) {
52         return;
53     }
54     lock_guard<mutex> lk(tester->outputMtx_);
55     tester->outputList_.emplace_back(index, data, *attr);
56     tester->outputCond_.notify_all();
57 }
58 
Create()59 bool TesterCapi::Create()
60 {
61     const char* mime = (opt_.protocol == H264) ? OH_AVCODEC_MIMETYPE_VIDEO_AVC : OH_AVCODEC_MIMETYPE_VIDEO_HEVC;
62     auto begin = std::chrono::steady_clock::now();
63     codec_ = opt_.isEncoder ? OH_VideoEncoder_CreateByMime(mime) : OH_VideoDecoder_CreateByMime(mime);
64     if (codec_ == nullptr) {
65         LOGE("Create failed");
66         return false;
67     }
68     CostRecorder::Instance().Update(begin,
69         opt_.isEncoder ? "OH_VideoEncoder_CreateByMime" : "OH_VideoDecoder_CreateByMime");
70     return true;
71 }
72 
SetCallback()73 bool TesterCapi::SetCallback()
74 {
75     OH_AVCodecAsyncCallback cb {
76         &TesterCapi::OnError,
77         &TesterCapi::OnStreamChanged,
78         &TesterCapi::OnNeedInputData,
79         &TesterCapi::OnNewOutputData,
80     };
81     auto begin = std::chrono::steady_clock::now();
82     OH_AVErrCode ret = opt_.isEncoder ? OH_VideoEncoder_SetCallback(codec_, cb, this) :
83                                         OH_VideoDecoder_SetCallback(codec_, cb, this);
84     if (ret != AV_ERR_OK) {
85         LOGE("SetCallback failed");
86         return false;
87     }
88     CostRecorder::Instance().Update(begin,
89         opt_.isEncoder ? "OH_VideoEncoder_SetCallback" : "OH_VideoDecoder_SetCallback");
90     return true;
91 }
92 
Start()93 bool TesterCapi::Start()
94 {
95     auto begin = std::chrono::steady_clock::now();
96     OH_AVErrCode ret = opt_.isEncoder ? OH_VideoEncoder_Start(codec_) :
97                                         OH_VideoDecoder_Start(codec_);
98     if (ret != AV_ERR_OK) {
99         LOGE("Start failed");
100         return false;
101     }
102     CostRecorder::Instance().Update(begin,
103         opt_.isEncoder ? "OH_VideoEncoder_Start" : "OH_VideoDecoder_Start");
104     return true;
105 }
106 
Stop()107 bool TesterCapi::Stop()
108 {
109     auto begin = std::chrono::steady_clock::now();
110     OH_AVErrCode ret = opt_.isEncoder ? OH_VideoEncoder_Stop(codec_) :
111                                         OH_VideoDecoder_Stop(codec_);
112     if (ret != AV_ERR_OK) {
113         LOGE("Stop failed");
114         return false;
115     }
116     CostRecorder::Instance().Update(begin,
117         opt_.isEncoder ? "OH_VideoEncoder_Stop" : "OH_VideoDecoder_Stop");
118     return true;
119 }
120 
Release()121 bool TesterCapi::Release()
122 {
123     auto begin = std::chrono::steady_clock::now();
124     OH_AVErrCode ret = opt_.isEncoder ? OH_VideoEncoder_Destroy(codec_) :
125                                         OH_VideoDecoder_Destroy(codec_);
126     if (ret != AV_ERR_OK) {
127         LOGE("Destroy failed");
128         return false;
129     }
130     CostRecorder::Instance().Update(begin,
131         opt_.isEncoder ? "OH_VideoEncoder_Destroy" : "OH_VideoDecoder_Destroy");
132     return true;
133 }
134 
Flush()135 bool TesterCapi::Flush()
136 {
137     auto begin = std::chrono::steady_clock::now();
138     OH_AVErrCode ret = opt_.isEncoder ? OH_VideoEncoder_Flush(codec_) :
139                                         OH_VideoDecoder_Flush(codec_);
140     if (ret != AV_ERR_OK) {
141         LOGE("Flush failed");
142         return false;
143     }
144     CostRecorder::Instance().Update(begin,
145         opt_.isEncoder ? "OH_VideoEncoder_Flush" : "OH_VideoDecoder_Flush");
146     return true;
147 }
148 
ClearAllBuffer()149 void TesterCapi::ClearAllBuffer()
150 {
151     {
152         lock_guard<mutex> lk(inputMtx_);
153         inputList_.clear();
154     }
155     {
156         lock_guard<mutex> lk(outputMtx_);
157         outputList_.clear();
158     }
159 }
160 
ConfigureEncoder()161 bool TesterCapi::ConfigureEncoder()
162 {
163     auto fmt = shared_ptr<OH_AVFormat>(OH_AVFormat_Create(), OH_AVFormat_Destroy);
164     IF_TRUE_RETURN_VAL_WITH_MSG(fmt == nullptr, false, "OH_AVFormat_Create failed");
165     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_WIDTH, opt_.dispW);
166     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_HEIGHT, opt_.dispH);
167     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_PIXEL_FORMAT, opt_.pixFmt);
168     OH_AVFormat_SetDoubleValue(fmt.get(), OH_MD_KEY_FRAME_RATE, opt_.frameRate);
169     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_RANGE_FLAG, opt_.rangeFlag);
170     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_COLOR_PRIMARIES, opt_.primary);
171     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_TRANSFER_CHARACTERISTICS, opt_.transfer);
172     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_MATRIX_COEFFICIENTS, opt_.matrix);
173 
174     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_I_FRAME_INTERVAL, opt_.iFrameInterval);
175     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_PROFILE, opt_.profile);
176     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, opt_.rateMode);
177     OH_AVFormat_SetLongValue(fmt.get(), OH_MD_KEY_BITRATE, opt_.bitRate);
178     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_QUALITY, opt_.quality);
179 
180     auto begin = std::chrono::steady_clock::now();
181     OH_AVErrCode ret = OH_VideoEncoder_Configure(codec_, fmt.get());
182     if (ret != AV_ERR_OK) {
183         LOGE("ConfigureEncoder failed");
184         return false;
185     }
186     CostRecorder::Instance().Update(begin, "OH_VideoEncoder_Configure");
187     return true;
188 }
189 
CreateInputSurface()190 bool TesterCapi::CreateInputSurface()
191 {
192     OHNativeWindow *window = nullptr;
193     auto begin = std::chrono::steady_clock::now();
194     OH_AVErrCode ret = OH_VideoEncoder_GetSurface(codec_, &window);
195     if (ret != AV_ERR_OK || window == nullptr) {
196         LOGE("CreateInputSurface failed");
197         return false;
198     }
199     surface_ = window->surface;
200     if (surface_ == nullptr) {
201         LOGE("surface in OHNativeWindow is null");
202         return false;
203     }
204     CostRecorder::Instance().Update(begin, "OH_VideoEncoder_GetSurface");
205     // if we dont decrease here, the OHNativeWindow will never be destroyed
206     OH_NativeWindow_DestroyNativeWindow(window);
207     return true;
208 }
209 
NotifyEos()210 bool TesterCapi::NotifyEos()
211 {
212     auto begin = std::chrono::steady_clock::now();
213     OH_AVErrCode ret = OH_VideoEncoder_NotifyEndOfStream(codec_);
214     if (ret != AV_ERR_OK) {
215         LOGE("NotifyEos failed");
216         return false;
217     }
218     CostRecorder::Instance().Update(begin, "OH_VideoEncoder_NotifyEndOfStream");
219     return true;
220 }
221 
RequestIDR()222 bool TesterCapi::RequestIDR()
223 {
224     auto fmt = shared_ptr<OH_AVFormat>(OH_AVFormat_Create(), OH_AVFormat_Destroy);
225     IF_TRUE_RETURN_VAL_WITH_MSG(fmt == nullptr, false, "OH_AVFormat_Create failed");
226     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_REQUEST_I_FRAME, true);
227 
228     auto begin = std::chrono::steady_clock::now();
229     OH_AVErrCode ret = OH_VideoEncoder_SetParameter(codec_, fmt.get());
230     if (ret != AV_ERR_OK) {
231         LOGE("RequestIDR failed");
232         return false;
233     }
234     CostRecorder::Instance().Update(begin, "OH_VideoEncoder_SetParameter");
235     return true;
236 }
237 
GetInputFormat()238 bool TesterCapi::GetInputFormat()
239 {
240     if (!opt_.isEncoder) {
241         return true;
242     }
243     auto begin = std::chrono::steady_clock::now();
244     OH_AVFormat *fmt = OH_VideoEncoder_GetInputDescription(codec_);
245     if (fmt == nullptr) {
246         LOGE("GetInputFormat failed");
247         return false;
248     }
249     CostRecorder::Instance().Update(begin, "OH_VideoEncoder_GetInputDescription");
250     inputFmt_ = shared_ptr<OH_AVFormat>(fmt, OH_AVFormat_Destroy);
251     return true;
252 }
253 
GetOutputFormat()254 bool TesterCapi::GetOutputFormat()
255 {
256     auto begin = std::chrono::steady_clock::now();
257     OH_AVFormat *fmt = opt_.isEncoder ? OH_VideoEncoder_GetOutputDescription(codec_) :
258                                         OH_VideoDecoder_GetOutputDescription(codec_);
259     if (fmt == nullptr) {
260         LOGE("GetOutputFormat failed");
261         return false;
262     }
263     CostRecorder::Instance().Update(begin,
264         opt_.isEncoder ? "OH_VideoEncoder_GetOutputDescription" : "OH_VideoDecoder_GetOutputDescription");
265     OH_AVFormat_Destroy(fmt);
266     return true;
267 }
268 
GetInputStride()269 optional<uint32_t> TesterCapi::GetInputStride()
270 {
271     int32_t stride = 0;
272     if (OH_AVFormat_GetIntValue(inputFmt_.get(), "stride", &stride)) {
273         return stride;
274     } else {
275         return nullopt;
276     }
277 }
278 
GetInputIndex(Span & span)279 std::optional<uint32_t> TesterCapi::GetInputIndex(Span& span)
280 {
281     uint32_t inputIdx;
282     OH_AVMemory* mem;
283     {
284         unique_lock<mutex> lk(inputMtx_);
285         if (opt_.timeout == -1) {
286             inputCond_.wait(lk, [this] {
287                 return !inputList_.empty();
288             });
289         } else {
290             bool ret = inputCond_.wait_for(lk, chrono::milliseconds(opt_.timeout), [this] {
291                 return !inputList_.empty();
292             });
293             if (!ret) {
294                 LOGE("time out");
295                 return nullopt;
296             }
297         }
298         std::tie(inputIdx, mem) = inputList_.front();
299         inputList_.pop_front();
300     }
301     if (mem == nullptr) {
302         LOGE("null OH_AVMemory");
303         return nullopt;
304     }
305     char *dstVa = reinterpret_cast<char*>(OH_AVMemory_GetAddr(mem));
306     int size = OH_AVMemory_GetSize(mem);
307     if (dstVa == nullptr || size <= 0) {
308         LOGE("invalid va or size");
309         return nullopt;
310     }
311     span.va = dstVa;
312     span.capacity = static_cast<size_t>(size);
313     return inputIdx;
314 }
315 
QueueInput(uint32_t idx,OH_AVCodecBufferAttr attr)316 bool TesterCapi::QueueInput(uint32_t idx, OH_AVCodecBufferAttr attr)
317 {
318     auto begin = std::chrono::steady_clock::now();
319     OH_AVErrCode err = opt_.isEncoder ? OH_VideoEncoder_PushInputData(codec_, idx, attr) :
320                                         OH_VideoDecoder_PushInputData(codec_, idx, attr);
321     if (err != AV_ERR_OK) {
322         LOGE("QueueInputBuffer failed");
323         return false;
324     }
325     CostRecorder::Instance().Update(begin,
326         opt_.isEncoder ? "OH_VideoEncoder_PushInputData" : "OH_VideoDecoder_PushInputData");
327     return true;
328 }
329 
GetOutputIndex()330 std::optional<uint32_t> TesterCapi::GetOutputIndex()
331 {
332     uint32_t outIdx;
333     OH_AVCodecBufferAttr attr;
334     {
335         unique_lock<mutex> lk(outputMtx_);
336         if (opt_.timeout == -1) {
337             outputCond_.wait(lk, [this] {
338                 return !outputList_.empty();
339             });
340         } else {
341             bool waitRes = outputCond_.wait_for(lk, chrono::milliseconds(opt_.timeout), [this] {
342                 return !outputList_.empty();
343             });
344             if (!waitRes) {
345                 LOGE("time out");
346                 return nullopt;
347             }
348         }
349         std::tie(outIdx, std::ignore, attr) = outputList_.front();
350         outputList_.pop_front();
351     }
352     if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) {
353         LOGI("output eos, quit loop");
354         return nullopt;
355     }
356     return outIdx;
357 }
358 
ReturnOutput(uint32_t idx)359 bool TesterCapi::ReturnOutput(uint32_t idx)
360 {
361     OH_AVErrCode err;
362     string apiName;
363     auto begin = std::chrono::steady_clock::now();
364     if (opt_.isEncoder) {
365         err = OH_VideoEncoder_FreeOutputData(codec_, idx);
366         apiName = "OH_VideoEncoder_FreeOutputData";
367     } else {
368         if (opt_.isBufferMode) {
369             err = OH_VideoDecoder_FreeOutputData(codec_, idx);
370             apiName = "OH_VideoDecoder_FreeOutputData";
371         } else {
372             err = OH_VideoDecoder_RenderOutputData(codec_, idx);
373             apiName = "OH_VideoDecoder_RenderOutputData";
374         }
375     }
376     if (err != AV_ERR_OK) {
377         LOGE("%{public}s failed", apiName.c_str());
378         return false;
379     }
380     CostRecorder::Instance().Update(begin, apiName);
381     return true;
382 }
383 
SetOutputSurface(sptr<Surface> & surface)384 bool TesterCapi::SetOutputSurface(sptr<Surface>& surface)
385 {
386     OHNativeWindow *window = CreateNativeWindowFromSurface(&surface);
387     if (window == nullptr) {
388         LOGE("CreateNativeWindowFromSurface failed");
389         return false;
390     }
391     auto begin = std::chrono::steady_clock::now();
392     OH_AVErrCode err = OH_VideoDecoder_SetSurface(codec_, window);
393     if (err != AV_ERR_OK) {
394         LOGE("OH_VideoDecoder_SetSurface failed");
395         return false;
396     }
397     CostRecorder::Instance().Update(begin, "OH_VideoDecoder_SetSurface");
398     return true;
399 }
400 
ConfigureDecoder()401 bool TesterCapi::ConfigureDecoder()
402 {
403     auto fmt = shared_ptr<OH_AVFormat>(OH_AVFormat_Create(), OH_AVFormat_Destroy);
404     IF_TRUE_RETURN_VAL_WITH_MSG(fmt == nullptr, false, "OH_AVFormat_Create failed");
405     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_WIDTH, opt_.dispW);
406     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_HEIGHT, opt_.dispH);
407     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_PIXEL_FORMAT, opt_.pixFmt);
408     OH_AVFormat_SetDoubleValue(fmt.get(), OH_MD_KEY_FRAME_RATE, opt_.frameRate);
409     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_ROTATION, opt_.rotation);
410 
411     auto begin = std::chrono::steady_clock::now();
412     OH_AVErrCode ret = OH_VideoDecoder_Configure(codec_, fmt.get());
413     if (ret != AV_ERR_OK) {
414         LOGE("OH_VideoDecoder_Configure failed");
415         return false;
416     }
417     CostRecorder::Instance().Update(begin, "OH_VideoDecoder_Configure");
418     return true;
419 }