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 printf("i = %u\n", 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 printf("RunDecEnc succ\n");
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 printf("%s input: flags=0x%x (eos)\n", codecStr, attr.flags);
140 LOGI("%s input: flags=0x%x (eos)", codecStr, attr.flags);
141 return;
142 }
143 if (attr.flags & AVCODEC_BUFFER_FLAG_CODEC_DATA) {
144 printf("%s input: flags=0x%x, pts=%" PRId64 ", size=%d\n", codecStr, attr.flags, attr.pts, attr.size);
145 LOGI("%s input: flags=0x%x, pts=%" PRId64 ", size=%d", codecStr, attr.flags, attr.pts, attr.size);
146 return;
147 }
148 printf("%s input: flags=0x%x, pts=%" PRId64 ", size=%d\n", codecStr, attr.flags, attr.pts, attr.size);
149 LOGI("%s input: flags=0x%x, pts=%" PRId64 ", size=%d", codecStr, attr.flags, attr.pts, attr.size);
150 if (firstInTime_ == 0) {
151 firstInTime_ = now;
152 }
153 inTotalCnt_++;
154 int64_t fromFirstInToNow = now - firstInTime_;
155 if (fromFirstInToNow != 0) {
156 inFps_ = inTotalCnt_ * US_TO_S / fromFirstInToNow;
157 }
158 }
159
AfterGotOutput(const OH_AVCodecBufferAttr & attr)160 void TesterCommon::AfterGotOutput(const OH_AVCodecBufferAttr& attr)
161 {
162 const char* codecStr = opt_.isEncoder ? "encoder" : "decoder";
163 int64_t now = GetNowUs();
164 if (attr.flags & AVCODEC_BUFFER_FLAG_EOS) {
165 printf("%s output: flags=0x%x (eos)\n", codecStr, attr.flags);
166 LOGI("%s output: flags=0x%x (eos)", codecStr, attr.flags);
167 return;
168 }
169 if (attr.flags & AVCODEC_BUFFER_FLAG_CODEC_DATA) {
170 printf("%s output: flags=0x%x, pts=%" PRId64 ", size=%d\n", codecStr, attr.flags, attr.pts, attr.size);
171 LOGI("%s output: flags=0x%x, pts=%" PRId64 ", size=%d", codecStr, attr.flags, attr.pts, attr.size);
172 return;
173 }
174 if (firstOutTime_ == 0) {
175 firstOutTime_ = now;
176 }
177 outTotalCnt_++;
178
179 int64_t fromInToOut = now - attr.pts;
180 totalCost_ += fromInToOut;
181 double oneFrameCostMs = fromInToOut / US_TO_MS;
182 double averageCostMs = totalCost_ / US_TO_MS / outTotalCnt_;
183
184 int64_t fromFirstOutToNow = now - firstOutTime_;
185 if (fromFirstOutToNow == 0) {
186 printf("%s output: flags=0x%x, pts=%" PRId64 ", size=%d, cost %.2f ms, average %.2f ms\n",
187 codecStr, attr.flags, attr.pts, attr.size, oneFrameCostMs, averageCostMs);
188 LOGI("%s output: flags=0x%x, pts=%" PRId64 ", size=%d, cost %.2f ms, average %.2f ms",
189 codecStr, attr.flags, attr.pts, attr.size, oneFrameCostMs, averageCostMs);
190 } else {
191 double outFps = outTotalCnt_ * US_TO_S / fromFirstOutToNow;
192 printf("%s output: flags=0x%x, pts=%" PRId64 ", size=%d, cost %.2f ms, average %.2f ms, "
193 "in fps %.2f, out fps %.2f\n",
194 codecStr, attr.flags, attr.pts, attr.size, oneFrameCostMs, averageCostMs, inFps_, outFps);
195 LOGI("%s output: flags=0x%x, pts=%" PRId64 ", size=%d, cost %.2f ms, average %.2f ms, "
196 "in fps %.2f, out fps %.2f",
197 codecStr, attr.flags, attr.pts, attr.size, oneFrameCostMs, averageCostMs, inFps_, outFps);
198 }
199 }
200
OutputLoop()201 void TesterCommon::OutputLoop()
202 {
203 while (true) {
204 BufInfo buf {};
205 if (!WaitForOutput(buf)) {
206 return;
207 }
208 if (opt_.isEncoder && opt_.decThenEnc) {
209 CheckVivid(buf);
210 }
211 ReturnOutput(buf.idx);
212 }
213 }
214
CheckVivid(const BufInfo & buf)215 void TesterCommon::CheckVivid(const BufInfo& buf)
216 {
217 vector<uint8_t> inVividSei;
218 {
219 lock_guard<mutex> lk(vividMtx_);
220 auto it = vividMap_.find(buf.attr.pts);
221 if (it == vividMap_.end()) {
222 return;
223 }
224 inVividSei = std::move(it->second);
225 vividMap_.erase(buf.attr.pts);
226 }
227 shared_ptr<StartCodeDetector> demuxer = StartCodeDetector::Create(opt_.protocol);
228 demuxer->SetSource(buf.va, buf.attr.size);
229 optional<Sample> sample = demuxer->PeekNextSample();
230 if (!sample.has_value()) {
231 printf("--- output pts %" PRId64 " has no sample but input has vivid\n", buf.attr.pts);
232 return;
233 }
234 if (sample->vividSei.empty()) {
235 printf("--- output pts %" PRId64 " has no vivid but input has vivid\n", buf.attr.pts);
236 return;
237 }
238 bool eq = std::equal(inVividSei.begin(), inVividSei.end(), sample->vividSei.begin());
239 if (eq) {
240 printf("--- output pts %" PRId64 " has vivid and is same as input vivid\n", buf.attr.pts);
241 } else {
242 printf("--- output pts %" PRId64 " has vivid but is different from input vivid\n", buf.attr.pts);
243 }
244 }
245
RunEncoder()246 bool TesterCommon::RunEncoder()
247 {
248 ifs_ = ifstream(opt_.inputFile, ios::binary);
249 IF_TRUE_RETURN_VAL_WITH_MSG(!ifs_, false, "Failed to open file %{public}s", opt_.inputFile.c_str());
250 optional<GraphicPixelFormat> displayFmt = TypeConverter::InnerFmtToDisplayFmt(opt_.pixFmt);
251 IF_TRUE_RETURN_VAL_WITH_MSG(!displayFmt, false, "invalid pixel format");
252 displayFmt_ = displayFmt.value();
253
254 bool ret = Create();
255 IF_TRUE_RETURN_VAL(!ret, false);
256 ret = SetCallback();
257 IF_TRUE_RETURN_VAL(!ret, false);
258 ret = ConfigureEncoder();
259 IF_TRUE_RETURN_VAL(!ret, false);
260 sptr<Surface> surface;
261 if (!opt_.isBufferMode) {
262 producerSurface_ = CreateInputSurface();
263 IF_TRUE_RETURN_VAL(producerSurface_ == nullptr, false);
264 }
265 ret = Start();
266 IF_TRUE_RETURN_VAL(!ret, false);
267 GetInputFormat();
268 GetOutputFormat();
269
270 thread th(&TesterCommon::OutputLoop, this);
271 EncoderInputLoop();
272 if (th.joinable()) {
273 th.join();
274 }
275 ret = Stop();
276 IF_TRUE_RETURN_VAL(!ret, false);
277 ret = Release();
278 IF_TRUE_RETURN_VAL(!ret, false);
279 return true;
280 }
281
EncoderInputLoop()282 void TesterCommon::EncoderInputLoop()
283 {
284 while (true) {
285 BufInfo buf {};
286 bool ret = opt_.isBufferMode ? WaitForInput(buf) : WaitForInputSurfaceBuffer(buf);
287 if (!ret) {
288 continue;
289 }
290 buf.attr.size = ReadOneFrame(buf);
291 if (buf.attr.size == 0) {
292 buf.attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
293 BeforeQueueInput(buf.attr);
294 ret = opt_.isBufferMode ? ReturnInput(buf) : NotifyEos();
295 if (ret) {
296 LOGI("queue eos succ, quit loop");
297 return;
298 } else {
299 LOGW("queue eos failed");
300 continue;
301 }
302 }
303 BeforeQueueInput(buf.attr);
304 ret = opt_.isBufferMode ? ReturnInput(buf) : ReturnInputSurfaceBuffer(buf);
305 if (!ret) {
306 continue;
307 }
308 currInputCnt_++;
309 if (opt_.idrFrameNo.has_value() && currInputCnt_ == opt_.idrFrameNo.value()) {
310 RequestIDR();
311 }
312 }
313 }
314
SurfaceBufferToBufferInfo(BufInfo & buf,sptr<SurfaceBuffer> surfaceBuffer)315 bool TesterCommon::SurfaceBufferToBufferInfo(BufInfo& buf, sptr<SurfaceBuffer> surfaceBuffer)
316 {
317 if (surfaceBuffer == nullptr) {
318 LOGE("null surfaceBuffer");
319 return false;
320 }
321 buf.va = static_cast<uint8_t *>(surfaceBuffer->GetVirAddr());
322 buf.capacity = surfaceBuffer->GetSize();
323
324 buf.dispW = surfaceBuffer->GetWidth();
325 buf.dispH = surfaceBuffer->GetHeight();
326 buf.fmt = static_cast<GraphicPixelFormat>(surfaceBuffer->GetFormat());
327 buf.byteStride = surfaceBuffer->GetStride();
328 return true;
329 }
330
NativeBufferToBufferInfo(BufInfo & buf,OH_NativeBuffer * nativeBuffer)331 bool TesterCommon::NativeBufferToBufferInfo(BufInfo& buf, OH_NativeBuffer* nativeBuffer)
332 {
333 if (nativeBuffer == nullptr) {
334 LOGE("null OH_NativeBuffer");
335 return false;
336 }
337 OH_NativeBuffer_Config cfg;
338 OH_NativeBuffer_GetConfig(nativeBuffer, &cfg);
339 buf.dispW = cfg.width;
340 buf.dispH = cfg.height;
341 buf.fmt = static_cast<GraphicPixelFormat>(cfg.format);
342 buf.byteStride = cfg.stride;
343 return true;
344 }
345
WaitForInputSurfaceBuffer(BufInfo & buf)346 bool TesterCommon::WaitForInputSurfaceBuffer(BufInfo& buf)
347 {
348 BufferRequestConfig cfg = {opt_.dispW, opt_.dispH, 32, displayFmt_,
349 BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA, 0, };
350 sptr<SurfaceBuffer> surfaceBuffer;
351 int32_t fence;
352 GSError err = producerSurface_->RequestBuffer(surfaceBuffer, fence, cfg);
353 if (err != GSERROR_OK) {
354 return false;
355 }
356 buf.surfaceBuf = surfaceBuffer;
357 return SurfaceBufferToBufferInfo(buf, surfaceBuffer);
358 }
359
ReturnInputSurfaceBuffer(BufInfo & buf)360 bool TesterCommon::ReturnInputSurfaceBuffer(BufInfo& buf)
361 {
362 BufferFlushConfig flushConfig = {
363 .damage = {
364 .w = opt_.dispW,
365 .h = opt_.dispH,
366 },
367 .timestamp = buf.attr.pts,
368 };
369 GSError err = producerSurface_->FlushBuffer(buf.surfaceBuf, -1, flushConfig);
370 if (err != GSERROR_OK) {
371 LOGE("FlushBuffer failed");
372 return false;
373 }
374 return true;
375 }
376
377 #define RETURN_ZERO_IF_EOS(expectedSize) \
378 do { \
379 if (ifs_.gcount() != (expectedSize)) { \
380 LOGI("no more data"); \
381 return 0; \
382 } \
383 } while (0)
384
ReadOneFrameYUV420P(ImgBuf & dstImg)385 uint32_t TesterCommon::ReadOneFrameYUV420P(ImgBuf& dstImg)
386 {
387 char* dst = reinterpret_cast<char*>(dstImg.va);
388 char* start = dst;
389 // copy Y
390 for (uint32_t i = 0; i < dstImg.dispH; i++) {
391 ifs_.read(dst, dstImg.dispW);
392 RETURN_ZERO_IF_EOS(dstImg.dispW);
393 dst += dstImg.byteStride;
394 }
395 // copy U
396 for (uint32_t i = 0; i < dstImg.dispH / SAMPLE_RATIO; i++) {
397 ifs_.read(dst, dstImg.dispW / SAMPLE_RATIO);
398 RETURN_ZERO_IF_EOS(dstImg.dispW / SAMPLE_RATIO);
399 dst += dstImg.byteStride / SAMPLE_RATIO;
400 }
401 // copy V
402 for (uint32_t i = 0; i < dstImg.dispH / SAMPLE_RATIO; i++) {
403 ifs_.read(dst, dstImg.dispW / SAMPLE_RATIO);
404 RETURN_ZERO_IF_EOS(dstImg.dispW / SAMPLE_RATIO);
405 dst += dstImg.byteStride / SAMPLE_RATIO;
406 }
407 return dst - start;
408 }
409
ReadOneFrameYUV420SP(ImgBuf & dstImg)410 uint32_t TesterCommon::ReadOneFrameYUV420SP(ImgBuf& dstImg)
411 {
412 char* dst = reinterpret_cast<char*>(dstImg.va);
413 char* start = dst;
414 // copy Y
415 for (uint32_t i = 0; i < dstImg.dispH; i++) {
416 ifs_.read(dst, dstImg.dispW);
417 RETURN_ZERO_IF_EOS(dstImg.dispW);
418 dst += dstImg.byteStride;
419 }
420 // copy UV
421 for (uint32_t i = 0; i < dstImg.dispH / SAMPLE_RATIO; i++) {
422 ifs_.read(dst, dstImg.dispW);
423 RETURN_ZERO_IF_EOS(dstImg.dispW);
424 dst += dstImg.byteStride;
425 }
426 return dst - start;
427 }
428
ReadOneFrameRGBA(ImgBuf & dstImg)429 uint32_t TesterCommon::ReadOneFrameRGBA(ImgBuf& dstImg)
430 {
431 char* dst = reinterpret_cast<char*>(dstImg.va);
432 char* start = dst;
433 for (uint32_t i = 0; i < dstImg.dispH; i++) {
434 ifs_.read(dst, dstImg.dispW * BYTES_PER_PIXEL_RBGA);
435 RETURN_ZERO_IF_EOS(dstImg.dispW * BYTES_PER_PIXEL_RBGA);
436 dst += dstImg.byteStride;
437 }
438 return dst - start;
439 }
440
ReadOneFrame(ImgBuf & dstImg)441 uint32_t TesterCommon::ReadOneFrame(ImgBuf& dstImg)
442 {
443 if (dstImg.va == nullptr) {
444 LOGE("dst image has null va");
445 return 0;
446 }
447 if (dstImg.byteStride < dstImg.dispW) {
448 LOGE("byteStride %{public}u < dispW %{public}u", dstImg.byteStride, dstImg.dispW);
449 return 0;
450 }
451 uint32_t sampleSize = 0;
452 switch (dstImg.fmt) {
453 case GRAPHIC_PIXEL_FMT_YCBCR_420_P:
454 case GRAPHIC_PIXEL_FMT_YCBCR_420_SP:
455 case GRAPHIC_PIXEL_FMT_YCRCB_420_SP: {
456 sampleSize = GetYuv420Size(dstImg.byteStride, dstImg.dispH);
457 break;
458 }
459 case GRAPHIC_PIXEL_FMT_RGBA_8888: {
460 sampleSize = dstImg.byteStride * dstImg.dispH;
461 break;
462 }
463 default:
464 return 0;
465 }
466 if (sampleSize > dstImg.capacity) {
467 LOGE("sampleSize %{public}u > dst capacity %{public}zu", sampleSize, dstImg.capacity);
468 return 0;
469 }
470 if (opt_.mockFrameCnt.has_value() && currInputCnt_ > opt_.mockFrameCnt.value()) {
471 return 0;
472 }
473 if ((opt_.maxReadFrameCnt > 0 && currInputCnt_ >= opt_.maxReadFrameCnt)) {
474 return sampleSize;
475 }
476 switch (dstImg.fmt) {
477 case GRAPHIC_PIXEL_FMT_YCBCR_420_P: {
478 return ReadOneFrameYUV420P(dstImg);
479 }
480 case GRAPHIC_PIXEL_FMT_YCBCR_420_SP:
481 case GRAPHIC_PIXEL_FMT_YCRCB_420_SP: {
482 return ReadOneFrameYUV420SP(dstImg);
483 }
484 case GRAPHIC_PIXEL_FMT_RGBA_8888: {
485 return ReadOneFrameRGBA(dstImg);
486 }
487 default:
488 return 0;
489 }
490 }
491
InitDemuxer()492 bool TesterCommon::InitDemuxer()
493 {
494 ifs_ = ifstream(opt_.inputFile, ios::binary);
495 IF_TRUE_RETURN_VAL_WITH_MSG(!ifs_, false, "Failed to open file %{public}s", opt_.inputFile.c_str());
496 demuxer_ = StartCodeDetector::Create(opt_.protocol);
497 totalSampleCnt_ = demuxer_->SetSource(opt_.inputFile);
498 if (totalSampleCnt_ == 0) {
499 LOGE("no nalu found");
500 return false;
501 }
502 return true;
503 }
504
RunDecoder()505 bool TesterCommon::RunDecoder()
506 {
507 bool ret = InitDemuxer();
508 IF_TRUE_RETURN_VAL(!ret, false);
509 ret = Create();
510 IF_TRUE_RETURN_VAL(!ret, false);
511 ret = SetCallback();
512 IF_TRUE_RETURN_VAL(!ret, false);
513 ret = ConfigureDecoder();
514 IF_TRUE_RETURN_VAL(!ret, false);
515 if (!opt_.isBufferMode) {
516 sptr<Surface> surface = opt_.render ? CreateSurfaceFromWindow() : CreateSurfaceNormal();
517 if (surface == nullptr) {
518 return false;
519 }
520 ret = SetOutputSurface(surface);
521 IF_TRUE_RETURN_VAL(!ret, false);
522 }
523 GetInputFormat();
524 GetOutputFormat();
525 ret = Start();
526 IF_TRUE_RETURN_VAL(!ret, false);
527
528 thread outputThread(&TesterCommon::OutputLoop, this);
529 DecoderInputLoop();
530 if (outputThread.joinable()) {
531 outputThread.join();
532 }
533
534 ret = Stop();
535 IF_TRUE_RETURN_VAL(!ret, false);
536 ret = Release();
537 IF_TRUE_RETURN_VAL(!ret, false);
538 if (window_ != nullptr) {
539 window_->Destroy();
540 window_ = nullptr;
541 }
542 return true;
543 }
544
CreateSurfaceFromWindow()545 sptr<Surface> TesterCommon::CreateSurfaceFromWindow()
546 {
547 sptr<WindowOption> option = new WindowOption();
548 option->SetWindowType(WindowType::WINDOW_TYPE_FLOAT);
549 option->SetWindowMode(WindowMode::WINDOW_MODE_FULLSCREEN);
550 sptr<Window> window = Window::Create("DemoWindow", option);
551 if (window == nullptr) {
552 LOGE("Create Window failed");
553 return nullptr;
554 }
555 shared_ptr<RSSurfaceNode> node = window->GetSurfaceNode();
556 if (node == nullptr) {
557 LOGE("GetSurfaceNode failed");
558 return nullptr;
559 }
560 sptr<Surface> surface = node->GetSurface();
561 if (surface == nullptr) {
562 LOGE("GetSurface failed");
563 return nullptr;
564 }
565 window->Show();
566 window_ = window;
567 return surface;
568 }
569
CreateSurfaceNormal()570 sptr<Surface> TesterCommon::CreateSurfaceNormal()
571 {
572 sptr<Surface> consumerSurface = Surface::CreateSurfaceAsConsumer();
573 if (consumerSurface == nullptr) {
574 LOGE("CreateSurfaceAsConsumer failed");
575 return nullptr;
576 }
577 sptr<IBufferConsumerListener> listener = new Listener(this);
578 GSError err = consumerSurface->RegisterConsumerListener(listener);
579 if (err != GSERROR_OK) {
580 LOGE("RegisterConsumerListener failed");
581 return nullptr;
582 }
583 err = consumerSurface->SetDefaultUsage(BUFFER_USAGE_CPU_READ);
584 if (err != GSERROR_OK) {
585 LOGE("SetDefaultUsage failed");
586 return nullptr;
587 }
588 sptr<IBufferProducer> bufferProducer = consumerSurface->GetProducer();
589 sptr<Surface> producerSurface = Surface::CreateSurfaceAsProducer(bufferProducer);
590 if (producerSurface == nullptr) {
591 LOGE("CreateSurfaceAsProducer failed");
592 return nullptr;
593 }
594 surface_ = consumerSurface;
595 return producerSurface;
596 }
597
OnBufferAvailable()598 void TesterCommon::Listener::OnBufferAvailable()
599 {
600 sptr<SurfaceBuffer> buffer;
601 int32_t fence;
602 int64_t timestamp;
603 OHOS::Rect damage;
604 GSError err = tester_->surface_->AcquireBuffer(buffer, fence, timestamp, damage);
605 if (err != GSERROR_OK || buffer == nullptr) {
606 LOGW("AcquireBuffer failed");
607 return;
608 }
609 tester_->surface_->ReleaseBuffer(buffer, -1);
610 }
611
DecoderInputLoop()612 void TesterCommon::DecoderInputLoop()
613 {
614 PrepareSeek();
615 while (true) {
616 if (!SeekIfNecessary()) {
617 return;
618 }
619 BufInfo buf {};
620 if (!WaitForInput(buf)) {
621 continue;
622 }
623
624 size_t sampleIdx;
625 bool isCsd;
626 buf.attr.size = GetNextSample(buf, sampleIdx, isCsd);
627 if (isCsd) {
628 buf.attr.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
629 }
630 if (buf.attr.size == 0 || (opt_.maxReadFrameCnt > 0 && currInputCnt_ > opt_.maxReadFrameCnt)) {
631 buf.attr.size = 0;
632 buf.attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
633 BeforeQueueInput(buf.attr);
634 if (ReturnInput(buf)) {
635 LOGI("queue eos succ, quit loop");
636 return;
637 } else {
638 LOGW("queue eos failed");
639 continue;
640 }
641 }
642 BeforeQueueInput(buf.attr);
643 if (!ReturnInput(buf)) {
644 LOGW("queue sample %{public}zu failed", sampleIdx);
645 continue;
646 }
647 currInputCnt_++;
648 currSampleIdx_ = sampleIdx;
649 demuxer_->MoveToNext();
650 }
651 }
652
SaveVivid(int64_t pts)653 void TesterCommon::SaveVivid(int64_t pts)
654 {
655 optional<Sample> sample = demuxer_->PeekNextSample();
656 if (!sample.has_value()) {
657 return;
658 }
659 if (sample->vividSei.empty()) {
660 return;
661 }
662 lock_guard<mutex> lk(vividMtx_);
663 vividMap_[pts] = sample->vividSei;
664 }
665
GenerateRandomNumInRange(size_t rangeStart,size_t rangeEnd)666 static size_t GenerateRandomNumInRange(size_t rangeStart, size_t rangeEnd)
667 {
668 return rangeStart + rand() % (rangeEnd - rangeStart);
669 }
670
PrepareSeek()671 void TesterCommon::PrepareSeek()
672 {
673 int mockCnt = 0;
674 size_t lastSeekTo = 0;
675 while (mockCnt++ < opt_.flushCnt) {
676 size_t seekFrom = GenerateRandomNumInRange(lastSeekTo, totalSampleCnt_);
677 size_t seekTo = GenerateRandomNumInRange(0, totalSampleCnt_);
678 LOGI("mock seek from sample index %{public}zu to %{public}zu", seekFrom, seekTo);
679 userSeekPos_.emplace_back(seekFrom, seekTo);
680 lastSeekTo = seekTo;
681 }
682 }
683
SeekIfNecessary()684 bool TesterCommon::SeekIfNecessary()
685 {
686 if (userSeekPos_.empty()) {
687 return true;
688 }
689 size_t seekFrom;
690 size_t seekTo;
691 std::tie(seekFrom, seekTo) = userSeekPos_.front();
692 if (currSampleIdx_ != seekFrom) {
693 return true;
694 }
695 LOGI("begin to seek from sample index %{public}zu to %{public}zu", seekFrom, seekTo);
696 if (!demuxer_->SeekTo(seekTo)) {
697 return true;
698 }
699 if (!Flush()) {
700 return false;
701 }
702 if (!Start()) {
703 return false;
704 }
705 userSeekPos_.pop_front();
706 return true;
707 }
708
GetNextSample(const Span & dstSpan,size_t & sampleIdx,bool & isCsd)709 int TesterCommon::GetNextSample(const Span& dstSpan, size_t& sampleIdx, bool& isCsd)
710 {
711 optional<Sample> sample = demuxer_->PeekNextSample();
712 if (!sample.has_value()) {
713 return 0;
714 }
715 uint32_t sampleSize = sample->endPos - sample->startPos;
716 if (sampleSize > dstSpan.capacity) {
717 LOGE("sampleSize %{public}u > dst capacity %{public}zu", sampleSize, dstSpan.capacity);
718 return 0;
719 }
720 LOGI("sample %{public}zu: size = %{public}u, isCsd = %{public}d, isIDR = %{public}d, %{public}s",
721 sample->idx, sampleSize, sample->isCsd, sample->isIdr, sample->s.c_str());
722 sampleIdx = sample->idx;
723 isCsd = sample->isCsd;
724 ifs_.seekg(sample->startPos);
725 ifs_.read(reinterpret_cast<char*>(dstSpan.va), sampleSize);
726 return sampleSize;
727 }
728 } // namespace OHOS::MediaAVCodec