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 }