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