• 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 <fstream>
17 #include <sstream>
18 #include "hcodec.h"
19 #include "hcodec_log.h"
20 #include "hcodec_dfx.h"
21 #include "hcodec_utils.h"
22 #include "hisysevent.h"
23 
24 namespace OHOS::MediaAVCodec {
25 using namespace std;
26 
FuncTracker(std::string value)27 FuncTracker::FuncTracker(std::string value) : value_(std::move(value))
28 {
29     PLOGI("%s >>", value_.c_str());
30 }
31 
~FuncTracker()32 FuncTracker::~FuncTracker()
33 {
34     PLOGI("%s <<", value_.c_str());
35 }
36 
OnPrintAllBufferOwner(const MsgInfo & msg)37 void HCodec::OnPrintAllBufferOwner(const MsgInfo& msg)
38 {
39     TimePoint lastOwnerChangeTime;
40     msg.param->GetValue(KEY_LAST_OWNER_CHANGE_TIME, lastOwnerChangeTime);
41     if (lastOwnerChangeTime == lastOwnerChangeTime_) {
42         UpdateOwner();  // update all owner count trace in case of systrace is catched too late
43         if (!circulateHasStopped_) {
44             HLOGW("buffer circulate stoped");
45             PrintAllBufferInfo();
46             circulateHasStopped_ = true;
47         }
48     }
49     ParamSP param = make_shared<ParamBundle>();
50     param->SetValue(KEY_LAST_OWNER_CHANGE_TIME, lastOwnerChangeTime_);
51     SendAsyncMsg(MsgWhat::PRINT_ALL_BUFFER_OWNER, param, THREE_SECONDS_IN_US);
52 }
53 
PrintAllBufferInfo()54 void HCodec::PrintAllBufferInfo()
55 {
56     auto now = chrono::steady_clock::now();
57     PrintAllBufferInfo(now, OMX_DirInput);
58     PrintAllBufferInfo(now, OMX_DirOutput);
59 }
60 
PrintAllBufferInfo(const TimePoint & now,OMX_DIRTYPE port)61 void HCodec::PrintAllBufferInfo(const TimePoint& now, OMX_DIRTYPE port)
62 {
63     const Record& record = record_[port];
64     const char* inOutStr = (port == OMX_DirInput) ? " in" : "out";
65     bool eos = (port == OMX_DirInput) ? inputPortEos_ : outputPortEos_;
66     const std::array<int, OWNER_CNT>& arr = record.currOwner_;
67     const vector<BufferInfo>& pool = (port == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
68 
69     std::stringstream s;
70     for (const BufferInfo& info : pool) {
71         int64_t holdMs = chrono::duration_cast<chrono::milliseconds>(now - info.lastOwnerChangeTime).count();
72         s << info.bufferId << ":" << ToString(info.owner) << "(" << holdMs << "), ";
73     }
74     HLOGI("%s: eos=%d, cnt=%" PRIu64 ", pts=%" PRId64 ", %d/%d/%d/%d, %s", inOutStr, eos,
75           record.frameCntTotal_, record.lastPts_,
76           arr[OWNED_BY_US], arr[OWNED_BY_USER], arr[OWNED_BY_OMX], arr[OWNED_BY_SURFACE], s.str().c_str());
77 }
78 
OnGetHidumperInfo()79 std::string HCodec::OnGetHidumperInfo()
80 {
81     auto now = chrono::steady_clock::now();
82     std::stringstream s;
83     auto getbufferCapacity = [](const std::vector<BufferInfo> &pool) -> int32_t {
84         IF_TRUE_RETURN_VAL(pool.empty(), 0);
85         IF_TRUE_RETURN_VAL(pool.front().surfaceBuffer, pool.front().surfaceBuffer->GetSize());
86         IF_TRUE_RETURN_VAL(!(pool.front().avBuffer && pool.front().avBuffer->memory_), 0);
87         return pool.front().avBuffer->memory_->GetCapacity();
88     };
89 
90     s << "        " << "[" << compUniqueStr_ << "][" << currState_->GetName() << "]" << endl;
91     s << "        " << "------------INPUT-----------" << endl;
92     s << "        " << "eos:" << inputPortEos_ << ", etb:" << record_[OMX_DirInput].frameCntTotal_
93       << ", bufferCapacity:" << getbufferCapacity(inputBufferPool_) << endl;
94     for (const BufferInfo& info : inputBufferPool_) {
95         int64_t holdMs = chrono::duration_cast<chrono::milliseconds>(now - info.lastOwnerChangeTime).count();
96         s << "        " << "inBufId = " << info.bufferId << ", owner = " << ToString(info.owner);
97         if (info.hasSwapedOut) {
98             s << ", hasSwapedOut = " << info.hasSwapedOut << ", nextOwner = " << ToString(info.nextStepOwner);
99         }
100         s << ", holdMs = " << holdMs << endl;
101     }
102     s << "        " << "----------------------------" << endl;
103     s << "        " << "------------OUTPUT----------" << endl;
104     s << "        " << "eos:" << outputPortEos_ << ", fbd:" << record_[OMX_DirOutput].frameCntTotal_
105       << ", bufferCapacity:" << getbufferCapacity(outputBufferPool_) << endl;
106     for (const BufferInfo& info : outputBufferPool_) {
107         int fd = info.surfaceBuffer == nullptr ? -1 : info.surfaceBuffer->GetFileDescriptor();
108         int64_t holdMs = chrono::duration_cast<chrono::milliseconds>(now - info.lastOwnerChangeTime).count();
109         s << "        " << "outBufId = " << info.bufferId << ", fd = " << fd << ", owner = " << ToString(info.owner);
110         if (info.hasSwapedOut) {
111             s << ", hasSwapedOut = " << info.hasSwapedOut << ", nextOwner = " << ToString(info.nextStepOwner);
112         }
113         s << ", holdMs = " << holdMs << endl;
114     }
115     s << "        " << "----------------------------" << endl << endl;
116     return s.str();
117 }
118 
UpdateOwner()119 void HCodec::UpdateOwner()
120 {
121     UpdateOwner(OMX_DirInput);
122     UpdateOwner(OMX_DirOutput);
123 }
124 
FaultEventWrite(const string & faultType,const std::string & msg)125 void HCodec::FaultEventWrite(const string& faultType, const std::string& msg)
126 {
127     HiSysEventWrite(HISYSEVENT_DOMAIN_HCODEC, "FAULT",
128                     OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
129                     "MODULE", "HardwareDecoder",
130                     "FAULTTYPE", faultType,
131                     "MSG", msg);
132 }
133 
UpdateOwner(OMX_DIRTYPE port)134 void HCodec::UpdateOwner(OMX_DIRTYPE port)
135 {
136     std::array<int, OWNER_CNT>& arr = record_[port].currOwner_;
137     const vector<BufferInfo>& pool = (port == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
138 
139     arr.fill(0);
140     for (const BufferInfo &info : pool) {
141         arr[info.owner]++;
142     }
143     for (uint32_t owner = 0; owner < static_cast<uint32_t>(OWNER_CNT); owner++) {
144         CountTrace(HITRACE_TAG_ZMEDIA, record_[port].ownerTraceTag_[owner], arr[owner]);
145     }
146 }
147 
ReduceOwner(OMX_DIRTYPE port,BufferOwner owner)148 void HCodec::ReduceOwner(OMX_DIRTYPE port, BufferOwner owner)
149 {
150     Record& record = record_[port];
151     record.currOwner_[owner]--;
152     CountTrace(HITRACE_TAG_ZMEDIA, record.ownerTraceTag_[owner], record.currOwner_[owner]);
153 }
154 
ChangeOwner(BufferInfo & info,BufferOwner newOwner)155 void HCodec::ChangeOwner(BufferInfo& info, BufferOwner newOwner)
156 {
157     auto now = chrono::steady_clock::now();
158     OMX_DIRTYPE port = info.isInput ? OMX_DirInput : OMX_DirOutput;
159     Record& record = record_[port];
160     std::array<int, OWNER_CNT>& currOwner = record.currOwner_;
161     BufferOwner oldOwner = info.owner;
162     if (!record.beginOfInterval_.has_value()) {
163         record.ResetInterval(now);
164     }
165 
166     UpdateHoldCnt(now, port, oldOwner);
167     UpdateHoldCnt(now, port, newOwner);
168     UpdateHoldTime(now, info, newOwner);
169 
170     // now change owner
171     currOwner[oldOwner]--;
172     currOwner[newOwner]++;
173     info.owner = newOwner;
174     info.lastOwnerChangeTime = now;
175     record.lastOwnerChangeTime_[oldOwner] = now;
176     record.lastOwnerChangeTime_[newOwner] = now;
177     lastOwnerChangeTime_ = now;
178     if (circulateHasStopped_) {
179         HLOGI("circulate resume, %s, %s -> %s, pts=%" PRId64,
180             (info.isInput ? "in" : "out"), ToString(oldOwner), ToString(newOwner), info.omxBuffer->pts);
181         circulateHasStopped_ = false;
182     }
183 
184     CountTrace(HITRACE_TAG_ZMEDIA, record.ownerTraceTag_[oldOwner], currOwner[oldOwner]);
185     CountTrace(HITRACE_TAG_ZMEDIA, record.ownerTraceTag_[newOwner], currOwner[newOwner]);
186 
187     if (info.isInput && oldOwner == OWNED_BY_US && newOwner == OWNED_BY_OMX) {
188         record.frameCntTotal_++;
189         record.frameCntInterval_++;
190         record.frameMbitsInterval_ += info.omxBuffer->filledLen * BYTE_TO_MBIT;
191         record.lastPts_ = info.omxBuffer->pts;
192         debugMode_ ? UpdateInputRecord(now, info) : PrintStatistic(now, port);
193     }
194     if (!info.isInput && oldOwner == OWNED_BY_US && newOwner == OWNED_BY_USER) {
195         record.frameCntTotal_++;
196         record.frameCntInterval_++;
197         record.frameMbitsInterval_ += info.omxBuffer->filledLen * BYTE_TO_MBIT;
198         record.lastPts_ = info.omxBuffer->pts;
199         debugMode_ ? UpdateOutputRecord(now, info) : PrintStatistic(now, port);
200     }
201 }
202 
203 // now, on this port, this owner's hold cnt is gonna change
UpdateHoldCnt(const TimePoint & now,OMX_DIRTYPE port,BufferOwner owner)204 void HCodec::UpdateHoldCnt(const TimePoint& now, OMX_DIRTYPE port, BufferOwner owner)
205 {
206     Record& record = record_[port];
207     if (!record.lastOwnerChangeTime_[owner].has_value()) {
208         return;
209     }
210     auto holdUs = chrono::duration_cast<chrono::microseconds>(
211         now - record.lastOwnerChangeTime_[owner].value()).count();
212     if (holdUs < 0) {
213         HLOGW("steady clock has go backwards, %ld us", holdUs);
214         record.ResetInterval(now);
215         return;
216     }
217     TotalEvent& holdCnt = record.holdCntInterval_[owner];
218     holdCnt.eventCnt += static_cast<uint64_t>(holdUs);
219     holdCnt.eventSum += (static_cast<uint64_t>(holdUs) *
220                          static_cast<uint64_t>(record.currOwner_[owner]));
221 }
222 
223 // now, this buffer is gonna change to new owner
UpdateHoldTime(const TimePoint & now,const BufferInfo & info,BufferOwner newOwner)224 void HCodec::UpdateHoldTime(const TimePoint& now, const BufferInfo& info, BufferOwner newOwner)
225 {
226     Record& record = record_[info.isInput ? OMX_DirInput : OMX_DirOutput];
227     auto holdUs = chrono::duration_cast<chrono::microseconds>(now - info.lastOwnerChangeTime).count();
228     if (holdUs < 0) {
229         HLOGW("steady clock has go backwards, %ld us", holdUs);
230         record.ResetInterval(now);
231         return;
232     }
233     BufferOwner oldOwner = info.owner;
234     TotalEvent& oldOwnerHoldTime = record.holdTimeInterval_[oldOwner];
235     oldOwnerHoldTime.eventCnt++;
236     oldOwnerHoldTime.eventSum += static_cast<uint64_t>(holdUs);
237     if (debugMode_) {
238         std::array<int, OWNER_CNT> currOwner = record.currOwner_;
239         currOwner[oldOwner]--;
240         currOwner[newOwner]++;
241         HLOGI("%s = %u, after hold %.1f ms, %s -> %s, %d/%d/%d/%d", (info.isInput ? "inBufId" : "outBufId"),
242             info.bufferId, holdUs / US_TO_MS, ToString(oldOwner), ToString(newOwner),
243             currOwner[OWNED_BY_US], currOwner[OWNED_BY_USER], currOwner[OWNED_BY_OMX], currOwner[OWNED_BY_SURFACE]);
244     }
245 }
246 
CalculateInterval(const TimePoint & now,OMX_DIRTYPE port,IntervalAverage & ave)247 bool HCodec::CalculateInterval(const TimePoint& now, OMX_DIRTYPE port, IntervalAverage& ave)
248 {
249     Record& record = record_[port];
250     auto fromBeginOfIntervalToNowUs = chrono::duration_cast<chrono::microseconds>(
251         now - record.beginOfInterval_.value()).count();
252     if (fromBeginOfIntervalToNowUs < 0) {
253         HLOGW("steady clock has go backwards, %ld us", fromBeginOfIntervalToNowUs);
254         record.ResetInterval(now);
255         return false;
256     }
257     if (fromBeginOfIntervalToNowUs == 0) {
258         return false;
259     }
260 
261     ave.fps = record.frameCntInterval_ * US_TO_S / fromBeginOfIntervalToNowUs;
262     ave.mbps = record.frameMbitsInterval_ * US_TO_S / fromBeginOfIntervalToNowUs;
263     for (uint32_t owner = 0; owner < static_cast<uint32_t>(OWNER_CNT); owner++) {
264         const TotalEvent& holdCnt = record.holdCntInterval_[owner];
265         ave.holdCnt[owner] = (holdCnt.eventCnt == 0) ? 0 :
266             static_cast<double>(holdCnt.eventSum) / holdCnt.eventCnt;
267         const TotalEvent& holdTime = record.holdTimeInterval_[owner];
268         ave.holdMs[owner] = (holdTime.eventCnt == 0) ? -1 :
269             (holdTime.eventSum / US_TO_MS / holdTime.eventCnt);
270     }
271     return true;
272 }
273 
PrintStatistic(const TimePoint & now,OMX_DIRTYPE port)274 void HCodec::PrintStatistic(const TimePoint& now, OMX_DIRTYPE port)
275 {
276     Record& record = record_[port];
277     if (record.frameCntInterval_ % PRINT_PER_FRAME != 0) {
278         return;
279     }
280     IntervalAverage ave;
281     bool ret = CalculateInterval(now, port, ave);
282     if (!ret) {
283         return;
284     }
285     const char* inOutStr = (port == OMX_DirInput) ? " in" : "out";
286     HLOGI("%s: fps=%.1f, Mbps=%.1f, cnt=%" PRIu64 ", pts=%" PRId64 ", %.1f/%.1f/%.1f/%.1f, %.0f/%.0f/%.0f/%.0f, "
287         "fence %.3f, discard %.0f%%", inOutStr, ave.fps, ave.mbps, record.frameCntTotal_, record.lastPts_,
288         ave.holdCnt[OWNED_BY_US], ave.holdCnt[OWNED_BY_USER], ave.holdCnt[OWNED_BY_OMX], ave.holdCnt[OWNED_BY_SURFACE],
289         ave.holdMs[OWNED_BY_US], ave.holdMs[OWNED_BY_USER], ave.holdMs[OWNED_BY_OMX], ave.holdMs[OWNED_BY_SURFACE],
290         record.waitFenceCostUsInterval_ / US_TO_MS / PRINT_PER_FRAME,
291         static_cast<double>(record.discardCntInterval_) / PRINT_PER_FRAME * 100); // 100: percent
292     record.ResetInterval(now);
293 }
294 
UpdateInputRecord(const TimePoint & now,const BufferInfo & info)295 void HCodec::UpdateInputRecord(const TimePoint& now, const BufferInfo& info)
296 {
297     if (!info.IsValidFrame()) {
298         return;
299     }
300     inTimeMap_[info.omxBuffer->pts] = now;
301     Record& record = record_[info.isInput ? OMX_DirInput : OMX_DirOutput];
302     auto fromBeginOfIntervalToNowUs = chrono::duration_cast<chrono::microseconds>(
303         now - record.beginOfInterval_.value()).count();
304     if (fromBeginOfIntervalToNowUs < 0) {
305         HLOGW("steady clock has go backwards, %ld us", fromBeginOfIntervalToNowUs);
306         record.ResetInterval(now);
307         return;
308     }
309     if (fromBeginOfIntervalToNowUs == 0) {
310         HLOGI("pts = %" PRId64 ", len = %u, flags = 0x%x",
311               info.omxBuffer->pts, info.omxBuffer->filledLen, info.omxBuffer->flag);
312     } else {
313         double inFps = record.frameCntInterval_ * US_TO_S / fromBeginOfIntervalToNowUs;
314         HLOGI("pts = %" PRId64 ", len = %u, flags = 0x%x, in fps %.2f",
315               info.omxBuffer->pts, info.omxBuffer->filledLen, info.omxBuffer->flag, inFps);
316     }
317 }
318 
UpdateOutputRecord(const TimePoint & now,const BufferInfo & info)319 void HCodec::UpdateOutputRecord(const TimePoint& now, const BufferInfo& info)
320 {
321     if (!info.IsValidFrame()) {
322         return;
323     }
324     auto it = inTimeMap_.find(info.omxBuffer->pts);
325     if (it == inTimeMap_.end()) {
326         return;
327     }
328     Record& record = record_[info.isInput ? OMX_DirInput : OMX_DirOutput];
329     auto fromInToOut = chrono::duration_cast<chrono::microseconds>(now - it->second).count();
330     inTimeMap_.erase(it);
331     if (fromInToOut < 0) {
332         HLOGW("steady clock has go backwards, %ld us", fromInToOut);
333         record.ResetInterval(now);
334         return;
335     }
336     onePtsInToOutTotalCostUs_ += static_cast<uint64_t>(fromInToOut);
337     double oneFrameCostMs = fromInToOut / US_TO_MS;
338     double averageCostMs = onePtsInToOutTotalCostUs_ / US_TO_MS / record.frameCntInterval_;
339 
340     auto fromBeginOfIntervalToNowUs = chrono::duration_cast<chrono::microseconds>(
341         now - record.beginOfInterval_.value()).count();
342     if (fromBeginOfIntervalToNowUs < 0) {
343         HLOGW("steady clock has go backwards, %ld us", fromBeginOfIntervalToNowUs);
344         record.ResetInterval(now);
345         return;
346     }
347     if (fromBeginOfIntervalToNowUs == 0) {
348         HLOGI("pts = %" PRId64 ", len = %u, flags = 0x%x, "
349               "cost %.2f ms (%.2f ms)",
350               info.omxBuffer->pts, info.omxBuffer->filledLen, info.omxBuffer->flag,
351               oneFrameCostMs, averageCostMs);
352     } else {
353         double outFps = record.frameCntInterval_ * US_TO_S / fromBeginOfIntervalToNowUs;
354         HLOGI("pts = %" PRId64 ", len = %u, flags = 0x%x, "
355               "cost %.2f ms (%.2f ms), out fps %.2f",
356               info.omxBuffer->pts, info.omxBuffer->filledLen, info.omxBuffer->flag,
357               oneFrameCostMs, averageCostMs, outFps);
358     }
359 }
360 
IsValidFrame() const361 bool HCodec::BufferInfo::IsValidFrame() const
362 {
363     if (omxBuffer->flag & OMX_BUFFERFLAG_EOS) {
364         return false;
365     }
366     if (omxBuffer->flag & OMX_BUFFERFLAG_CODECCONFIG) {
367         return false;
368     }
369     if (omxBuffer->filledLen == 0) {
370         return false;
371     }
372     return true;
373 }
374 
375 #ifdef BUILD_ENG_VERSION
Dump(const string & prefix,uint64_t cnt,DumpMode dumpMode,bool isEncoder) const376 void HCodec::BufferInfo::Dump(const string& prefix, uint64_t cnt, DumpMode dumpMode, bool isEncoder) const
377 {
378     if (isInput) {
379         if (((dumpMode & DUMP_ENCODER_INPUT) && isEncoder) ||
380             ((dumpMode & DUMP_DECODER_INPUT) && !isEncoder)) {
381             Dump(prefix + "_Input", cnt);
382         }
383     } else {
384         if (((dumpMode & DUMP_ENCODER_OUTPUT) && isEncoder) ||
385             ((dumpMode & DUMP_DECODER_OUTPUT) && !isEncoder)) {
386             Dump(prefix + "_Output", cnt);
387         }
388     }
389 }
390 
Dump(const string & prefix,uint64_t cnt) const391 void HCodec::BufferInfo::Dump(const string& prefix, uint64_t cnt) const
392 {
393     if (surfaceBuffer) {
394         DumpSurfaceBuffer(prefix, cnt);
395     } else {
396         DumpLinearBuffer(prefix);
397     }
398 }
399 
DumpSurfaceBuffer(const std::string & prefix,uint64_t cnt) const400 void HCodec::BufferInfo::DumpSurfaceBuffer(const std::string& prefix, uint64_t cnt) const
401 {
402     if (omxBuffer->filledLen == 0) {
403         return;
404     }
405     const char* va = reinterpret_cast<const char*>(surfaceBuffer->GetVirAddr());
406     IF_TRUE_RETURN_VOID_WITH_MSG(va == nullptr, "null va");
407     int w = surfaceBuffer->GetWidth();
408     int h = surfaceBuffer->GetHeight();
409     int byteStride = surfaceBuffer->GetStride();
410     IF_TRUE_RETURN_VOID_WITH_MSG(byteStride == 0, "stride 0");
411     int alignedH = h;
412     uint32_t totalSize = surfaceBuffer->GetSize();
413     uint32_t seq = surfaceBuffer->GetSeqNum();
414     GraphicPixelFormat graphicFmt = static_cast<GraphicPixelFormat>(surfaceBuffer->GetFormat());
415     std::optional<PixelFmt> fmt = TypeConverter::GraphicFmtToFmt(graphicFmt);
416     IF_TRUE_RETURN_VOID_WITH_MSG(!fmt.has_value(), "unknown fmt %d", graphicFmt);
417 
418     string suffix;
419     bool dumpAsVideo = true;
420     DecideDumpInfo(alignedH, totalSize, suffix, dumpAsVideo);
421 
422     char name[128];
423     int ret = 0;
424     if (dumpAsVideo) {
425         ret = sprintf_s(name, sizeof(name), "%s/%s_%dx%d(%dx%d)_fmt%s.%s",
426                         DUMP_PATH, prefix.c_str(), w, h, byteStride, alignedH,
427                         fmt->strFmt.c_str(), suffix.c_str());
428     } else {
429         ret = sprintf_s(name, sizeof(name), "%s/%s_%" PRIu64 "_%dx%d(%d)_fmt%s_pts%" PRId64 "_seq%u.%s",
430                         DUMP_PATH, prefix.c_str(), cnt, w, h, byteStride,
431                         fmt->strFmt.c_str(), omxBuffer->pts, seq, suffix.c_str());
432     }
433     if (ret > 0) {
434         ofstream ofs(name, ios::binary | ios::app);
435         if (ofs.is_open()) {
436             ofs.write(va, totalSize);
437         } else {
438             LOGW("cannot open %s", name);
439         }
440     }
441     // if we unmap here, flush cache will fail
442 }
443 
DecideDumpInfo(int & alignedH,uint32_t & totalSize,string & suffix,bool & dumpAsVideo) const444 void HCodec::BufferInfo::DecideDumpInfo(int& alignedH, uint32_t& totalSize, string& suffix, bool& dumpAsVideo) const
445 {
446     int h = surfaceBuffer->GetHeight();
447     int byteStride = surfaceBuffer->GetStride();
448     GraphicPixelFormat fmt = static_cast<GraphicPixelFormat>(surfaceBuffer->GetFormat());
449     switch (fmt) {
450         case GRAPHIC_PIXEL_FMT_YCBCR_420_P:
451         case GRAPHIC_PIXEL_FMT_YCRCB_420_SP:
452         case GRAPHIC_PIXEL_FMT_YCBCR_420_SP:
453         case GRAPHIC_PIXEL_FMT_YCBCR_P010:
454         case GRAPHIC_PIXEL_FMT_YCRCB_P010: {
455             OH_NativeBuffer_Planes *planes = nullptr;
456             GSError err = surfaceBuffer->GetPlanesInfo(reinterpret_cast<void**>(&planes));
457             if (err != GSERROR_OK || planes == nullptr) { // compressed
458                 suffix = "bin";
459                 dumpAsVideo = false;
460                 return;
461             }
462             alignedH = static_cast<int32_t>(static_cast<int64_t>(planes->planes[1].offset) / byteStride);
463             totalSize = GetYuv420Size(byteStride, alignedH);
464             suffix = "yuv";
465             break;
466         }
467         case GRAPHIC_PIXEL_FMT_RGBA_1010102:
468         case GRAPHIC_PIXEL_FMT_RGBA_8888: {
469             totalSize = static_cast<uint32_t>(byteStride * h);
470             suffix = "rgba";
471             break;
472         }
473         default: {
474             suffix = "bin";
475             dumpAsVideo = false;
476             break;
477         }
478     }
479 }
480 
DumpLinearBuffer(const string & prefix) const481 void HCodec::BufferInfo::DumpLinearBuffer(const string& prefix) const
482 {
483     if (omxBuffer->filledLen == 0) {
484         return;
485     }
486     if (avBuffer == nullptr || avBuffer->memory_ == nullptr) {
487         LOGW("invalid avbuffer");
488         return;
489     }
490     const char* va = reinterpret_cast<const char*>(avBuffer->memory_->GetAddr());
491     if (va == nullptr) {
492         LOGW("null va");
493         return;
494     }
495 
496     char name[128];
497     int ret = sprintf_s(name, sizeof(name), "%s/%s.bin", DUMP_PATH, prefix.c_str());
498     if (ret <= 0) {
499         LOGW("sprintf_s failed");
500         return;
501     }
502     ofstream ofs(name, ios::binary | ios::app);
503     if (ofs.is_open()) {
504         ofs.write(va, omxBuffer->filledLen);
505     } else {
506         LOGW("cannot open %s", name);
507     }
508 }
509 #endif // BUILD_ENG_VERSION
510 }