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 }