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_common.h"
17 #include "hcodec_api.h"
18 #include "hcodec_log.h"
19 #include "hcodec_utils.h"
20 #include "native_avcodec_base.h"
21 #include "tester_capi.h"
22 #include "tester_codecbase.h"
23 #include "type_converter.h"
24 #include "v1_0/buffer_handle_meta_key_type.h"
25 #include "v1_0/cm_color_space.h"
26 #include "v1_0/hdr_static_metadata.h"
27
28 namespace OHOS::MediaAVCodec {
29 using namespace std;
30 using namespace Media;
31 using namespace OHOS::HDI::Display::Graphic::Common::V1_0;
32
33 std::mutex TesterCommon::vividMtx_;
34 std::unordered_map<int64_t, std::vector<uint8_t>> TesterCommon::vividMap_;
35
GetNowUs()36 int64_t TesterCommon::GetNowUs()
37 {
38 auto now = chrono::steady_clock::now();
39 return chrono::duration_cast<chrono::microseconds>(now.time_since_epoch()).count();
40 }
41
Create(const CommandOpt & opt)42 shared_ptr<TesterCommon> TesterCommon::Create(const CommandOpt& opt)
43 {
44 switch (opt.apiType) {
45 case ApiType::TEST_CODEC_BASE:
46 return make_shared<TesterCodecBase>(opt);
47 case ApiType::TEST_C_API_OLD:
48 return make_shared<TesterCapiOld>(opt);
49 case ApiType::TEST_C_API_NEW:
50 return make_shared<TesterCapiNew>(opt);
51 default:
52 return nullptr;
53 }
54 }
55
Run(const CommandOpt & opt)56 bool TesterCommon::Run(const CommandOpt& opt)
57 {
58 opt.Print();
59 if (!opt.isEncoder && opt.decThenEnc) {
60 return RunDecEnc(opt);
61 }
62 shared_ptr<TesterCommon> tester = Create(opt);
63 CostRecorder::Instance().Clear();
64 for (uint32_t i = 0; i < opt.repeatCnt; i++) {
65 TLOGI("i = %u", i);
66 bool ret = tester->RunOnce();
67 if (!ret) {
68 return false;
69 }
70 }
71 CostRecorder::Instance().Print();
72 return true;
73 }
74
RunDecEnc(const CommandOpt & decOpt)75 bool TesterCommon::RunDecEnc(const CommandOpt& decOpt)
76 {
77 {
78 lock_guard<mutex> lk(vividMtx_);
79 vividMap_.clear();
80 }
81 shared_ptr<TesterCommon> decoder = Create(decOpt);
82 CommandOpt encOpt = decOpt;
83 encOpt.isEncoder = true;
84 shared_ptr<TesterCommon> encoder = Create(encOpt);
85
86 bool ret = decoder->InitDemuxer();
87 IF_TRUE_RETURN_VAL(!ret, false);
88 ret = decoder->Create();
89 IF_TRUE_RETURN_VAL(!ret, false);
90 ret = decoder->SetCallback();
91 IF_TRUE_RETURN_VAL(!ret, false);
92 ret = decoder->ConfigureDecoder();
93 IF_TRUE_RETURN_VAL(!ret, false);
94
95 ret = encoder->Create();
96 IF_TRUE_RETURN_VAL(!ret, false);
97 ret = encoder->SetCallback();
98 IF_TRUE_RETURN_VAL(!ret, false);
99 ret = encoder->ConfigureEncoder();
100 IF_TRUE_RETURN_VAL(!ret, false);
101
102 sptr<Surface> surface = encoder->CreateInputSurface();
103 IF_TRUE_RETURN_VAL(surface == nullptr, false);
104 ret = decoder->SetOutputSurface(surface);
105 IF_TRUE_RETURN_VAL(!ret, false);
106
107 ret = encoder->Start();
108 IF_TRUE_RETURN_VAL(!ret, false);
109 ret = decoder->Start();
110 IF_TRUE_RETURN_VAL(!ret, false);
111 thread decOutThread(&TesterCommon::OutputLoop, decoder.get());
112 thread encOutThread(&TesterCommon::OutputLoop, encoder.get());
113 decoder->DecoderInputLoop();
114 if (decOutThread.joinable()) {
115 decOutThread.join();
116 }
117 encoder->NotifyEos();
118 if (encOutThread.joinable()) {
119 encOutThread.join();
120 }
121 decoder->Release();
122 encoder->Release();
123 TLOGI("RunDecEnc succ");
124 return true;
125 }
126
RunOnce()127 bool TesterCommon::RunOnce()
128 {
129 return opt_.isEncoder ? RunEncoder() : RunDecoder();
130 }
131
BeforeQueueInput(OH_AVCodecBufferAttr & attr)132 void TesterCommon::BeforeQueueInput(OH_AVCodecBufferAttr& attr)
133 {
134 const char* codecStr = opt_.isEncoder ? "encoder" : "decoder";
135 int64_t now = GetNowUs();
136 attr.pts = now;
137 if (!opt_.isEncoder && opt_.decThenEnc) {
138 SaveVivid(attr.pts);
139 }
140 if (attr.flags & AVCODEC_BUFFER_FLAG_EOS) {
141 TLOGI("%s input: flags=0x%x (eos)", codecStr, attr.flags);
142 return;
143 }
144 if (attr.flags & AVCODEC_BUFFER_FLAG_CODEC_DATA) {
145 TLOGI("%s input: flags=0x%x, pts=%" PRId64 ", size=%d", codecStr, attr.flags, attr.pts, attr.size);
146 return;
147 }
148 TLOGI("%s input: flags=0x%x, pts=%" PRId64 ", size=%d", codecStr, attr.flags, attr.pts, attr.size);
149 if (firstInTime_ == 0) {
150 firstInTime_ = now;
151 }
152 inTotalCnt_++;
153 int64_t fromFirstInToNow = now - firstInTime_;
154 if (fromFirstInToNow != 0) {
155 inFps_ = inTotalCnt_ * US_TO_S / fromFirstInToNow;
156 }
157 }
158
AfterGotOutput(const OH_AVCodecBufferAttr & attr)159 void TesterCommon::AfterGotOutput(const OH_AVCodecBufferAttr& attr)
160 {
161 const char* codecStr = opt_.isEncoder ? "encoder" : "decoder";
162 int64_t now = GetNowUs();
163 if (attr.flags & AVCODEC_BUFFER_FLAG_EOS) {
164 TLOGI("%s output: flags=0x%x (eos)", codecStr, attr.flags);
165 return;
166 }
167 if (attr.flags & AVCODEC_BUFFER_FLAG_CODEC_DATA) {
168 TLOGI("%s output: flags=0x%x, pts=%" PRId64 ", size=%d", codecStr, attr.flags, attr.pts, attr.size);
169 return;
170 }
171 if (firstOutTime_ == 0) {
172 firstOutTime_ = now;
173 }
174 outTotalCnt_++;
175
176 int64_t fromInToOut = now - attr.pts;
177 totalCost_ += fromInToOut;
178 double oneFrameCostMs = fromInToOut / US_TO_MS;
179 double averageCostMs = totalCost_ / US_TO_MS / outTotalCnt_;
180
181 int64_t fromFirstOutToNow = now - firstOutTime_;
182 if (fromFirstOutToNow == 0) {
183 TLOGI("%s output: flags=0x%x, pts=%" PRId64 ", size=%d, cost %.2f ms, average %.2f ms",
184 codecStr, attr.flags, attr.pts, attr.size, oneFrameCostMs, averageCostMs);
185 } else {
186 double outFps = outTotalCnt_ * US_TO_S / fromFirstOutToNow;
187 TLOGI("%s output: flags=0x%x, pts=%" PRId64 ", size=%d, cost %.2f ms, average %.2f ms, "
188 "in fps %.2f, out fps %.2f",
189 codecStr, attr.flags, attr.pts, attr.size, oneFrameCostMs, averageCostMs, inFps_, outFps);
190 }
191 }
192
OutputLoop()193 void TesterCommon::OutputLoop()
194 {
195 while (true) {
196 BufInfo buf {};
197 if (!WaitForOutput(buf)) {
198 return;
199 }
200 if (opt_.isEncoder && opt_.decThenEnc) {
201 CheckVivid(buf);
202 }
203 ReturnOutput(buf.idx);
204 }
205 }
206
CheckVivid(const BufInfo & buf)207 void TesterCommon::CheckVivid(const BufInfo& buf)
208 {
209 vector<uint8_t> inVividSei;
210 {
211 lock_guard<mutex> lk(vividMtx_);
212 auto it = vividMap_.find(buf.attr.pts);
213 if (it == vividMap_.end()) {
214 return;
215 }
216 inVividSei = std::move(it->second);
217 vividMap_.erase(buf.attr.pts);
218 }
219 shared_ptr<StartCodeDetector> demuxer = StartCodeDetector::Create(opt_.protocol);
220 demuxer->SetSource(buf.va, buf.attr.size);
221 optional<Sample> sample = demuxer->PeekNextSample();
222 if (!sample.has_value()) {
223 TLOGI("--- output pts %" PRId64 " has no sample but input has vivid", buf.attr.pts);
224 return;
225 }
226 if (sample->vividSei.empty()) {
227 TLOGI("--- output pts %" PRId64 " has no vivid but input has vivid", buf.attr.pts);
228 return;
229 }
230 bool eq = std::equal(inVividSei.begin(), inVividSei.end(), sample->vividSei.begin());
231 if (eq) {
232 TLOGI("--- output pts %" PRId64 " has vivid and is same as input vivid", buf.attr.pts);
233 } else {
234 TLOGI("--- output pts %" PRId64 " has vivid but is different from input vivid", buf.attr.pts);
235 }
236 }
237
InnerFmtToDisplayFmt(VideoPixelFormat format,bool is10Bit)238 static std::optional<GraphicPixelFormat> InnerFmtToDisplayFmt(VideoPixelFormat format, bool is10Bit)
239 {
240 struct Fmt {
241 VideoPixelFormat videoFmt;
242 bool is10Bit;
243 GraphicPixelFormat graFmt;
244 };
245 vector<Fmt> TABLE = {
246 {VideoPixelFormat::YUVI420, false, GRAPHIC_PIXEL_FMT_YCBCR_420_P},
247 {VideoPixelFormat::NV12, false, GRAPHIC_PIXEL_FMT_YCBCR_420_SP},
248 {VideoPixelFormat::NV12, true, GRAPHIC_PIXEL_FMT_YCBCR_P010},
249 {VideoPixelFormat::NV21, false, GRAPHIC_PIXEL_FMT_YCRCB_420_SP},
250 {VideoPixelFormat::NV21, true, GRAPHIC_PIXEL_FMT_YCRCB_P010},
251 {VideoPixelFormat::RGBA, false, GRAPHIC_PIXEL_FMT_RGBA_8888},
252 {VideoPixelFormat::RGBA, true, GRAPHIC_PIXEL_FMT_RGBA_1010102},
253 {VideoPixelFormat::RGBA1010102, false, GRAPHIC_PIXEL_FMT_RGBA_1010102},
254 {VideoPixelFormat::RGBA1010102, true, GRAPHIC_PIXEL_FMT_RGBA_1010102},
255 };
256 auto it = find_if(TABLE.begin(), TABLE.end(), [format, is10Bit](const Fmt& p) {
257 return p.videoFmt == format && p.is10Bit == is10Bit;
258 });
259 if (it != TABLE.end()) {
260 return it->graFmt;
261 }
262 return nullopt;
263 }
264
RunEncoder()265 bool TesterCommon::RunEncoder()
266 {
267 ifs_ = ifstream(opt_.inputFile, ios::binary);
268 IF_TRUE_RETURN_VAL_WITH_MSG(!ifs_, false, "Failed to open file %s", opt_.inputFile.c_str());
269 if (!opt_.isBufferMode) {
270 is10Bit_ = (opt_.protocol == H265) && (opt_.profile == HEVC_PROFILE_MAIN_10);
271 optional<GraphicPixelFormat> displayFmt = InnerFmtToDisplayFmt(opt_.pixFmt, is10Bit_);
272 IF_TRUE_RETURN_VAL_WITH_MSG(!displayFmt, false, "invalid pixel format");
273 displayFmt_ = displayFmt.value();
274 }
275 w_ = opt_.dispW;
276 h_ = opt_.dispH;
277
278 bool ret = Create();
279 IF_TRUE_RETURN_VAL(!ret, false);
280 ret = SetCallback();
281 IF_TRUE_RETURN_VAL(!ret, false);
282 ret = ConfigureEncoder();
283 IF_TRUE_RETURN_VAL(!ret, false);
284 sptr<Surface> surface;
285 if (!opt_.isBufferMode) {
286 producerSurface_ = CreateInputSurface();
287 IF_TRUE_RETURN_VAL(producerSurface_ == nullptr, false);
288 }
289 ret = Start();
290 IF_TRUE_RETURN_VAL(!ret, false);
291 GetInputFormat();
292 GetOutputFormat();
293
294 thread th(&TesterCommon::OutputLoop, this);
295 EncoderInputLoop();
296 if (th.joinable()) {
297 th.join();
298 }
299 ret = Stop();
300 IF_TRUE_RETURN_VAL(!ret, false);
301 ret = Release();
302 IF_TRUE_RETURN_VAL(!ret, false);
303 return true;
304 }
305
UpdateMemberFromResourceParam(const ResourceParams & param)306 bool TesterCommon::UpdateMemberFromResourceParam(const ResourceParams& param)
307 {
308 ifstream ifs = ifstream(param.inputFile, ios::binary);
309 IF_TRUE_RETURN_VAL_WITH_MSG(!ifs, false, "Failed to open file %s", param.inputFile.c_str());
310 optional<GraphicPixelFormat> displayFmt = InnerFmtToDisplayFmt(param.pixFmt, is10Bit_);
311 IF_TRUE_RETURN_VAL_WITH_MSG(!displayFmt, false, "invalid pixel format");
312 ifs_ = std::move(ifs);
313 displayFmt_ = displayFmt.value();
314 w_ = param.dispW;
315 h_ = param.dispH;
316 return true;
317 }
318
EncoderInputLoop()319 void TesterCommon::EncoderInputLoop()
320 {
321 while (true) {
322 if (!opt_.isBufferMode && !opt_.resourceParamsMap.empty() &&
323 opt_.resourceParamsMap.begin()->first == currInputCnt_) {
324 UpdateMemberFromResourceParam(opt_.resourceParamsMap.begin()->second);
325 opt_.resourceParamsMap.erase(opt_.resourceParamsMap.begin());
326 }
327 BufInfo buf {};
328 bool ret = opt_.isBufferMode ? WaitForInput(buf) : WaitForInputSurfaceBuffer(buf);
329 if (!ret) {
330 continue;
331 }
332 buf.attr.size = ReadOneFrame(buf);
333 if (buf.attr.size == 0) {
334 buf.attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
335 BeforeQueueInput(buf.attr);
336 ret = opt_.isBufferMode ? ReturnInput(buf) : NotifyEos();
337 if (ret) {
338 TLOGI("queue eos succ, quit loop");
339 return;
340 } else {
341 TLOGW("queue eos failed");
342 continue;
343 }
344 }
345 if (!opt_.setParameterParamsMap.empty() && opt_.setParameterParamsMap.begin()->first == currInputCnt_) {
346 const SetParameterParams ¶m = opt_.setParameterParamsMap.begin()->second;
347 if (param.requestIdr.has_value()) {
348 RequestIDR();
349 }
350 SetEncoderParameter(param);
351 opt_.setParameterParamsMap.erase(opt_.setParameterParamsMap.begin());
352 }
353 if (opt_.isBufferMode && !opt_.perFrameParamsMap.empty() &&
354 opt_.perFrameParamsMap.begin()->first == currInputCnt_) {
355 SetEncoderPerFrameParam(buf, opt_.perFrameParamsMap.begin()->second);
356 opt_.perFrameParamsMap.erase(opt_.perFrameParamsMap.begin());
357 }
358 if (!opt_.isBufferMode && opt_.repeatAfter.has_value()) {
359 this_thread::sleep_for(std::chrono::milliseconds(rand() % 1000)); // 1000 ms
360 }
361 BeforeQueueInput(buf.attr);
362 ret = opt_.isBufferMode ? ReturnInput(buf) : ReturnInputSurfaceBuffer(buf);
363 if (!ret) {
364 continue;
365 }
366 if (opt_.enableInputCb) {
367 WaitForInput(buf);
368 if (!opt_.perFrameParamsMap.empty() && opt_.perFrameParamsMap.begin()->first == currInputCnt_) {
369 SetEncoderPerFrameParam(buf, opt_.perFrameParamsMap.begin()->second);
370 opt_.perFrameParamsMap.erase(opt_.perFrameParamsMap.begin());
371 }
372 ReturnInput(buf);
373 }
374 currInputCnt_++;
375 }
376 }
377
CreateWaterMarkBuffer()378 std::shared_ptr<AVBuffer> TesterCommon::CreateWaterMarkBuffer()
379 {
380 ifstream ifs = ifstream(opt_.waterMark.waterMarkFile.inputFile, ios::binary);
381 if (!ifs) {
382 TLOGE("Failed to open file %s", opt_.waterMark.waterMarkFile.inputFile.c_str());
383 return nullptr;
384 }
385 BufferRequestConfig cfg = {opt_.waterMark.waterMarkFile.dispW, opt_.waterMark.waterMarkFile.dispH,
386 32, GRAPHIC_PIXEL_FMT_RGBA_8888,
387 BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA, 0, };
388 std::shared_ptr<AVAllocator> avAllocator = AVAllocatorFactory::CreateSurfaceAllocator(cfg);
389 if (avAllocator == nullptr) {
390 TLOGE("CreateSurfaceAllocator failed");
391 return nullptr;
392 }
393 std::shared_ptr<AVBuffer> avBuffer = AVBuffer::CreateAVBuffer(avAllocator, 0);
394 if (avBuffer == nullptr) {
395 TLOGE("CreateAVBuffer failed");
396 return nullptr;
397 }
398 sptr<SurfaceBuffer> surfaceBuffer = avBuffer->memory_->GetSurfaceBuffer();
399 if (surfaceBuffer == nullptr) {
400 TLOGE("Create SurfaceBuffer failed");
401 return nullptr;
402 }
403 BufInfo buf;
404 SurfaceBufferToBufferInfo(buf, surfaceBuffer);
405 ReadOneFrameRGBA(ifs, buf);
406 avBuffer->meta_->SetData(OHOS::Media::Tag::VIDEO_ENCODER_ENABLE_WATERMARK, true);
407 avBuffer->meta_->SetData(OHOS::Media::Tag::VIDEO_COORDINATE_X, opt_.waterMark.dstX);
408 avBuffer->meta_->SetData(OHOS::Media::Tag::VIDEO_COORDINATE_Y, opt_.waterMark.dstY);
409 avBuffer->meta_->SetData(OHOS::Media::Tag::VIDEO_COORDINATE_W, opt_.waterMark.dstW);
410 avBuffer->meta_->SetData(OHOS::Media::Tag::VIDEO_COORDINATE_H, opt_.waterMark.dstH);
411 return avBuffer;
412 }
413
SurfaceBufferToBufferInfo(BufInfo & buf,sptr<SurfaceBuffer> surfaceBuffer)414 bool TesterCommon::SurfaceBufferToBufferInfo(BufInfo& buf, sptr<SurfaceBuffer> surfaceBuffer)
415 {
416 if (surfaceBuffer == nullptr) {
417 TLOGE("null surfaceBuffer");
418 return false;
419 }
420 buf.va = static_cast<uint8_t *>(surfaceBuffer->GetVirAddr());
421 buf.capacity = surfaceBuffer->GetSize();
422
423 buf.dispW = surfaceBuffer->GetWidth();
424 buf.dispH = surfaceBuffer->GetHeight();
425 buf.fmt = static_cast<GraphicPixelFormat>(surfaceBuffer->GetFormat());
426 buf.byteStride = surfaceBuffer->GetStride();
427 return true;
428 }
429
NativeBufferToBufferInfo(BufInfo & buf,OH_NativeBuffer * nativeBuffer)430 bool TesterCommon::NativeBufferToBufferInfo(BufInfo& buf, OH_NativeBuffer* nativeBuffer)
431 {
432 if (nativeBuffer == nullptr) {
433 TLOGE("null OH_NativeBuffer");
434 return false;
435 }
436 OH_NativeBuffer_Config cfg;
437 OH_NativeBuffer_GetConfig(nativeBuffer, &cfg);
438 buf.dispW = cfg.width;
439 buf.dispH = cfg.height;
440 buf.fmt = static_cast<GraphicPixelFormat>(cfg.format);
441 buf.byteStride = cfg.stride;
442 return true;
443 }
444
WaitForInputSurfaceBuffer(BufInfo & buf)445 bool TesterCommon::WaitForInputSurfaceBuffer(BufInfo& buf)
446 {
447 BufferRequestConfig cfg = {w_, h_, 32, displayFmt_,
448 BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA, 0, };
449 sptr<SurfaceBuffer> surfaceBuffer;
450 int32_t fence;
451 GSError err = producerSurface_->RequestBuffer(surfaceBuffer, fence, cfg);
452 if (err != GSERROR_OK) {
453 return false;
454 }
455 buf.surfaceBuf = surfaceBuffer;
456 return SurfaceBufferToBufferInfo(buf, surfaceBuffer);
457 }
458
SetStaticMetaData(BufInfo & buf)459 void TesterCommon::SetStaticMetaData(BufInfo& buf)
460 {
461 using namespace OHOS::HDI::Display::Graphic::Common::V1_0;
462 vector<uint8_t> vec(sizeof(HdrStaticMetadata));
463 HdrStaticMetadata* info = (HdrStaticMetadata*)vec.data();
464 float value1 = 0.00002;
465 float value2 = 0.0001;
466 float lightLevel = 1000.0;
467 info->smpte2086.displayPrimaryGreen.x = 8500 * value1; // 8500
468 info->smpte2086.displayPrimaryGreen.y = 39850 * value1; // 39850
469 info->smpte2086.displayPrimaryBlue.x = 6550 * value1; //6550
470 info->smpte2086.displayPrimaryBlue.y = 2300 * value1; // 2300
471 info->smpte2086.displayPrimaryRed.x = 35400 * value1; // 35400
472 info->smpte2086.displayPrimaryRed.y = 14600 * value1; // 14600
473 info->smpte2086.whitePoint.x = 15635 * value1; // 15635
474 info->smpte2086.whitePoint.y = 16450 * value1; // 16450
475 info->smpte2086.maxLuminance = 10000000 * value2; // 10000000
476 info->smpte2086.minLuminance = 50 * value2; // 50
477 info->cta861.maxContentLightLevel = lightLevel;
478 info->cta861.maxFrameAverageLightLevel = lightLevel;
479 buf.surfaceBuf->SetMetadata(ATTRKEY_HDR_STATIC_METADATA, vec);
480 }
481
SetDynamicMetaData(BufInfo & buf)482 void TesterCommon::SetDynamicMetaData(BufInfo& buf)
483 {
484 std::vector<uint8_t> HDR_VIVID_INPUT1 = {1, 47, 87, 30, 138, 187, 117, 240, 26, 190, 187, 29, 128, 0, 82,
485 142, 25, 152, 6, 100, 171, 42, 207, 235, 248, 67, 176, 235, 252, 16, 93,
486 242, 106, 132, 0, 10, 81, 199, 178, 80, 255, 217, 150, 101, 253, 149, 53,
487 212, 169, 127, 160, 0, 0};
488 buf.surfaceBuf->SetMetadata(ATTRKEY_HDR_DYNAMIC_METADATA, HDR_VIVID_INPUT1);
489 }
490
ReturnInputSurfaceBuffer(BufInfo & buf)491 bool TesterCommon::ReturnInputSurfaceBuffer(BufInfo& buf)
492 {
493 BufferFlushConfig flushConfig = {
494 .damage = {
495 .w = w_,
496 .h = h_,
497 },
498 .timestamp = buf.attr.pts,
499 };
500 if (is10Bit_) {
501 vector<uint8_t> vec(sizeof(CM_ColorSpaceInfo));
502 CM_ColorSpaceInfo* info = (CM_ColorSpaceInfo*)vec.data();
503 info->primaries = COLORPRIMARIES_BT2020;
504 info->transfunc = TRANSFUNC_HLG;
505 info->matrix = MATRIX_BT2020;
506 info->range = RANGE_LIMITED;
507 buf.surfaceBuf->SetMetadata(ATTRKEY_COLORSPACE_INFO, vec);
508 SetStaticMetaData(buf);
509 SetDynamicMetaData(buf);
510 }
511 GSError err = producerSurface_->FlushBuffer(buf.surfaceBuf, -1, flushConfig);
512 if (err != GSERROR_OK) {
513 TLOGE("FlushBuffer failed");
514 return false;
515 }
516 return true;
517 }
518
519 #define RETURN_ZERO_IF_EOS(expectedSize) \
520 do { \
521 if (src.gcount() != (expectedSize)) { \
522 TLOGI("no more data"); \
523 return 0; \
524 } \
525 } while (0)
526
ReadOneFrameYUV420P(std::ifstream & src,ImgBuf & dstImg)527 uint32_t TesterCommon::ReadOneFrameYUV420P(std::ifstream& src, ImgBuf& dstImg)
528 {
529 char* dst = reinterpret_cast<char*>(dstImg.va);
530 char* start = dst;
531 // copy Y
532 for (uint32_t i = 0; i < dstImg.dispH; i++) {
533 src.read(dst, dstImg.dispW);
534 RETURN_ZERO_IF_EOS(dstImg.dispW);
535 dst += dstImg.byteStride;
536 }
537 // copy U
538 for (uint32_t i = 0; i < dstImg.dispH / SAMPLE_RATIO; i++) {
539 src.read(dst, dstImg.dispW / SAMPLE_RATIO);
540 RETURN_ZERO_IF_EOS(dstImg.dispW / SAMPLE_RATIO);
541 dst += dstImg.byteStride / SAMPLE_RATIO;
542 }
543 // copy V
544 for (uint32_t i = 0; i < dstImg.dispH / SAMPLE_RATIO; i++) {
545 src.read(dst, dstImg.dispW / SAMPLE_RATIO);
546 RETURN_ZERO_IF_EOS(dstImg.dispW / SAMPLE_RATIO);
547 dst += dstImg.byteStride / SAMPLE_RATIO;
548 }
549 return dst - start;
550 }
551
ReadOneFrameYUV420SP(std::ifstream & src,ImgBuf & dstImg,uint8_t bytesPerPixel)552 uint32_t TesterCommon::ReadOneFrameYUV420SP(std::ifstream& src, ImgBuf& dstImg, uint8_t bytesPerPixel)
553 {
554 char* dst = reinterpret_cast<char*>(dstImg.va);
555 char* start = dst;
556 // copy Y
557 for (uint32_t i = 0; i < dstImg.dispH; i++) {
558 src.read(dst, dstImg.dispW * bytesPerPixel);
559 RETURN_ZERO_IF_EOS(dstImg.dispW * bytesPerPixel);
560 dst += dstImg.byteStride;
561 }
562 // copy UV
563 for (uint32_t i = 0; i < dstImg.dispH / SAMPLE_RATIO; i++) {
564 src.read(dst, dstImg.dispW * bytesPerPixel);
565 RETURN_ZERO_IF_EOS(dstImg.dispW * bytesPerPixel);
566 dst += dstImg.byteStride;
567 }
568 return dst - start;
569 }
570
ReadOneFrameRGBA(std::ifstream & src,ImgBuf & dstImg)571 uint32_t TesterCommon::ReadOneFrameRGBA(std::ifstream& src, ImgBuf& dstImg)
572 {
573 char* dst = reinterpret_cast<char*>(dstImg.va);
574 char* start = dst;
575 for (uint32_t i = 0; i < dstImg.dispH; i++) {
576 src.read(dst, dstImg.dispW * BYTES_PER_PIXEL_RBGA);
577 RETURN_ZERO_IF_EOS(dstImg.dispW * BYTES_PER_PIXEL_RBGA);
578 dst += dstImg.byteStride;
579 }
580 return dst - start;
581 }
582
ReadOneFrame(ImgBuf & dstImg)583 uint32_t TesterCommon::ReadOneFrame(ImgBuf& dstImg)
584 {
585 if (dstImg.va == nullptr) {
586 TLOGE("dst image has null va");
587 return 0;
588 }
589 if (dstImg.byteStride < dstImg.dispW) {
590 TLOGE("byteStride %u < dispW %u", dstImg.byteStride, dstImg.dispW);
591 return 0;
592 }
593 uint32_t sampleSize = 0;
594 switch (dstImg.fmt) {
595 case GRAPHIC_PIXEL_FMT_YCBCR_420_P:
596 case GRAPHIC_PIXEL_FMT_YCBCR_420_SP:
597 case GRAPHIC_PIXEL_FMT_YCRCB_420_SP:
598 case GRAPHIC_PIXEL_FMT_YCBCR_P010:
599 case GRAPHIC_PIXEL_FMT_YCRCB_P010: {
600 sampleSize = GetYuv420Size(dstImg.byteStride, dstImg.dispH);
601 break;
602 }
603 case GRAPHIC_PIXEL_FMT_RGBA_1010102:
604 case GRAPHIC_PIXEL_FMT_RGBA_8888: {
605 sampleSize = dstImg.byteStride * dstImg.dispH;
606 break;
607 }
608 default:
609 return 0;
610 }
611 if (sampleSize > dstImg.capacity) {
612 TLOGE("sampleSize %u > dst capacity %zu", sampleSize, dstImg.capacity);
613 return 0;
614 }
615 if (opt_.mockFrameCnt.has_value() && currInputCnt_ > opt_.mockFrameCnt.value()) {
616 return 0;
617 }
618 if ((opt_.maxReadFrameCnt > 0 && currInputCnt_ >= opt_.maxReadFrameCnt)) {
619 return sampleSize;
620 }
621 switch (dstImg.fmt) {
622 case GRAPHIC_PIXEL_FMT_YCBCR_420_P: {
623 return ReadOneFrameYUV420P(ifs_, dstImg);
624 }
625 case GRAPHIC_PIXEL_FMT_YCBCR_420_SP:
626 case GRAPHIC_PIXEL_FMT_YCRCB_420_SP: {
627 return ReadOneFrameYUV420SP(ifs_, dstImg, 1);
628 }
629 case GRAPHIC_PIXEL_FMT_YCBCR_P010:
630 case GRAPHIC_PIXEL_FMT_YCRCB_P010: {
631 return ReadOneFrameYUV420SP(ifs_, dstImg, 2); // bytesPerPixel=2
632 }
633 case GRAPHIC_PIXEL_FMT_RGBA_1010102:
634 case GRAPHIC_PIXEL_FMT_RGBA_8888: {
635 return ReadOneFrameRGBA(ifs_, dstImg);
636 }
637 default:
638 return 0;
639 }
640 }
641
InitDemuxer()642 bool TesterCommon::InitDemuxer()
643 {
644 ifs_ = ifstream(opt_.inputFile, ios::binary);
645 IF_TRUE_RETURN_VAL_WITH_MSG(!ifs_, false, "Failed to open file %s", opt_.inputFile.c_str());
646 demuxer_ = StartCodeDetector::Create(opt_.protocol);
647 totalSampleCnt_ = demuxer_->SetSource(opt_.inputFile);
648 if (totalSampleCnt_ == 0) {
649 TLOGE("no nalu found");
650 return false;
651 }
652 return true;
653 }
654
RunDecoder()655 bool TesterCommon::RunDecoder()
656 {
657 bool ret = InitDemuxer();
658 IF_TRUE_RETURN_VAL(!ret, false);
659 ret = Create();
660 IF_TRUE_RETURN_VAL(!ret, false);
661 ret = SetCallback();
662 IF_TRUE_RETURN_VAL(!ret, false);
663 ret = ConfigureDecoder();
664 IF_TRUE_RETURN_VAL(!ret, false);
665 if (!opt_.isBufferMode) {
666 sptr<Surface> surface = CreateSurfaceNormal();
667 if (surface == nullptr) {
668 return false;
669 }
670 ret = SetOutputSurface(surface);
671 IF_TRUE_RETURN_VAL(!ret, false);
672 }
673 GetInputFormat();
674 GetOutputFormat();
675 ret = Start();
676 IF_TRUE_RETURN_VAL(!ret, false);
677
678 thread outputThread(&TesterCommon::OutputLoop, this);
679 DecoderInputLoop();
680 if (outputThread.joinable()) {
681 outputThread.join();
682 }
683
684 ret = Stop();
685 IF_TRUE_RETURN_VAL(!ret, false);
686 ret = Release();
687 IF_TRUE_RETURN_VAL(!ret, false);
688 return true;
689 }
690
CreateSurfaceNormal()691 sptr<Surface> TesterCommon::CreateSurfaceNormal()
692 {
693 sptr<Surface> consumerSurface = Surface::CreateSurfaceAsConsumer();
694 if (consumerSurface == nullptr) {
695 TLOGE("CreateSurfaceAsConsumer failed");
696 return nullptr;
697 }
698 sptr<IBufferConsumerListener> listener = new Listener(this);
699 GSError err = consumerSurface->RegisterConsumerListener(listener);
700 if (err != GSERROR_OK) {
701 TLOGE("RegisterConsumerListener failed");
702 return nullptr;
703 }
704 err = consumerSurface->SetDefaultUsage(BUFFER_USAGE_CPU_READ);
705 if (err != GSERROR_OK) {
706 TLOGE("SetDefaultUsage failed");
707 return nullptr;
708 }
709 sptr<IBufferProducer> bufferProducer = consumerSurface->GetProducer();
710 sptr<Surface> producerSurface = Surface::CreateSurfaceAsProducer(bufferProducer);
711 if (producerSurface == nullptr) {
712 TLOGE("CreateSurfaceAsProducer failed");
713 return nullptr;
714 }
715 surface_ = consumerSurface;
716 return producerSurface;
717 }
718
OnBufferAvailable()719 void TesterCommon::Listener::OnBufferAvailable()
720 {
721 sptr<SurfaceBuffer> buffer;
722 int32_t fence;
723 int64_t timestamp;
724 OHOS::Rect damage;
725 GSError err = tester_->surface_->AcquireBuffer(buffer, fence, timestamp, damage);
726 if (err != GSERROR_OK || buffer == nullptr) {
727 TLOGW("AcquireBuffer failed");
728 return;
729 }
730 tester_->surface_->ReleaseBuffer(buffer, -1);
731 }
732
DecoderInputLoop()733 void TesterCommon::DecoderInputLoop()
734 {
735 PrepareSeek();
736 while (true) {
737 if (!SeekIfNecessary()) {
738 return;
739 }
740 BufInfo buf {};
741 if (!WaitForInput(buf)) {
742 continue;
743 }
744
745 size_t sampleIdx;
746 bool isCsd;
747 buf.attr.size = GetNextSample(buf, sampleIdx, isCsd);
748 if (isCsd) {
749 buf.attr.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
750 }
751 if (buf.attr.size == 0 || (opt_.maxReadFrameCnt > 0 && currInputCnt_ > opt_.maxReadFrameCnt)) {
752 buf.attr.size = 0;
753 buf.attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
754 BeforeQueueInput(buf.attr);
755 if (ReturnInput(buf)) {
756 TLOGI("queue eos succ, quit loop");
757 return;
758 } else {
759 TLOGW("queue eos failed");
760 continue;
761 }
762 }
763 BeforeQueueInput(buf.attr);
764 if (!ReturnInput(buf)) {
765 TLOGW("queue sample %zu failed", sampleIdx);
766 continue;
767 }
768 currInputCnt_++;
769 currSampleIdx_ = sampleIdx;
770 demuxer_->MoveToNext();
771 }
772 }
773
SaveVivid(int64_t pts)774 void TesterCommon::SaveVivid(int64_t pts)
775 {
776 optional<Sample> sample = demuxer_->PeekNextSample();
777 if (!sample.has_value()) {
778 return;
779 }
780 if (sample->vividSei.empty()) {
781 return;
782 }
783 lock_guard<mutex> lk(vividMtx_);
784 vividMap_[pts] = sample->vividSei;
785 }
786
GenerateRandomNumInRange(size_t rangeStart,size_t rangeEnd)787 static size_t GenerateRandomNumInRange(size_t rangeStart, size_t rangeEnd)
788 {
789 return rangeStart + rand() % (rangeEnd - rangeStart);
790 }
791
PrepareSeek()792 void TesterCommon::PrepareSeek()
793 {
794 int mockCnt = 0;
795 size_t lastSeekTo = 0;
796 while (mockCnt++ < opt_.flushCnt) {
797 size_t seekFrom = GenerateRandomNumInRange(lastSeekTo, totalSampleCnt_);
798 size_t seekTo = GenerateRandomNumInRange(0, totalSampleCnt_);
799 TLOGI("mock seek from sample index %zu to %zu", seekFrom, seekTo);
800 userSeekPos_.emplace_back(seekFrom, seekTo);
801 lastSeekTo = seekTo;
802 }
803 }
804
SeekIfNecessary()805 bool TesterCommon::SeekIfNecessary()
806 {
807 if (userSeekPos_.empty()) {
808 return true;
809 }
810 size_t seekFrom;
811 size_t seekTo;
812 std::tie(seekFrom, seekTo) = userSeekPos_.front();
813 if (currSampleIdx_ != seekFrom) {
814 return true;
815 }
816 TLOGI("begin to seek from sample index %zu to %zu", seekFrom, seekTo);
817 if (!demuxer_->SeekTo(seekTo)) {
818 return true;
819 }
820 if (!Flush()) {
821 return false;
822 }
823 if (!Start()) {
824 return false;
825 }
826 userSeekPos_.pop_front();
827 return true;
828 }
829
GetNextSample(const Span & dstSpan,size_t & sampleIdx,bool & isCsd)830 int TesterCommon::GetNextSample(const Span& dstSpan, size_t& sampleIdx, bool& isCsd)
831 {
832 optional<Sample> sample = demuxer_->PeekNextSample();
833 if (!sample.has_value()) {
834 return 0;
835 }
836 uint32_t sampleSize = sample->endPos - sample->startPos;
837 if (sampleSize > dstSpan.capacity) {
838 TLOGE("sampleSize %u > dst capacity %zu", sampleSize, dstSpan.capacity);
839 return 0;
840 }
841 TLOGI("sample %zu: size = %u, isCsd = %d, isIDR = %d, %s",
842 sample->idx, sampleSize, sample->isCsd, sample->isIdr, sample->s.c_str());
843 sampleIdx = sample->idx;
844 isCsd = sample->isCsd;
845 ifs_.seekg(sample->startPos);
846 ifs_.read(reinterpret_cast<char*>(dstSpan.va), sampleSize);
847 return sampleSize;
848 }
849
GetCodecMime(const CodeType & type)850 std::string TesterCommon::GetCodecMime(const CodeType& type)
851 {
852 switch (type) {
853 case H264:
854 return "video/avc";
855 case H265:
856 return "video/hevc";
857 case H266:
858 return "video/vvc";
859 default:
860 return "";
861 }
862 }
863 } // namespace OHOS::MediaAVCodec