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 &param = 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