• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "tester_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