• 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 "native_avcodec_base.h"
18 #include "ui/rs_surface_node.h"  // foundation/graphic/graphic_2d/rosen/modules/render_service_client/core/
19 #include "utils.h"
20 #include "hcodec_api.h"
21 #include "hcodec_log.h"
22 #include "type_converter.h"
23 #include "tester_codecbase.h"
24 #include "tester_capi.h"
25 
26 namespace OHOS::MediaAVCodec {
27 using namespace std;
28 using namespace OHOS::Rosen;
29 
GetNowUs()30 int64_t TesterCommon::GetNowUs()
31 {
32     auto now = chrono::steady_clock::now();
33     return chrono::duration_cast<chrono::microseconds>(now.time_since_epoch()).count();
34 }
35 
Run(const CommandOpt & opt)36 bool TesterCommon::Run(const CommandOpt& opt)
37 {
38     opt.Print();
39     shared_ptr<TesterCommon> tester;
40     if (opt.testCodecBaseApi) {
41         tester = make_shared<TesterCodecBase>(opt);
42     } else {
43         tester = make_shared<TesterCapi>(opt);
44     }
45     CostRecorder::Instance().Clear();
46     for (uint32_t i = 0; i < opt.repeatCnt; i++) {
47         printf("i = %u\n", i);
48         bool ret = tester->RunOnce();
49         if (!ret) {
50             return false;
51         }
52     }
53     CostRecorder::Instance().Print();
54     return true;
55 }
56 
RunOnce()57 bool TesterCommon::RunOnce()
58 {
59     return opt_.isEncoder ? RunEncoder() : RunDecoder();
60 }
61 
OutputLoop()62 void TesterCommon::OutputLoop()
63 {
64     while (true) {
65         optional<uint32_t> outputIdx = GetOutputIndex();
66         if (!outputIdx.has_value()) {
67             return;
68         }
69         ReturnOutput(outputIdx.value());
70     }
71 }
72 
RunEncoder()73 bool TesterCommon::RunEncoder()
74 {
75     ifs_ = ifstream(opt_.inputFile, ios::binary);
76     IF_TRUE_RETURN_VAL_WITH_MSG(!ifs_, false, "Failed to open file %{public}s", opt_.inputFile.c_str());
77     optional<GraphicPixelFormat> displayFmt = TypeConverter::InnerFmtToDisplayFmt(opt_.pixFmt);
78     IF_TRUE_RETURN_VAL_WITH_MSG(!displayFmt, false, "invalid pixel format");
79     displayFmt_ = displayFmt.value();
80 
81     bool ret = Create();
82     IF_TRUE_RETURN_VAL(!ret, false);
83     ret = SetCallback();
84     IF_TRUE_RETURN_VAL(!ret, false);
85     ret = ConfigureEncoder();
86     IF_TRUE_RETURN_VAL(!ret, false);
87     ret = GetInputFormat();
88     if (opt_.isBufferMode) {
89         stride_ = opt_.dispW;
90         if (ret) {
91             optional<uint32_t> stride = GetInputStride();
92             if (stride && stride.value() >= opt_.dispW) {
93                 stride_ = stride.value();
94             }
95         }
96     } else {
97         ret = CreateInputSurface();
98         IF_TRUE_RETURN_VAL(!ret, false);
99     }
100     GetOutputFormat();
101     ret = Start();
102     IF_TRUE_RETURN_VAL(!ret, false);
103 
104     thread th(&TesterCommon::OutputLoop, this);
105     if (opt_.isBufferMode) {
106         EncoderInputLoop();
107     } else {
108         InputSurfaceLoop();
109     }
110     if (th.joinable()) {
111         th.join();
112     }
113     ret = Stop();
114     IF_TRUE_RETURN_VAL(!ret, false);
115     ret = Release();
116     IF_TRUE_RETURN_VAL(!ret, false);
117     return true;
118 }
119 
EncoderInputLoop()120 void TesterCommon::EncoderInputLoop()
121 {
122     while (true) {
123         Span span;
124         optional<uint32_t> inputIdx = GetInputIndex(span);
125         if (!inputIdx.has_value()) {
126             continue;
127         }
128         OH_AVCodecBufferAttr info;
129         info.offset = 0;
130         info.flags = 0;
131         info.size = ReadOneFrame(span);
132         if (info.size == 0 || (opt_.inputCnt > 0 && currInputCnt_ > opt_.inputCnt)) {
133             info.flags = AVCODEC_BUFFER_FLAGS_EOS;
134             if (!QueueInput(inputIdx.value(), info)) {
135                 continue;
136             } else {
137                 LOGI("queue eos succ, quit loop");
138                 return;
139             }
140         }
141         info.pts = GetNowUs();
142         if (!QueueInput(inputIdx.value(), info)) {
143             continue;
144         }
145         currInputCnt_++;
146         if (currInputCnt_ == opt_.numIdrFrame) {
147             RequestIDR();
148         }
149     }
150 }
151 
InputSurfaceLoop()152 void TesterCommon::InputSurfaceLoop()
153 {
154     BufferRequestConfig cfg = {opt_.dispW, opt_.dispH, 32, displayFmt_,
155                                BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA, 0, };
156 
157     while (true)  {
158         sptr<SurfaceBuffer> surfaceBuffer;
159         int32_t fence;
160         GSError err = surface_->RequestBuffer(surfaceBuffer, fence, cfg);
161         if (err != GSERROR_OK || surfaceBuffer == nullptr) {
162             this_thread::sleep_for(10ms);
163             continue;
164         }
165         char* dst = reinterpret_cast<char *>(surfaceBuffer->GetVirAddr());
166         int stride = surfaceBuffer->GetStride();
167         if (dst == nullptr || stride < opt_.dispW) {
168             LOGE("invalid va or stride %{public}d", stride);
169             surface_->CancelBuffer(surfaceBuffer);
170             continue;
171         }
172         stride_ = stride;
173         uint32_t filledLen = ReadOneFrame(Span {dst, surfaceBuffer->GetSize()});
174         if (filledLen == 0 || (opt_.inputCnt > 0 && currInputCnt_ > opt_.inputCnt)) {
175             LOGI("input eos, quit loop");
176             if (!NotifyEos()) {
177                 LOGE("NotifyEos failed");
178             }
179             return;
180         }
181         BufferFlushConfig flushConfig = {
182             .damage = {
183                 .w = opt_.dispW,
184                 .h = opt_.dispH,
185             },
186             .timestamp = GetNowUs(),
187         };
188         err = surface_->FlushBuffer(surfaceBuffer, -1, flushConfig);
189         if (err != GSERROR_OK) {
190             LOGE("FlushBuffer failed");
191             continue;
192         }
193         currInputCnt_++;
194         if (currInputCnt_ == opt_.numIdrFrame) {
195             RequestIDR();
196         }
197     }
198 }
199 
200 #define RETURN_ZERO_IF_EOS(expectedSize) \
201     do { \
202         if (ifs_.gcount() != (expectedSize)) { \
203             LOGI("no more data"); \
204             return 0; \
205         } \
206     } while (0)
207 
ReadOneFrameYUV420P(char * dst)208 uint32_t TesterCommon::ReadOneFrameYUV420P(char* dst)
209 {
210     char* start = dst;
211     // copy Y
212     for (uint32_t i = 0; i < opt_.dispH; i++) {
213         ifs_.read(dst, opt_.dispW);
214         RETURN_ZERO_IF_EOS(opt_.dispW);
215         dst += stride_;
216     }
217     // copy U
218     for (uint32_t i = 0; i < opt_.dispH / SAMPLE_RATIO; i++) {
219         ifs_.read(dst, opt_.dispW / SAMPLE_RATIO);
220         RETURN_ZERO_IF_EOS(opt_.dispW / SAMPLE_RATIO);
221         dst += stride_ / SAMPLE_RATIO;
222     }
223     // copy V
224     for (uint32_t i = 0; i < opt_.dispH / SAMPLE_RATIO; i++) {
225         ifs_.read(dst, opt_.dispW / SAMPLE_RATIO);
226         RETURN_ZERO_IF_EOS(opt_.dispW / SAMPLE_RATIO);
227         dst += stride_ / SAMPLE_RATIO;
228     }
229     return dst - start;
230 }
231 
ReadOneFrameYUV420SP(char * dst)232 uint32_t TesterCommon::ReadOneFrameYUV420SP(char* dst)
233 {
234     char* start = dst;
235     // copy Y
236     for (uint32_t i = 0; i < opt_.dispH; i++) {
237         ifs_.read(dst, opt_.dispW);
238         RETURN_ZERO_IF_EOS(opt_.dispW);
239         dst += stride_;
240     }
241     // copy UV
242     for (uint32_t i = 0; i < opt_.dispH / SAMPLE_RATIO; i++) {
243         ifs_.read(dst, opt_.dispW);
244         RETURN_ZERO_IF_EOS(opt_.dispW);
245         dst += stride_;
246     }
247     return dst - start;
248 }
249 
ReadOneFrameRGBA(char * dst)250 uint32_t TesterCommon::ReadOneFrameRGBA(char* dst)
251 {
252     char* start = dst;
253     for (uint32_t i = 0; i < opt_.dispH; i++) {
254         ifs_.read(dst, opt_.dispW * BYTES_PER_PIXEL_RBGA);
255         RETURN_ZERO_IF_EOS(opt_.dispW * BYTES_PER_PIXEL_RBGA);
256         dst += stride_;
257     }
258     return dst - start;
259 }
260 
ReadOneFrame(Span dstSpan)261 uint32_t TesterCommon::ReadOneFrame(Span dstSpan)
262 {
263     uint32_t sampleSize = 0;
264     switch (opt_.pixFmt) {
265         case YUVI420:
266         case NV12:
267         case NV21: {
268             sampleSize = GetYuv420Size(stride_, opt_.dispH);
269             break;
270         }
271         case RGBA: {
272             sampleSize = stride_ * opt_.dispH;
273             break;
274         }
275         default:
276             return 0;
277     }
278     if (sampleSize > dstSpan.capacity) {
279         LOGE("sampleSize %{public}u > dst capacity %{public}zu", sampleSize, dstSpan.capacity);
280         return 0;
281     }
282 
283     switch (opt_.pixFmt) {
284         case YUVI420: {
285             return ReadOneFrameYUV420P(dstSpan.va);
286         }
287         case NV12:
288         case NV21: {
289             return ReadOneFrameYUV420SP(dstSpan.va);
290         }
291         case RGBA: {
292             return ReadOneFrameRGBA(dstSpan.va);
293         }
294         default:
295             return 0;
296     }
297 }
298 
RunDecoder()299 bool TesterCommon::RunDecoder()
300 {
301     ifs_ = ifstream(opt_.inputFile, ios::binary);
302     IF_TRUE_RETURN_VAL_WITH_MSG(!ifs_, false, "Failed to open file %{public}s", opt_.inputFile.c_str());
303     totalSampleCnt_ = demuxer_.SetSource(opt_.inputFile, opt_.protocol);
304     if (totalSampleCnt_ == 0) {
305         LOGE("no nalu found");
306         return false;
307     }
308 
309     bool ret = Create();
310     IF_TRUE_RETURN_VAL(!ret, false);
311     ret = SetCallback();
312     IF_TRUE_RETURN_VAL(!ret, false);
313     ret = ConfigureDecoder();
314     IF_TRUE_RETURN_VAL(!ret, false);
315     if (!opt_.isBufferMode) {
316         sptr<Surface> surface = CreateSurfaceNormal();
317         if (surface == nullptr) {
318             return false;
319         }
320         ret = SetOutputSurface(surface);
321         IF_TRUE_RETURN_VAL(!ret, false);
322     }
323     GetInputFormat();
324     GetOutputFormat();
325     ret = Start();
326     IF_TRUE_RETURN_VAL(!ret, false);
327 
328     thread outputThread(&TesterCommon::OutputLoop, this);
329     DecoderInputLoop();
330     if (outputThread.joinable()) {
331         outputThread.join();
332     }
333 
334     ret = Stop();
335     IF_TRUE_RETURN_VAL(!ret, false);
336     ret = Release();
337     IF_TRUE_RETURN_VAL(!ret, false);
338     if (window_ != nullptr) {
339         window_->Destroy();
340         window_ = nullptr;
341     }
342     return true;
343 }
344 
CreateSurfaceFromWindow()345 sptr<Surface> TesterCommon::CreateSurfaceFromWindow()
346 {
347     sptr<WindowOption> option = new WindowOption();
348     option->SetWindowRect({ 0, 0, opt_.dispW, opt_.dispH });
349     option->SetWindowType(WindowType::WINDOW_TYPE_FLOAT);
350     option->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING);
351     sptr<Window> window = Window::Create("DemoWindow", option);
352     if (window == nullptr) {
353         LOGE("Create Window failed");
354         return nullptr;
355     }
356     shared_ptr<RSSurfaceNode> node = window->GetSurfaceNode();
357     if (node == nullptr) {
358         LOGE("GetSurfaceNode failed");
359         return nullptr;
360     }
361     sptr<Surface> surface = node->GetSurface();
362     if (surface == nullptr) {
363         LOGE("GetSurface failed");
364         return nullptr;
365     }
366     window->Show();
367     window_ = window;
368     return surface;
369 }
370 
CreateSurfaceNormal()371 sptr<Surface> TesterCommon::CreateSurfaceNormal()
372 {
373     sptr<Surface> consumerSurface = Surface::CreateSurfaceAsConsumer();
374     if (consumerSurface == nullptr) {
375         LOGE("CreateSurfaceAsConsumer failed");
376         return nullptr;
377     }
378     sptr<IBufferConsumerListener> listener = new Listener(this);
379     GSError err = consumerSurface->RegisterConsumerListener(listener);
380     if (err != GSERROR_OK) {
381         LOGE("RegisterConsumerListener failed");
382         return nullptr;
383     }
384     sptr<IBufferProducer> bufferProducer = consumerSurface->GetProducer();
385     sptr<Surface> producerSurface = Surface::CreateSurfaceAsProducer(bufferProducer);
386     if (producerSurface == nullptr) {
387         LOGE("CreateSurfaceAsProducer failed");
388         return nullptr;
389     }
390     surface_ = consumerSurface;
391     return producerSurface;
392 }
393 
OnBufferAvailable()394 void TesterCommon::Listener::OnBufferAvailable()
395 {
396     sptr<SurfaceBuffer> buffer;
397     int32_t fence;
398     int64_t timestamp;
399     OHOS::Rect damage;
400     GSError err = tester_->surface_->AcquireBuffer(buffer, fence, timestamp, damage);
401     if (err != GSERROR_OK || buffer == nullptr) {
402         LOGW("AcquireBuffer failed");
403         return;
404     }
405     tester_->surface_->ReleaseBuffer(buffer, -1);
406 }
407 
DecoderInputLoop()408 void TesterCommon::DecoderInputLoop()
409 {
410     PrepareSeek();
411     while (true) {
412         if (!SeekIfNecessary()) {
413             return;
414         }
415         Span span;
416         optional<uint32_t> inputIdx = GetInputIndex(span);
417         if (!inputIdx.has_value()) {
418             continue;
419         }
420         OH_AVCodecBufferAttr info;
421         info.offset = 0;
422         info.flags = 0;
423 
424         size_t sampleIdx;
425         bool isCsd;
426         info.size = GetNextSample(span, sampleIdx, isCsd);
427         if (isCsd) {
428             info.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
429         }
430         if (info.size == 0 || (opt_.inputCnt > 0 && currInputCnt_ > opt_.inputCnt)) {
431             info.flags = AVCODEC_BUFFER_FLAGS_EOS;
432             if (!QueueInput(inputIdx.value(), info)) {
433                 LOGW("queue eos failed");
434                 continue;
435             } else {
436                 LOGI("queue eos succ, quit loop");
437                 return;
438             }
439         }
440         info.pts = GetNowUs();
441         if (!QueueInput(inputIdx.value(), info)) {
442             LOGW("queue sample %{public}zu failed", sampleIdx);
443             continue;
444         }
445         currInputCnt_++;
446         currSampleIdx_ = sampleIdx;
447         demuxer_.MoveToNext();
448     }
449 }
450 
GenerateRandomNumInRange(size_t rangeStart,size_t rangeEnd)451 static size_t GenerateRandomNumInRange(size_t rangeStart, size_t rangeEnd)
452 {
453     return rangeStart + rand() % (rangeEnd - rangeStart);
454 }
455 
PrepareSeek()456 void TesterCommon::PrepareSeek()
457 {
458     int mockCnt = 0;
459     size_t lastSeekTo = 0;
460     while (mockCnt++ < opt_.flushCnt) {
461         size_t seekFrom = GenerateRandomNumInRange(lastSeekTo, totalSampleCnt_);
462         size_t seekTo = GenerateRandomNumInRange(0, totalSampleCnt_);
463         LOGI("mock seek from sample index %{public}zu to %{public}zu", seekFrom, seekTo);
464         userSeekPos_.emplace_back(seekFrom, seekTo);
465         lastSeekTo = seekTo;
466     }
467 }
468 
SeekIfNecessary()469 bool TesterCommon::SeekIfNecessary()
470 {
471     if (userSeekPos_.empty()) {
472         return true;
473     }
474     size_t seekFrom;
475     size_t seekTo;
476     std::tie(seekFrom, seekTo) = userSeekPos_.front();
477     if (currSampleIdx_ != seekFrom) {
478         return true;
479     }
480     LOGI("begin to seek from sample index %{public}zu to %{public}zu", seekFrom, seekTo);
481     if (!demuxer_.SeekTo(seekTo)) {
482         return true;
483     }
484     if (!Flush()) {
485         return false;
486     }
487     if (!Start()) {
488         return false;
489     }
490     userSeekPos_.pop_front();
491     return true;
492 }
493 
GetNextSample(Span dstSpan,size_t & sampleIdx,bool & isCsd)494 int TesterCommon::GetNextSample(Span dstSpan, size_t& sampleIdx, bool& isCsd)
495 {
496     optional<Sample> sample = demuxer_.PeekNextSample();
497     if (!sample.has_value()) {
498         return 0;
499     }
500     uint32_t sampleSize = sample->endPos - sample->startPos;
501     if (sampleSize > dstSpan.capacity) {
502         LOGE("sampleSize %{public}u > dst capacity %{public}zu", sampleSize, dstSpan.capacity);
503         return 0;
504     }
505     sampleIdx = sample->idx;
506     isCsd = sample->isCsd;
507     ifs_.seekg(sample->startPos);
508     ifs_.read(dstSpan.va, sampleSize);
509     return sampleSize;
510 }
511 } // namespace OHOS::MediaAVCodec