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