• 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_codecbase.h"
17 #include "avcodec_errors.h"
18 #include "type_converter.h"
19 #include "hcodec_log.h"
20 #include "hcodec_utils.h"
21 #include "hcodec_api.h"
22 
23 namespace OHOS::MediaAVCodec {
24 using namespace std;
25 
OnError(AVCodecErrorType errorType,int32_t errorCode)26 void TesterCodecBase::CallBack::OnError(AVCodecErrorType errorType, int32_t errorCode)
27 {
28     TLOGI(">>");
29 }
30 
OnOutputFormatChanged(const Format & format)31 void TesterCodecBase::CallBack::OnOutputFormatChanged(const Format &format)
32 {
33     TLOGI(">>");
34 }
35 
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)36 void TesterCodecBase::CallBack::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
37 {
38     lock_guard<mutex> lk(tester_->inputMtx_);
39     tester_->inputList_.emplace_back(index, buffer);
40     tester_->inputCond_.notify_all();
41 }
42 
OnOutputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)43 void TesterCodecBase::CallBack::OnOutputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
44 {
45     if (!(buffer->flag_ & AVCODEC_BUFFER_FLAG_EOS)) {
46         auto metaStr = StringifyMeta(buffer->meta_);
47         TLOGI("%s", metaStr.c_str());
48     }
49     tester_->AfterGotOutput(OH_AVCodecBufferAttr {
50         .pts = buffer->pts_,
51         .size = buffer->memory_ ? buffer->memory_->GetSize() : 0,
52         .flags = buffer->flag_,
53     });
54     lock_guard<mutex> lk(tester_->outputMtx_);
55     tester_->outputList_.emplace_back(index, buffer);
56     tester_->outputCond_.notify_all();
57 }
58 
Create()59 bool TesterCodecBase::Create()
60 {
61     string mime = GetCodecMime(opt_.protocol);
62     string name = GetCodecName(opt_.isEncoder, mime);
63     auto begin = std::chrono::steady_clock::now();
64     CreateHCodecByName(name, codec_);
65     if (codec_ == nullptr) {
66         TLOGE("Create failed");
67         return false;
68     }
69     Media::Meta meta{};
70     int32_t err = codec_->Init(meta);
71     if (err != AVCS_ERR_OK) {
72         TLOGE("Init failed");
73         return false;
74     }
75     CostRecorder::Instance().Update(begin, "Create");
76     return true;
77 }
78 
SetCallback()79 bool TesterCodecBase::SetCallback()
80 {
81     shared_ptr<CallBack> cb = make_shared<CallBack>(this);
82     auto begin = std::chrono::steady_clock::now();
83     int32_t err = codec_->SetCallback(cb);
84     if (err != AVCS_ERR_OK) {
85         TLOGE("SetCallback failed");
86         return false;
87     }
88     CostRecorder::Instance().Update(begin, "SetCallback");
89     return true;
90 }
91 
Start()92 bool TesterCodecBase::Start()
93 {
94     auto begin = std::chrono::steady_clock::now();
95     int32_t err = codec_->Start();
96     if (err != AVCS_ERR_OK) {
97         TLOGE("Start failed");
98         return false;
99     }
100     CostRecorder::Instance().Update(begin, "Start");
101     return true;
102 }
103 
Stop()104 bool TesterCodecBase::Stop()
105 {
106     auto begin = std::chrono::steady_clock::now();
107     int32_t err = codec_->Stop();
108     if (err != AVCS_ERR_OK) {
109         TLOGE("Stop failed");
110         return false;
111     }
112     CostRecorder::Instance().Update(begin, "Stop");
113     return true;
114 }
115 
Release()116 bool TesterCodecBase::Release()
117 {
118     auto begin = std::chrono::steady_clock::now();
119     int32_t err = codec_->Release();
120     if (err != AVCS_ERR_OK) {
121         TLOGE("Release failed");
122         return false;
123     }
124     CostRecorder::Instance().Update(begin, "Release");
125     return true;
126 }
127 
Flush()128 bool TesterCodecBase::Flush()
129 {
130     auto begin = std::chrono::steady_clock::now();
131     int32_t err = codec_->Flush();
132     if (err != AVCS_ERR_OK) {
133         TLOGE("Flush failed");
134         return false;
135     }
136     CostRecorder::Instance().Update(begin, "Flush");
137     return true;
138 }
139 
ClearAllBuffer()140 void TesterCodecBase::ClearAllBuffer()
141 {
142     {
143         lock_guard<mutex> lk(inputMtx_);
144         inputList_.clear();
145     }
146     {
147         lock_guard<mutex> lk(outputMtx_);
148         outputList_.clear();
149     }
150 }
151 
EnableHighPerf(Format & fmt) const152 void TesterCodecBase::EnableHighPerf(Format& fmt) const
153 {
154     if (opt_.isHighPerfMode) {
155         fmt.PutIntValue("frame_rate_adaptive_mode", 1);
156     }
157 }
158 
ConfigureEncoder()159 bool TesterCodecBase::ConfigureEncoder()
160 {
161     Format fmt;
162     fmt.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, opt_.dispW);
163     fmt.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, opt_.dispH);
164     fmt.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast<int32_t>(opt_.pixFmt));
165     fmt.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, opt_.frameRate);
166     if (opt_.rangeFlag.has_value()) {
167         fmt.PutIntValue(MediaDescriptionKey::MD_KEY_RANGE_FLAG, opt_.rangeFlag.value());
168     }
169     if (opt_.primary.has_value()) {
170         fmt.PutIntValue(MediaDescriptionKey::MD_KEY_COLOR_PRIMARIES, opt_.primary.value());
171     }
172     if (opt_.transfer.has_value()) {
173         fmt.PutIntValue(MediaDescriptionKey::MD_KEY_TRANSFER_CHARACTERISTICS, opt_.transfer.value());
174     }
175     if (opt_.matrix.has_value()) {
176         fmt.PutIntValue(MediaDescriptionKey::MD_KEY_MATRIX_COEFFICIENTS, opt_.matrix.value());
177     }
178     if (opt_.iFrameInterval.has_value()) {
179         fmt.PutIntValue(MediaDescriptionKey::MD_KEY_I_FRAME_INTERVAL, opt_.iFrameInterval.value());
180     }
181     if (opt_.profile.has_value()) {
182         fmt.PutIntValue(MediaDescriptionKey::MD_KEY_PROFILE, opt_.profile.value());
183     }
184     if (opt_.rateMode.has_value()) {
185         fmt.PutIntValue(MediaDescriptionKey::MD_KEY_VIDEO_ENCODE_BITRATE_MODE, opt_.rateMode.value());
186     }
187     if (opt_.bitRate.has_value()) {
188         fmt.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, opt_.bitRate.value());
189     }
190     if (opt_.quality.has_value()) {
191         fmt.PutIntValue(MediaDescriptionKey::MD_KEY_QUALITY, opt_.quality.value());
192     }
193     if (opt_.sqrFactor.has_value()) {
194         fmt.PutIntValue(MediaDescriptionKey::MD_KEY_VIDEO_ENCODER_SQR_FACTOR, opt_.sqrFactor.value());
195     }
196     if (opt_.maxBitrate.has_value()) {
197         fmt.PutLongValue(MediaDescriptionKey::MD_KEY_VIDEO_ENCODER_MAX_BITRATE, opt_.maxBitrate.value());
198     }
199     if (opt_.layerCnt.has_value()) {
200         fmt.PutIntValue(OHOS::Media::Tag::VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY, true);
201         int32_t temporalGopSize = 0;
202         switch (opt_.layerCnt.value()) {
203             case 2: // 2: temporal layerCnt
204                 temporalGopSize = 2; // 2: temporalGopSize
205                 break;
206             case 3: // 3: temporal layerCnt
207                 temporalGopSize = 4; // 4: temporalGopSize
208                 break;
209             default:
210                 break;
211         }
212         fmt.PutIntValue(OHOS::Media::Tag::VIDEO_ENCODER_TEMPORAL_GOP_SIZE, temporalGopSize);
213         fmt.PutIntValue(OHOS::Media::Tag::VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE, 2); // 2: gop mode
214     }
215     EnableHighPerf(fmt);
216     if (opt_.qpRange.has_value()) {
217         fmt.PutIntValue(OHOS::Media::Tag::VIDEO_ENCODER_QP_MIN, opt_.qpRange->qpMin);
218         fmt.PutIntValue(OHOS::Media::Tag::VIDEO_ENCODER_QP_MAX, opt_.qpRange->qpMax);
219     }
220     if (opt_.repeatAfter.has_value()) {
221         fmt.PutIntValue(OHOS::Media::Tag::VIDEO_ENCODER_REPEAT_PREVIOUS_FRAME_AFTER, opt_.repeatAfter.value());
222     }
223     if (opt_.repeatMaxCnt.has_value()) {
224         fmt.PutIntValue(OHOS::Media::Tag::VIDEO_ENCODER_REPEAT_PREVIOUS_MAX_COUNT, opt_.repeatMaxCnt.value());
225     }
226     if (!opt_.isBufferMode && !opt_.perFrameParamsMap.empty()) {
227         fmt.PutIntValue(OHOS::Media::Tag::VIDEO_ENCODER_ENABLE_SURFACE_INPUT_CALLBACK, 1);
228         opt_.enableInputCb = true;
229     }
230     if (opt_.ltrFrameCount > 0) {
231         fmt.PutIntValue(OHOS::Media::Tag::VIDEO_ENCODER_LTR_FRAME_COUNT, opt_.ltrFrameCount);
232     }
233     if (opt_.paramsFeedback == 1) {
234         fmt.PutIntValue(OHOS::Media::Tag::VIDEO_ENCODER_ENABLE_PARAMS_FEEDBACK, opt_.paramsFeedback);
235     }
236     auto begin = std::chrono::steady_clock::now();
237     int32_t err = codec_->Configure(fmt);
238     if (err != AVCS_ERR_OK) {
239         TLOGE("Configure failed");
240         return false;
241     }
242     CostRecorder::Instance().Update(begin, "Configure");
243 
244     if (opt_.waterMark.isSet) {
245         shared_ptr<AVBuffer> buffer = CreateWaterMarkBuffer();
246         err = codec_->SetCustomBuffer(buffer);
247         if (err != AVCS_ERR_OK) {
248             TLOGE("SetCustomBuffer failed");
249             return false;
250         }
251     }
252     return true;
253 }
254 
SetEncoderParameter(const SetParameterParams & param)255 bool TesterCodecBase::SetEncoderParameter(const SetParameterParams& param)
256 {
257     Format fmt;
258     if (param.bitRate.has_value()) {
259         fmt.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, param.bitRate.value());
260     }
261     if (param.frameRate.has_value()) {
262         fmt.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, param.frameRate.value());
263     }
264     if (param.qpRange.has_value()) {
265         fmt.PutIntValue(OHOS::Media::Tag::VIDEO_ENCODER_QP_MIN, static_cast<int32_t>(param.qpRange->qpMin));
266         fmt.PutIntValue(OHOS::Media::Tag::VIDEO_ENCODER_QP_MAX, static_cast<int32_t>(param.qpRange->qpMax));
267     }
268     if (opt_.scaleMode.has_value()) {
269         fmt.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, static_cast<int32_t>(opt_.scaleMode.value()));
270     }
271     int32_t err = codec_->SetParameter(fmt);
272     if (err != AVCS_ERR_OK) {
273         TLOGE("SetParameter failed");
274         return false;
275     }
276     return true;
277 }
278 
SetEncoderPerFrameParam(BufInfo & buf,const PerFrameParams & param)279 bool TesterCodecBase::SetEncoderPerFrameParam(BufInfo& buf, const PerFrameParams& param)
280 {
281     if (buf.avbuf == nullptr) {
282         return false;
283     }
284     shared_ptr<Media::Meta> meta = buf.avbuf->meta_;
285     if (meta == nullptr) {
286         return false;
287     }
288     if (param.requestIdr.has_value()) {
289         meta->SetData(OHOS::Media::Tag::VIDEO_REQUEST_I_FRAME, param.requestIdr.value());
290     }
291     if (param.qpRange.has_value()) {
292         meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_QP_MIN, static_cast<int32_t>(param.qpRange->qpMin));
293         meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_QP_MAX, static_cast<int32_t>(param.qpRange->qpMax));
294     }
295     if (param.ltrParam.has_value()) {
296         meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_PER_FRAME_MARK_LTR,
297             static_cast<bool>(param.ltrParam->markAsLTR));
298         if (param.ltrParam->useLTR > 0) {
299             meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_PER_FRAME_USE_LTR,
300                 static_cast<int32_t>(param.ltrParam->useLTRPoc));
301         }
302     }
303     if (param.discard.has_value()) {
304         meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_PER_FRAME_DISCARD, param.discard.value());
305     }
306     if (param.ebrParam.has_value()) {
307         meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_QP_MIN, static_cast<int32_t>(param.ebrParam->minQp));
308         meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_QP_MAX, static_cast<int32_t>(param.ebrParam->maxQp));
309         meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_QP_START, static_cast<int32_t>(param.ebrParam->startQp));
310         meta->SetData(OHOS::Media::Tag::VIDEO_PER_FRAME_IS_SKIP, static_cast<bool>(param.ebrParam->isSkip));
311     }
312     return true;
313 }
314 
CreateInputSurface()315 sptr<Surface> TesterCodecBase::CreateInputSurface()
316 {
317     auto begin = std::chrono::steady_clock::now();
318     sptr<Surface> ret = codec_->CreateInputSurface();
319     if (ret == nullptr) {
320         TLOGE("CreateInputSurface failed");
321         return nullptr;
322     }
323     CostRecorder::Instance().Update(begin, "CreateInputSurface");
324     return ret;
325 }
326 
NotifyEos()327 bool TesterCodecBase::NotifyEos()
328 {
329     auto begin = std::chrono::steady_clock::now();
330     int32_t err = codec_->NotifyEos();
331     if (err != AVCS_ERR_OK) {
332         TLOGE("NotifyEos failed");
333         return false;
334     }
335     CostRecorder::Instance().Update(begin, "NotifyEos");
336     return true;
337 }
338 
RequestIDR()339 bool TesterCodecBase::RequestIDR()
340 {
341     auto begin = std::chrono::steady_clock::now();
342     int32_t err = codec_->SignalRequestIDRFrame();
343     if (err != AVCS_ERR_OK) {
344         TLOGE("RequestIDR failed");
345         return false;
346     }
347     CostRecorder::Instance().Update(begin, "SignalRequestIDRFrame");
348     return true;
349 }
350 
GetInputFormat()351 bool TesterCodecBase::GetInputFormat()
352 {
353     auto begin = std::chrono::steady_clock::now();
354     int32_t err = codec_->GetInputFormat(inputFmt_);
355     if (err != AVCS_ERR_OK) {
356         TLOGE("GetInputFormat failed");
357         return false;
358     }
359     CostRecorder::Instance().Update(begin, "GetInputFormat");
360     return true;
361 }
362 
GetOutputFormat()363 bool TesterCodecBase::GetOutputFormat()
364 {
365     Format fmt;
366     auto begin = std::chrono::steady_clock::now();
367     int32_t err = codec_->GetOutputFormat(fmt);
368     if (err != AVCS_ERR_OK) {
369         TLOGE("GetOutputFormat failed");
370         return false;
371     }
372     CostRecorder::Instance().Update(begin, "GetOutputFormat");
373     return true;
374 }
375 
GetInputStride()376 optional<uint32_t> TesterCodecBase::GetInputStride()
377 {
378     int32_t stride = 0;
379     if (inputFmt_.GetIntValue("stride", stride)) {
380         return stride;
381     } else {
382         return nullopt;
383     }
384 }
385 
WaitForInput(BufInfo & buf)386 bool TesterCodecBase::WaitForInput(BufInfo& buf)
387 {
388     {
389         unique_lock<mutex> lk(inputMtx_);
390         if (opt_.timeout == -1) {
391             inputCond_.wait(lk, [this] {
392                 return !inputList_.empty();
393             });
394         } else {
395             bool ret = inputCond_.wait_for(lk, chrono::milliseconds(opt_.timeout), [this] {
396                 return !inputList_.empty();
397             });
398             if (!ret) {
399                 TLOGE("time out");
400                 return false;
401             }
402         }
403         std::tie(buf.idx, buf.avbuf) = inputList_.front();
404         inputList_.pop_front();
405     }
406     if (buf.avbuf == nullptr) {
407         TLOGE("null avbuffer");
408         return false;
409     }
410     if (opt_.enableInputCb) {
411         return true;
412     }
413     if (buf.avbuf->memory_ == nullptr) {
414         TLOGE("null memory in avbuffer");
415         return false;
416     }
417     buf.va = buf.avbuf->memory_->GetAddr();
418     buf.capacity = buf.avbuf->memory_->GetCapacity();
419     if (opt_.isEncoder && opt_.isBufferMode) {
420         sptr<SurfaceBuffer> surfaceBuffer = buf.avbuf->memory_->GetSurfaceBuffer();
421         if (!SurfaceBufferToBufferInfo(buf, surfaceBuffer)) {
422             return false;
423         }
424     }
425     return true;
426 }
427 
ReturnInput(const BufInfo & buf)428 bool TesterCodecBase::ReturnInput(const BufInfo& buf)
429 {
430     if (!opt_.enableInputCb) {
431         buf.avbuf->pts_ = buf.attr.pts;
432         buf.avbuf->flag_ = buf.attr.flags;
433         buf.avbuf->memory_->SetOffset(buf.attr.offset);
434         buf.avbuf->memory_->SetSize(buf.attr.size);
435     }
436 
437     auto begin = std::chrono::steady_clock::now();
438     int32_t err = codec_->QueueInputBuffer(buf.idx);
439     if (err != AVCS_ERR_OK) {
440         TLOGE("QueueInputBuffer failed");
441         return false;
442     }
443     CostRecorder::Instance().Update(begin, "QueueInputBuffer");
444     return true;
445 }
446 
WaitForOutput(BufInfo & buf)447 bool TesterCodecBase::WaitForOutput(BufInfo& buf)
448 {
449     {
450         unique_lock<mutex> lk(outputMtx_);
451         if (opt_.timeout == -1) {
452             outputCond_.wait(lk, [this] {
453                 return !outputList_.empty();
454             });
455         } else {
456             bool waitRes = outputCond_.wait_for(lk, chrono::milliseconds(opt_.timeout), [this] {
457                 return !outputList_.empty();
458             });
459             if (!waitRes) {
460                 TLOGE("time out");
461                 return false;
462             }
463         }
464         std::tie(buf.idx, buf.avbuf) = outputList_.front();
465         outputList_.pop_front();
466     }
467     if (buf.avbuf == nullptr) {
468         TLOGE("null avbuffer");
469         return false;
470     }
471     if (buf.avbuf->flag_ & AVCODEC_BUFFER_FLAG_EOS) {
472         TLOGI("output eos, quit loop");
473         return false;
474     }
475     buf.attr.pts = buf.avbuf->pts_;
476     if (buf.avbuf->memory_) {
477         buf.va = buf.avbuf->memory_->GetAddr();
478         buf.capacity = static_cast<size_t>(buf.avbuf->memory_->GetCapacity());
479         buf.attr.size = buf.avbuf->memory_->GetSize();
480     }
481     return true;
482 }
483 
ReturnOutput(uint32_t idx)484 bool TesterCodecBase::ReturnOutput(uint32_t idx)
485 {
486     int32_t ret;
487     string apiName;
488     auto begin = std::chrono::steady_clock::now();
489     if (opt_.isEncoder || opt_.isBufferMode) {
490         ret = codec_->ReleaseOutputBuffer(idx);
491         apiName = "ReleaseOutputBuffer";
492     } else {
493         ret = codec_->RenderOutputBuffer(idx);
494         apiName = "RenderOutputBuffer";
495     }
496     if (ret != AVCS_ERR_OK) {
497         TLOGE("%s failed", apiName.c_str());
498         return false;
499     }
500     CostRecorder::Instance().Update(begin, apiName);
501     return true;
502 }
503 
SetOutputSurface(sptr<Surface> & surface)504 bool TesterCodecBase::SetOutputSurface(sptr<Surface>& surface)
505 {
506     auto begin = std::chrono::steady_clock::now();
507     int32_t err = codec_->SetOutputSurface(surface);
508     if (err != AVCS_ERR_OK) {
509         TLOGE("SetOutputSurface failed");
510         return false;
511     }
512     CostRecorder::Instance().Update(begin, "SetOutputSurface");
513     return true;
514 }
515 
ConfigureDecoder()516 bool TesterCodecBase::ConfigureDecoder()
517 {
518     Format fmt;
519     fmt.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, opt_.dispW);
520     fmt.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, opt_.dispH);
521     fmt.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast<int32_t>(opt_.pixFmt));
522     fmt.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, opt_.frameRate);
523     fmt.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, opt_.rotation);
524     EnableHighPerf(fmt);
525     if (opt_.scaleMode.has_value()) {
526         fmt.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, static_cast<int32_t>(opt_.scaleMode.value()));
527     }
528     if (opt_.isVrrEnable.has_value()) {
529         fmt.PutIntValue(OHOS::Media::Tag::VIDEO_DECODER_OUTPUT_ENABLE_VRR, opt_.isVrrEnable.value());
530     }
531     auto begin = std::chrono::steady_clock::now();
532     int32_t err = codec_->Configure(fmt);
533     if (err != AVCS_ERR_OK) {
534         TLOGE("Configure failed");
535         return false;
536     }
537     CostRecorder::Instance().Update(begin, "Configure");
538     return true;
539 }
540 }