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