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 "hcodec_log.h"
19 #include "hcodec_api.h"
20
21 using namespace std;
22 using namespace OHOS::MediaAVCodec;
23
OnError(AVCodecErrorType errorType,int32_t errorCode)24 void TesterCodecBase::CallBack::OnError(AVCodecErrorType errorType, int32_t errorCode)
25 {
26 LOGI(">>");
27 }
28
OnOutputFormatChanged(const Format & format)29 void TesterCodecBase::CallBack::OnOutputFormatChanged(const Format &format)
30 {
31 LOGI(">>");
32 }
33
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVSharedMemory> buffer)34 void TesterCodecBase::CallBack::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
35 {
36 lock_guard<mutex> lk(tester_->inputMtx_);
37 tester_->inputList_.emplace_back(index, buffer);
38 tester_->inputCond_.notify_all();
39 }
40
OnOutputBufferAvailable(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag,std::shared_ptr<AVSharedMemory> buffer)41 void TesterCodecBase::CallBack::OnOutputBufferAvailable(
42 uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag, std::shared_ptr<AVSharedMemory> buffer)
43 {
44 lock_guard<mutex> lk(tester_->outputMtx_);
45 tester_->outputList_.emplace_back(index, info, flag, buffer);
46 tester_->outputCond_.notify_all();
47 }
48
Create()49 bool TesterCodecBase::Create()
50 {
51 string name = GetCodecName(opt_.isEncoder, (opt_.protocol == H264) ? "video/avc" : "video/hevc");
52 auto begin = std::chrono::steady_clock::now();
53 CreateHCodecByName(name, codec_);
54 if (codec_ == nullptr) {
55 LOGE("Create failed");
56 return false;
57 }
58 CostRecorder::Instance().Update(begin, "Create");
59 return true;
60 }
61
SetCallback()62 bool TesterCodecBase::SetCallback()
63 {
64 shared_ptr<CallBack> cb = make_shared<CallBack>(this);
65 auto begin = std::chrono::steady_clock::now();
66 int32_t err = codec_->SetCallback(cb);
67 if (err != AVCS_ERR_OK) {
68 LOGE("SetCallback failed");
69 return false;
70 }
71 CostRecorder::Instance().Update(begin, "SetCallback");
72 return true;
73 }
74
Start()75 bool TesterCodecBase::Start()
76 {
77 auto begin = std::chrono::steady_clock::now();
78 int32_t err = codec_->Start();
79 if (err != AVCS_ERR_OK) {
80 LOGE("Start failed");
81 return false;
82 }
83 CostRecorder::Instance().Update(begin, "Start");
84 return true;
85 }
86
Stop()87 bool TesterCodecBase::Stop()
88 {
89 auto begin = std::chrono::steady_clock::now();
90 int32_t err = codec_->Stop();
91 if (err != AVCS_ERR_OK) {
92 LOGE("Stop failed");
93 return false;
94 }
95 CostRecorder::Instance().Update(begin, "Stop");
96 return true;
97 }
98
Release()99 bool TesterCodecBase::Release()
100 {
101 auto begin = std::chrono::steady_clock::now();
102 int32_t err = codec_->Release();
103 if (err != AVCS_ERR_OK) {
104 LOGE("Release failed");
105 return false;
106 }
107 CostRecorder::Instance().Update(begin, "Release");
108 return true;
109 }
110
Flush()111 bool TesterCodecBase::Flush()
112 {
113 auto begin = std::chrono::steady_clock::now();
114 int32_t err = codec_->Flush();
115 if (err != AVCS_ERR_OK) {
116 LOGE("Flush failed");
117 return false;
118 }
119 CostRecorder::Instance().Update(begin, "Flush");
120 return true;
121 }
122
ClearAllBuffer()123 void TesterCodecBase::ClearAllBuffer()
124 {
125 {
126 lock_guard<mutex> lk(inputMtx_);
127 inputList_.clear();
128 }
129 {
130 lock_guard<mutex> lk(outputMtx_);
131 outputList_.clear();
132 }
133 }
134
ConfigureEncoder()135 bool TesterCodecBase::ConfigureEncoder()
136 {
137 Format fmt;
138 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, opt_.dispW);
139 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, opt_.dispH);
140 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, opt_.pixFmt);
141 fmt.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, opt_.frameRate);
142
143 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_RANGE_FLAG, opt_.rangeFlag);
144 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_COLOR_PRIMARIES, opt_.primary);
145 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_TRANSFER_CHARACTERISTICS, opt_.transfer);
146 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_MATRIX_COEFFICIENTS, opt_.matrix);
147
148 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_I_FRAME_INTERVAL, opt_.iFrameInterval);
149 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_PROFILE, opt_.profile);
150 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_VIDEO_ENCODE_BITRATE_MODE, opt_.rateMode);
151 fmt.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, opt_.bitRate);
152 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_QUALITY, opt_.quality);
153
154 auto begin = std::chrono::steady_clock::now();
155 int32_t err = codec_->Configure(fmt);
156 if (err != AVCS_ERR_OK) {
157 LOGE("Configure failed");
158 return false;
159 }
160 CostRecorder::Instance().Update(begin, "Configure");
161 return true;
162 }
163
CreateInputSurface()164 bool TesterCodecBase::CreateInputSurface()
165 {
166 auto begin = std::chrono::steady_clock::now();
167 surface_ = codec_->CreateInputSurface();
168 if (surface_ == nullptr) {
169 LOGE("CreateInputSurface failed");
170 return false;
171 }
172 CostRecorder::Instance().Update(begin, "CreateInputSurface");
173 return true;
174 }
175
NotifyEos()176 bool TesterCodecBase::NotifyEos()
177 {
178 auto begin = std::chrono::steady_clock::now();
179 int32_t err = codec_->NotifyEos();
180 if (err != AVCS_ERR_OK) {
181 LOGE("NotifyEos failed");
182 return false;
183 }
184 CostRecorder::Instance().Update(begin, "NotifyEos");
185 return true;
186 }
187
RequestIDR()188 bool TesterCodecBase::RequestIDR()
189 {
190 auto begin = std::chrono::steady_clock::now();
191 int32_t err = codec_->SignalRequestIDRFrame();
192 if (err != AVCS_ERR_OK) {
193 LOGE("RequestIDR failed");
194 return false;
195 }
196 CostRecorder::Instance().Update(begin, "SignalRequestIDRFrame");
197 return true;
198 }
199
GetInputFormat()200 bool TesterCodecBase::GetInputFormat()
201 {
202 auto begin = std::chrono::steady_clock::now();
203 int32_t err = codec_->GetInputFormat(inputFmt_);
204 if (err != AVCS_ERR_OK) {
205 LOGE("GetInputFormat failed");
206 return false;
207 }
208 CostRecorder::Instance().Update(begin, "GetInputFormat");
209 return true;
210 }
211
GetOutputFormat()212 bool TesterCodecBase::GetOutputFormat()
213 {
214 Format fmt;
215 auto begin = std::chrono::steady_clock::now();
216 int32_t err = codec_->GetOutputFormat(fmt);
217 if (err != AVCS_ERR_OK) {
218 LOGE("GetOutputFormat failed");
219 return false;
220 }
221 CostRecorder::Instance().Update(begin, "GetOutputFormat");
222 return true;
223 }
224
GetInputStride()225 optional<uint32_t> TesterCodecBase::GetInputStride()
226 {
227 int32_t stride = 0;
228 if (inputFmt_.GetIntValue("stride", stride)) {
229 return stride;
230 } else {
231 return nullopt;
232 }
233 }
234
GetInputIndex(Span & span)235 std::optional<uint32_t> TesterCodecBase::GetInputIndex(Span& span)
236 {
237 uint32_t inputIdx;
238 shared_ptr<AVSharedMemory> frame;
239 {
240 unique_lock<mutex> lk(inputMtx_);
241 if (opt_.timeout == -1) {
242 inputCond_.wait(lk, [this] {
243 return !inputList_.empty();
244 });
245 } else {
246 bool ret = inputCond_.wait_for(lk, chrono::milliseconds(opt_.timeout), [this] {
247 return !inputList_.empty();
248 });
249 if (!ret) {
250 LOGE("Input wait time out");
251 return nullopt;
252 }
253 }
254 std::tie(inputIdx, frame) = inputList_.front();
255 inputList_.pop_front();
256 }
257 if (frame == nullptr) {
258 LOGE("null AVSharedMemory");
259 return nullopt;
260 }
261 char *dstVa = reinterpret_cast<char *>(frame->GetBase());
262 int size = frame->GetSize();
263 if (dstVa == nullptr || size <= 0) {
264 LOGE("invalid va or size");
265 return nullopt;
266 }
267 span.va = dstVa;
268 span.capacity = static_cast<size_t>(size);
269 return inputIdx;
270 }
271
QueueInput(uint32_t idx,OH_AVCodecBufferAttr attr)272 bool TesterCodecBase::QueueInput(uint32_t idx, OH_AVCodecBufferAttr attr)
273 {
274 AVCodecBufferInfo info {
275 .presentationTimeUs = attr.pts,
276 .size = attr.size,
277 .offset = attr.offset,
278 };
279 AVCodecBufferFlag flag = static_cast<AVCodecBufferFlag>(attr.flags);
280 auto begin = std::chrono::steady_clock::now();
281 int32_t err = codec_->QueueInputBuffer(idx, info, flag);
282 if (err != AVCS_ERR_OK) {
283 LOGE("QueueInputBuffer failed");
284 return false;
285 }
286 CostRecorder::Instance().Update(begin, "QueueInputBuffer");
287 return true;
288 }
289
GetOutputIndex()290 std::optional<uint32_t> TesterCodecBase::GetOutputIndex()
291 {
292 uint32_t outIdx;
293 AVCodecBufferInfo info;
294 AVCodecBufferFlag flag;
295 {
296 unique_lock<mutex> lk(outputMtx_);
297 if (opt_.timeout == -1) {
298 outputCond_.wait(lk, [this] {
299 return !outputList_.empty();
300 });
301 } else {
302 bool waitRes = outputCond_.wait_for(lk, chrono::milliseconds(opt_.timeout), [this] {
303 return !outputList_.empty();
304 });
305 if (!waitRes) {
306 LOGE("time out");
307 return nullopt;
308 }
309 }
310 std::tie(outIdx, info, flag, std::ignore) = outputList_.front();
311 outputList_.pop_front();
312 }
313 if (flag & AVCODEC_BUFFER_FLAG_EOS) {
314 LOGI("output eos, quit loop");
315 return nullopt;
316 }
317 return outIdx;
318 }
319
ReturnOutput(uint32_t idx)320 bool TesterCodecBase::ReturnOutput(uint32_t idx)
321 {
322 int32_t ret;
323 string apiName;
324 auto begin = std::chrono::steady_clock::now();
325 if (opt_.isEncoder || opt_.isBufferMode) {
326 ret = codec_->ReleaseOutputBuffer(idx);
327 apiName = "ReleaseOutputBuffer";
328 } else {
329 ret = codec_->RenderOutputBuffer(idx);
330 apiName = "RenderOutputBuffer";
331 }
332 if (ret != AVCS_ERR_OK) {
333 LOGE("%{public}s failed", apiName.c_str());
334 return false;
335 }
336 CostRecorder::Instance().Update(begin, apiName);
337 return true;
338 }
339
SetOutputSurface(sptr<Surface> & surface)340 bool TesterCodecBase::SetOutputSurface(sptr<Surface>& surface)
341 {
342 auto begin = std::chrono::steady_clock::now();
343 int32_t err = codec_->SetOutputSurface(surface);
344 if (err != AVCS_ERR_OK) {
345 LOGE("SetOutputSurface failed");
346 return false;
347 }
348 CostRecorder::Instance().Update(begin, "SetOutputSurface");
349 return true;
350 }
351
ConfigureDecoder()352 bool TesterCodecBase::ConfigureDecoder()
353 {
354 Format fmt;
355 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, opt_.dispW);
356 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, opt_.dispH);
357 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, opt_.pixFmt);
358 fmt.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, opt_.frameRate);
359 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, opt_.rotation);
360
361 auto begin = std::chrono::steady_clock::now();
362 int32_t err = codec_->Configure(fmt);
363 if (err != AVCS_ERR_OK) {
364 LOGE("Configure failed");
365 return false;
366 }
367 CostRecorder::Instance().Update(begin, "Configure");
368 return true;
369 }