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 "common/native_mfmagic.h"
18 #include "hcodec_log.h"
19 #include "native_avcodec_videodecoder.h"
20 #include "native_avcodec_videoencoder.h"
21 #include "native_window.h"
22 
23 namespace OHOS::MediaAVCodec {
24 using namespace std;
25 
OnError(OH_AVCodec * codec,int32_t errorCode,void * userData)26 void TesterCapi::OnError(OH_AVCodec *codec, int32_t errorCode, void *userData)
27 {
28     TLOGI(">>");
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     TLOGI(">>");
34 }
35 
OnNeedInputData(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)36 void TesterCapiOld::OnNeedInputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
37 {
38     TesterCapiOld* tester = static_cast<TesterCapiOld*>(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 TesterCapiOld::OnNewOutputData(
48     OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr, void *userData)
49 {
50     TesterCapiOld* tester = static_cast<TesterCapiOld*>(userData);
51     if (tester == nullptr || attr == nullptr) {
52         return;
53     }
54     tester->AfterGotOutput(*attr);
55     lock_guard<mutex> lk(tester->outputMtx_);
56     tester->outputList_.emplace_back(index, data, *attr);
57     tester->outputCond_.notify_all();
58 }
59 
OnNeedInputBuffer(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * buffer,void * userData)60 void TesterCapiNew::OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
61 {
62     TesterCapiNew* tester = static_cast<TesterCapiNew*>(userData);
63     if (tester == nullptr) {
64         return;
65     }
66     lock_guard<mutex> lk(tester->inputMtx_);
67     tester->inputList_.emplace_back(index, buffer);
68     tester->inputCond_.notify_all();
69 }
70 
OnNewOutputBuffer(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * buffer,void * userData)71 void TesterCapiNew::OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
72 {
73     TesterCapiNew* tester = static_cast<TesterCapiNew*>(userData);
74     if (tester == nullptr) {
75         return;
76     }
77     OH_AVCodecBufferAttr attr;
78     OH_AVBuffer_GetBufferAttr(buffer, &attr);
79     tester->AfterGotOutput(attr);
80     lock_guard<mutex> lk(tester->outputMtx_);
81     tester->outputList_.emplace_back(index, buffer);
82     tester->outputCond_.notify_all();
83 }
84 
Create()85 bool TesterCapi::Create()
86 {
87     string mime = GetCodecMime(opt_.protocol);
88     auto begin = std::chrono::steady_clock::now();
89     codec_ = opt_.isEncoder ? OH_VideoEncoder_CreateByMime(mime.c_str()) : OH_VideoDecoder_CreateByMime(mime.c_str());
90     if (codec_ == nullptr) {
91         TLOGE("Create failed");
92         return false;
93     }
94     CostRecorder::Instance().Update(begin,
95         opt_.isEncoder ? "OH_VideoEncoder_CreateByMime" : "OH_VideoDecoder_CreateByMime");
96     return true;
97 }
98 
SetCallback()99 bool TesterCapiOld::SetCallback()
100 {
101     OH_AVCodecAsyncCallback cb {
102         &TesterCapi::OnError,
103         &TesterCapi::OnStreamChanged,
104         &TesterCapiOld::OnNeedInputData,
105         &TesterCapiOld::OnNewOutputData,
106     };
107     auto begin = std::chrono::steady_clock::now();
108     OH_AVErrCode ret = opt_.isEncoder ? OH_VideoEncoder_SetCallback(codec_, cb, this) :
109                                         OH_VideoDecoder_SetCallback(codec_, cb, this);
110     if (ret != AV_ERR_OK) {
111         TLOGE("SetCallback failed");
112         return false;
113     }
114     CostRecorder::Instance().Update(begin,
115         opt_.isEncoder ? "OH_VideoEncoder_SetCallback" : "OH_VideoDecoder_SetCallback");
116     return true;
117 }
118 
SetCallback()119 bool TesterCapiNew::SetCallback()
120 {
121     auto begin = std::chrono::steady_clock::now();
122     OH_AVCodecCallback cb {
123         &TesterCapi::OnError,
124         &TesterCapi::OnStreamChanged,
125         &TesterCapiNew::OnNeedInputBuffer,
126         &TesterCapiNew::OnNewOutputBuffer,
127     };
128     OH_AVErrCode ret = opt_.isEncoder ? OH_VideoEncoder_RegisterCallback(codec_, cb, this) :
129                                         OH_VideoDecoder_RegisterCallback(codec_, cb, this);
130     if (ret != AV_ERR_OK) {
131         TLOGE("RegisterCallback failed");
132         return false;
133     }
134     CostRecorder::Instance().Update(begin,
135         opt_.isEncoder ? "OH_VideoEncoder_RegisterCallback" : "OH_VideoDecoder_RegisterCallback");
136     return true;
137 }
138 
Start()139 bool TesterCapi::Start()
140 {
141     auto begin = std::chrono::steady_clock::now();
142     OH_AVErrCode ret = opt_.isEncoder ? OH_VideoEncoder_Start(codec_) :
143                                         OH_VideoDecoder_Start(codec_);
144     if (ret != AV_ERR_OK) {
145         TLOGE("Start failed");
146         return false;
147     }
148     CostRecorder::Instance().Update(begin,
149         opt_.isEncoder ? "OH_VideoEncoder_Start" : "OH_VideoDecoder_Start");
150     return true;
151 }
152 
Stop()153 bool TesterCapi::Stop()
154 {
155     auto begin = std::chrono::steady_clock::now();
156     OH_AVErrCode ret = opt_.isEncoder ? OH_VideoEncoder_Stop(codec_) :
157                                         OH_VideoDecoder_Stop(codec_);
158     if (ret != AV_ERR_OK) {
159         TLOGE("Stop failed");
160         return false;
161     }
162     CostRecorder::Instance().Update(begin,
163         opt_.isEncoder ? "OH_VideoEncoder_Stop" : "OH_VideoDecoder_Stop");
164     return true;
165 }
166 
Release()167 bool TesterCapi::Release()
168 {
169     auto begin = std::chrono::steady_clock::now();
170     OH_AVErrCode ret = opt_.isEncoder ? OH_VideoEncoder_Destroy(codec_) :
171                                         OH_VideoDecoder_Destroy(codec_);
172     if (ret != AV_ERR_OK) {
173         TLOGE("Destroy failed");
174         return false;
175     }
176     CostRecorder::Instance().Update(begin,
177         opt_.isEncoder ? "OH_VideoEncoder_Destroy" : "OH_VideoDecoder_Destroy");
178     return true;
179 }
180 
Flush()181 bool TesterCapi::Flush()
182 {
183     auto begin = std::chrono::steady_clock::now();
184     OH_AVErrCode ret = opt_.isEncoder ? OH_VideoEncoder_Flush(codec_) :
185                                         OH_VideoDecoder_Flush(codec_);
186     if (ret != AV_ERR_OK) {
187         TLOGE("Flush failed");
188         return false;
189     }
190     CostRecorder::Instance().Update(begin,
191         opt_.isEncoder ? "OH_VideoEncoder_Flush" : "OH_VideoDecoder_Flush");
192     return true;
193 }
194 
ClearAllBuffer()195 void TesterCapiOld::ClearAllBuffer()
196 {
197     {
198         lock_guard<mutex> lk(inputMtx_);
199         inputList_.clear();
200     }
201     {
202         lock_guard<mutex> lk(outputMtx_);
203         outputList_.clear();
204     }
205 }
206 
ClearAllBuffer()207 void TesterCapiNew::ClearAllBuffer()
208 {
209     {
210         lock_guard<mutex> lk(inputMtx_);
211         inputList_.clear();
212     }
213     {
214         lock_guard<mutex> lk(outputMtx_);
215         outputList_.clear();
216     }
217 }
218 
ConfigureEncoder()219 bool TesterCapi::ConfigureEncoder()
220 {
221     auto fmt = shared_ptr<OH_AVFormat>(OH_AVFormat_Create(), OH_AVFormat_Destroy);
222     IF_TRUE_RETURN_VAL_WITH_MSG(fmt == nullptr, false, "OH_AVFormat_Create failed");
223     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_WIDTH, opt_.dispW);
224     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_HEIGHT, opt_.dispH);
225     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_PIXEL_FORMAT, static_cast<int32_t>(opt_.pixFmt));
226     OH_AVFormat_SetDoubleValue(fmt.get(), OH_MD_KEY_FRAME_RATE, opt_.frameRate);
227     if (opt_.rangeFlag.has_value()) {
228         OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_RANGE_FLAG, opt_.rangeFlag.value());
229     }
230     if (opt_.primary.has_value()) {
231         OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_COLOR_PRIMARIES, opt_.primary.value());
232     }
233     if (opt_.transfer.has_value()) {
234         OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_TRANSFER_CHARACTERISTICS, opt_.transfer.value());
235     }
236     if (opt_.matrix.has_value()) {
237         OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_MATRIX_COEFFICIENTS, opt_.matrix.value());
238     }
239     if (opt_.iFrameInterval.has_value()) {
240         OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_I_FRAME_INTERVAL, opt_.iFrameInterval.value());
241     }
242     if (opt_.profile.has_value()) {
243         OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_PROFILE, opt_.profile.value());
244     }
245     if (opt_.rateMode.has_value()) {
246         OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, opt_.rateMode.value());
247     }
248     if (opt_.bitRate.has_value()) {
249         OH_AVFormat_SetLongValue(fmt.get(), OH_MD_KEY_BITRATE, opt_.bitRate.value());
250     }
251     if (opt_.quality.has_value()) {
252         OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_QUALITY, opt_.quality.value());
253     }
254 
255     auto begin = std::chrono::steady_clock::now();
256     OH_AVErrCode ret = OH_VideoEncoder_Configure(codec_, fmt.get());
257     if (ret != AV_ERR_OK) {
258         TLOGE("ConfigureEncoder failed");
259         return false;
260     }
261     CostRecorder::Instance().Update(begin, "OH_VideoEncoder_Configure");
262     return true;
263 }
264 
CreateInputSurface()265 sptr<Surface> TesterCapi::CreateInputSurface()
266 {
267     OHNativeWindow *window = nullptr;
268     auto begin = std::chrono::steady_clock::now();
269     OH_AVErrCode ret = OH_VideoEncoder_GetSurface(codec_, &window);
270     if (ret != AV_ERR_OK || window == nullptr) {
271         TLOGE("CreateInputSurface failed");
272         return nullptr;
273     }
274     sptr<Surface> surface = window->surface;
275     if (surface == nullptr) {
276         TLOGE("surface in OHNativeWindow is null");
277         return nullptr;
278     }
279     CostRecorder::Instance().Update(begin, "OH_VideoEncoder_GetSurface");
280     // if we dont decrease here, the OHNativeWindow will never be destroyed
281     OH_NativeWindow_DestroyNativeWindow(window);
282     return surface;
283 }
284 
NotifyEos()285 bool TesterCapi::NotifyEos()
286 {
287     auto begin = std::chrono::steady_clock::now();
288     OH_AVErrCode ret = OH_VideoEncoder_NotifyEndOfStream(codec_);
289     if (ret != AV_ERR_OK) {
290         TLOGE("NotifyEos failed");
291         return false;
292     }
293     CostRecorder::Instance().Update(begin, "OH_VideoEncoder_NotifyEndOfStream");
294     return true;
295 }
296 
RequestIDR()297 bool TesterCapi::RequestIDR()
298 {
299     auto fmt = shared_ptr<OH_AVFormat>(OH_AVFormat_Create(), OH_AVFormat_Destroy);
300     IF_TRUE_RETURN_VAL_WITH_MSG(fmt == nullptr, false, "OH_AVFormat_Create failed");
301     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_REQUEST_I_FRAME, true);
302 
303     auto begin = std::chrono::steady_clock::now();
304     OH_AVErrCode ret = OH_VideoEncoder_SetParameter(codec_, fmt.get());
305     if (ret != AV_ERR_OK) {
306         TLOGE("RequestIDR failed");
307         return false;
308     }
309     CostRecorder::Instance().Update(begin, "OH_VideoEncoder_SetParameter");
310     return true;
311 }
312 
GetInputFormat()313 bool TesterCapi::GetInputFormat()
314 {
315     if (!opt_.isEncoder) {
316         return true;
317     }
318     auto begin = std::chrono::steady_clock::now();
319     OH_AVFormat *fmt = OH_VideoEncoder_GetInputDescription(codec_);
320     if (fmt == nullptr) {
321         TLOGE("GetInputFormat failed");
322         return false;
323     }
324     CostRecorder::Instance().Update(begin, "OH_VideoEncoder_GetInputDescription");
325     inputFmt_ = shared_ptr<OH_AVFormat>(fmt, OH_AVFormat_Destroy);
326     OH_AVFormat_GetIntValue(inputFmt_.get(), "stride", &inputStride_);
327     return true;
328 }
329 
GetOutputFormat()330 bool TesterCapi::GetOutputFormat()
331 {
332     auto begin = std::chrono::steady_clock::now();
333     OH_AVFormat *fmt = opt_.isEncoder ? OH_VideoEncoder_GetOutputDescription(codec_) :
334                                         OH_VideoDecoder_GetOutputDescription(codec_);
335     if (fmt == nullptr) {
336         TLOGE("GetOutputFormat failed");
337         return false;
338     }
339     CostRecorder::Instance().Update(begin,
340         opt_.isEncoder ? "OH_VideoEncoder_GetOutputDescription" : "OH_VideoDecoder_GetOutputDescription");
341     OH_AVFormat_Destroy(fmt);
342     return true;
343 }
344 
GetInputStride()345 optional<uint32_t> TesterCapi::GetInputStride()
346 {
347     int32_t stride = 0;
348     if (OH_AVFormat_GetIntValue(inputFmt_.get(), "stride", &stride)) {
349         return stride;
350     } else {
351         return nullopt;
352     }
353 }
354 
WaitForInput(BufInfo & buf)355 bool TesterCapiOld::WaitForInput(BufInfo& buf)
356 {
357     {
358         unique_lock<mutex> lk(inputMtx_);
359         if (opt_.timeout == -1) {
360             inputCond_.wait(lk, [this] {
361                 return !inputList_.empty();
362             });
363         } else {
364             bool ret = inputCond_.wait_for(lk, chrono::milliseconds(opt_.timeout), [this] {
365                 return !inputList_.empty();
366             });
367             if (!ret) {
368                 TLOGE("time out");
369                 return false;
370             }
371         }
372         std::tie(buf.idx, buf.mem) = inputList_.front();
373         inputList_.pop_front();
374     }
375     if (buf.mem == nullptr) {
376         TLOGE("null OH_AVMemory");
377         return false;
378     }
379     buf.va = OH_AVMemory_GetAddr(buf.mem);
380     buf.capacity = OH_AVMemory_GetSize(buf.mem);
381     if (opt_.isEncoder && opt_.isBufferMode) {
382         buf.dispW = opt_.dispW;
383         buf.dispH = opt_.dispH;
384         buf.fmt = displayFmt_;
385         if (inputStride_ < static_cast<int32_t>(opt_.dispW)) {
386             TLOGE("pixelStride %d < dispW %u", inputStride_, opt_.dispW);
387             return false;
388         }
389         buf.byteStride = inputStride_;
390     }
391     return true;
392 }
393 
WaitForInput(BufInfo & buf)394 bool TesterCapiNew::WaitForInput(BufInfo& buf)
395 {
396     {
397         unique_lock<mutex> lk(inputMtx_);
398         if (opt_.timeout == -1) {
399             inputCond_.wait(lk, [this] {
400                 return !inputList_.empty();
401             });
402         } else {
403             bool ret = inputCond_.wait_for(lk, chrono::milliseconds(opt_.timeout), [this] {
404                 return !inputList_.empty();
405             });
406             if (!ret) {
407                 TLOGE("time out");
408                 return false;
409             }
410         }
411         std::tie(buf.idx, buf.cavbuf) = inputList_.front();
412         inputList_.pop_front();
413     }
414     if (buf.cavbuf == nullptr) {
415         TLOGE("null OH_AVBuffer");
416         return false;
417     }
418     buf.va = OH_AVBuffer_GetAddr(buf.cavbuf);
419     buf.capacity = OH_AVBuffer_GetCapacity(buf.cavbuf);
420     if (opt_.isEncoder && opt_.isBufferMode) {
421         OH_NativeBuffer* nativeBuffer = OH_AVBuffer_GetNativeBuffer(buf.cavbuf);
422         if (!NativeBufferToBufferInfo(buf, nativeBuffer)) {
423             return false;
424         }
425     }
426     return true;
427 }
428 
WaitForOutput(BufInfo & buf)429 bool TesterCapiOld::WaitForOutput(BufInfo& buf)
430 {
431     {
432         unique_lock<mutex> lk(outputMtx_);
433         if (opt_.timeout == -1) {
434             outputCond_.wait(lk, [this] {
435                 return !outputList_.empty();
436             });
437         } else {
438             bool waitRes = outputCond_.wait_for(lk, chrono::milliseconds(opt_.timeout), [this] {
439                 return !outputList_.empty();
440             });
441             if (!waitRes) {
442                 TLOGE("time out");
443                 return false;
444             }
445         }
446         std::tie(buf.idx, buf.mem, buf.attr) = outputList_.front();
447         outputList_.pop_front();
448     }
449     if (buf.attr.flags & AVCODEC_BUFFER_FLAGS_EOS) {
450         TLOGI("output eos, quit loop");
451         return false;
452     }
453     if (buf.mem != nullptr) {
454         buf.va = OH_AVMemory_GetAddr(buf.mem);
455         buf.capacity = OH_AVMemory_GetSize(buf.mem);
456     }
457     return true;
458 }
459 
WaitForOutput(BufInfo & buf)460 bool TesterCapiNew::WaitForOutput(BufInfo& buf)
461 {
462     {
463         unique_lock<mutex> lk(outputMtx_);
464         if (opt_.timeout == -1) {
465             outputCond_.wait(lk, [this] {
466                 return !outputList_.empty();
467             });
468         } else {
469             bool waitRes = outputCond_.wait_for(lk, chrono::milliseconds(opt_.timeout), [this] {
470                 return !outputList_.empty();
471             });
472             if (!waitRes) {
473                 TLOGE("time out");
474                 return false;
475             }
476         }
477         std::tie(buf.idx, buf.cavbuf) = outputList_.front();
478         outputList_.pop_front();
479     }
480     OH_AVCodecBufferAttr attr;
481     OH_AVBuffer_GetBufferAttr(buf.cavbuf, &attr);
482     if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) {
483         TLOGI("output eos, quit loop");
484         return false;
485     }
486     buf.attr = attr;
487     buf.va = OH_AVBuffer_GetAddr(buf.cavbuf);
488     buf.capacity = OH_AVBuffer_GetCapacity(buf.cavbuf);
489     return true;
490 }
491 
ReturnInput(const BufInfo & buf)492 bool TesterCapiOld::ReturnInput(const BufInfo& buf)
493 {
494     auto begin = std::chrono::steady_clock::now();
495     OH_AVErrCode err = opt_.isEncoder ? OH_VideoEncoder_PushInputData(codec_, buf.idx, buf.attr) :
496                                         OH_VideoDecoder_PushInputData(codec_, buf.idx, buf.attr);
497     if (err != AV_ERR_OK) {
498         TLOGE("QueueInputBuffer failed");
499         return false;
500     }
501     CostRecorder::Instance().Update(begin,
502         opt_.isEncoder ? "OH_VideoEncoder_PushInputData" : "OH_VideoDecoder_PushInputData");
503     return true;
504 }
505 
ReturnInput(const BufInfo & buf)506 bool TesterCapiNew::ReturnInput(const BufInfo& buf)
507 {
508     OH_AVBuffer_SetBufferAttr(buf.cavbuf, &buf.attr);
509     auto begin = std::chrono::steady_clock::now();
510     OH_AVErrCode err = opt_.isEncoder ? OH_VideoEncoder_PushInputBuffer(codec_, buf.idx) :
511                                         OH_VideoDecoder_PushInputBuffer(codec_, buf.idx);
512     if (err != AV_ERR_OK) {
513         TLOGE("PushInputBuffer failed");
514         return false;
515     }
516     CostRecorder::Instance().Update(begin,
517         opt_.isEncoder ? "OH_VideoEncoder_PushInputBuffer" : "OH_VideoDecoder_PushInputBuffer");
518     return true;
519 }
520 
ReturnOutput(uint32_t idx)521 bool TesterCapiOld::ReturnOutput(uint32_t idx)
522 {
523     OH_AVErrCode err;
524     string apiName;
525     auto begin = std::chrono::steady_clock::now();
526     if (opt_.isEncoder) {
527         err = OH_VideoEncoder_FreeOutputData(codec_, idx);
528         apiName = "OH_VideoEncoder_FreeOutputData";
529     } else {
530         if (opt_.isBufferMode) {
531             err = OH_VideoDecoder_FreeOutputData(codec_, idx);
532             apiName = "OH_VideoDecoder_FreeOutputData";
533         } else {
534             err = OH_VideoDecoder_RenderOutputData(codec_, idx);
535             apiName = "OH_VideoDecoder_RenderOutputData";
536         }
537     }
538     if (err != AV_ERR_OK) {
539         TLOGE("%s failed", apiName.c_str());
540         return false;
541     }
542     CostRecorder::Instance().Update(begin, apiName);
543     return true;
544 }
545 
ReturnOutput(uint32_t idx)546 bool TesterCapiNew::ReturnOutput(uint32_t idx)
547 {
548     OH_AVErrCode err;
549     string apiName;
550     auto begin = std::chrono::steady_clock::now();
551     if (opt_.isEncoder) {
552         err = OH_VideoEncoder_FreeOutputBuffer(codec_, idx);
553         apiName = "OH_VideoEncoder_FreeOutputBuffer";
554     } else {
555         if (opt_.isBufferMode) {
556             err = OH_VideoDecoder_FreeOutputBuffer(codec_, idx);
557             apiName = "OH_VideoDecoder_FreeOutputBuffer";
558         } else {
559             err = OH_VideoDecoder_RenderOutputBuffer(codec_, idx);
560             apiName = "OH_VideoDecoder_RenderOutputBuffer";
561         }
562     }
563     if (err != AV_ERR_OK) {
564         TLOGE("%s failed", apiName.c_str());
565         return false;
566     }
567     CostRecorder::Instance().Update(begin, apiName);
568     return true;
569 }
570 
SetOutputSurface(sptr<Surface> & surface)571 bool TesterCapi::SetOutputSurface(sptr<Surface>& surface)
572 {
573     OHNativeWindow *window = CreateNativeWindowFromSurface(&surface);
574     if (window == nullptr) {
575         TLOGE("CreateNativeWindowFromSurface failed");
576         return false;
577     }
578     auto begin = std::chrono::steady_clock::now();
579     OH_AVErrCode err = OH_VideoDecoder_SetSurface(codec_, window);
580     if (err != AV_ERR_OK) {
581         TLOGE("OH_VideoDecoder_SetSurface failed");
582         return false;
583     }
584     CostRecorder::Instance().Update(begin, "OH_VideoDecoder_SetSurface");
585     return true;
586 }
587 
ConfigureDecoder()588 bool TesterCapi::ConfigureDecoder()
589 {
590     auto fmt = shared_ptr<OH_AVFormat>(OH_AVFormat_Create(), OH_AVFormat_Destroy);
591     IF_TRUE_RETURN_VAL_WITH_MSG(fmt == nullptr, false, "OH_AVFormat_Create failed");
592     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_WIDTH, opt_.dispW);
593     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_HEIGHT, opt_.dispH);
594     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_PIXEL_FORMAT, static_cast<int32_t>(opt_.pixFmt));
595     OH_AVFormat_SetDoubleValue(fmt.get(), OH_MD_KEY_FRAME_RATE, opt_.frameRate);
596     OH_AVFormat_SetIntValue(fmt.get(), OH_MD_KEY_ROTATION, opt_.rotation);
597 
598     auto begin = std::chrono::steady_clock::now();
599     OH_AVErrCode ret = OH_VideoDecoder_Configure(codec_, fmt.get());
600     if (ret != AV_ERR_OK) {
601         TLOGE("OH_VideoDecoder_Configure failed");
602         return false;
603     }
604     CostRecorder::Instance().Update(begin, "OH_VideoDecoder_Configure");
605     return true;
606 }
607 }