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