• 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 "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 }