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