• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "hardware/imagecodec/image_codec.h"
18 #include "hardware/imagecodec/image_codec_log.h"
19 #include "image_log.h"
20 
21 namespace OHOS::ImagePlugin {
22 using namespace std;
23 
PrintAllBufferInfo()24 void ImageCodec::PrintAllBufferInfo()
25 {
26     HLOGI("------------INPUT-----------");
27     for (const BufferInfo& info : inputBufferPool_) {
28         HLOGI("inBufId = %{public}u, owner = %{public}s", info.bufferId, ToString(info.owner));
29     }
30     HLOGI("----------------------------");
31     HLOGI("------------OUTPUT----------");
32     for (const BufferInfo& info : outputBufferPool_) {
33         HLOGI("outBufId = %{public}u, owner = %{public}s", info.bufferId, ToString(info.owner));
34     }
35     HLOGI("----------------------------");
36 }
37 
CountOwner(bool isInput)38 std::array<uint32_t, ImageCodec::OWNER_CNT> ImageCodec::CountOwner(bool isInput)
39 {
40     std::array<uint32_t, OWNER_CNT> arr;
41     arr.fill(0);
42     const vector<BufferInfo>& pool = isInput ? inputBufferPool_ : outputBufferPool_;
43     for (const BufferInfo &info : pool) {
44         arr[info.owner]++;
45     }
46     return arr;
47 }
48 
ChangeOwner(BufferInfo & info,BufferOwner newOwner)49 void ImageCodec::ChangeOwner(BufferInfo& info, BufferOwner newOwner)
50 {
51     if (!debugMode_) {
52         info.owner = newOwner;
53         return;
54     }
55     BufferOwner oldOwner = info.owner;
56     const char* oldOwnerStr = ToString(oldOwner);
57     const char* newOwnerStr = ToString(newOwner);
58     const char* idStr = info.isInput ? "inBufId" : "outBufId";
59 
60     // calculate hold time
61     auto now = chrono::steady_clock::now();
62     uint64_t holdUs = static_cast<uint64_t>(
63         chrono::duration_cast<chrono::microseconds>(now - info.lastOwnerChangeTime).count());
64     double holdMs = holdUs / US_TO_MS;
65     TotalCntAndCost& holdRecord = info.isInput ? inputHoldTimeRecord_[oldOwner][newOwner] :
66                                                 outputHoldTimeRecord_[oldOwner][newOwner];
67     holdRecord.totalCnt++;
68     holdRecord.totalCostUs += holdUs;
69     double aveHoldMs = holdRecord.totalCostUs / US_TO_MS / holdRecord.totalCnt;
70 
71     // now change owner
72     info.lastOwnerChangeTime = now;
73     info.owner = newOwner;
74     std::array<uint32_t, OWNER_CNT> arr = CountOwner(info.isInput);
75     HLOGI("%{public}s = %{public}u, after hold %{public}.1f ms (%{public}.1f ms), %{public}s -> %{public}s, "
76           "%{public}u/%{public}u/%{public}u",
77           idStr, info.bufferId, holdMs, aveHoldMs, oldOwnerStr, newOwnerStr,
78           arr[OWNED_BY_US], arr[OWNED_BY_USER], arr[OWNED_BY_OMX]);
79 
80     if (info.isInput && oldOwner == OWNED_BY_US && newOwner == OWNED_BY_OMX) {
81         UpdateInputRecord(info, now);
82     }
83     if (!info.isInput && oldOwner == OWNED_BY_OMX && newOwner == OWNED_BY_US) {
84         UpdateOutputRecord(info, now);
85     }
86 }
87 
UpdateInputRecord(const BufferInfo & info,std::chrono::time_point<std::chrono::steady_clock> now)88 void ImageCodec::UpdateInputRecord(const BufferInfo& info, std::chrono::time_point<std::chrono::steady_clock> now)
89 {
90     bool cond = !info.IsValidFrame();
91     CHECK_ERROR_RETURN(cond);
92     inTimeMap_[info.omxBuffer->pts] = now;
93     if (inTotalCnt_ == 0) {
94         firstInTime_ = now;
95     }
96     inTotalCnt_++;
97 
98     uint64_t fromFirstInToNow = chrono::duration_cast<chrono::microseconds>(now - firstInTime_).count();
99     if (fromFirstInToNow == 0) {
100         HLOGI("pts = %{public}" PRId64 ", len = %{public}u, flags = 0x%{public}x",
101               info.omxBuffer->pts, info.omxBuffer->filledLen, info.omxBuffer->flag);
102     } else {
103         double inFps = inTotalCnt_ * US_TO_S / fromFirstInToNow;
104         HLOGI("pts = %{public}" PRId64 ", len = %{public}u, flags = 0x%{public}x, in fps %{public}.2f",
105               info.omxBuffer->pts, info.omxBuffer->filledLen, info.omxBuffer->flag, inFps);
106     }
107 }
108 
UpdateOutputRecord(const BufferInfo & info,std::chrono::time_point<std::chrono::steady_clock> now)109 void ImageCodec::UpdateOutputRecord(const BufferInfo& info, std::chrono::time_point<std::chrono::steady_clock> now)
110 {
111     bool cond = !info.IsValidFrame();
112     CHECK_ERROR_RETURN(cond);
113     auto it = inTimeMap_.find(info.omxBuffer->pts);
114     cond = it == inTimeMap_.end();
115     CHECK_ERROR_RETURN(cond);
116     if (outRecord_.totalCnt == 0) {
117         firstOutTime_ = now;
118     }
119     outRecord_.totalCnt++;
120 
121     uint64_t fromInToOut = chrono::duration_cast<chrono::microseconds>(now - it->second).count();
122     inTimeMap_.erase(it);
123     outRecord_.totalCostUs += fromInToOut;
124     double oneFrameCostMs = fromInToOut / US_TO_MS;
125     double averageCostMs = outRecord_.totalCostUs / US_TO_MS / outRecord_.totalCnt;
126 
127     uint64_t fromFirstOutToNow = chrono::duration_cast<chrono::microseconds>(now - firstOutTime_).count();
128     if (fromFirstOutToNow == 0) {
129         HLOGI("pts = %{public}" PRId64 ", len = %{public}u, flags = 0x%{public}x, "
130               "cost %{public}.2f ms (%{public}.2f ms)",
131               info.omxBuffer->pts, info.omxBuffer->filledLen, info.omxBuffer->flag,
132               oneFrameCostMs, averageCostMs);
133     } else {
134         double outFps = outRecord_.totalCnt * US_TO_S / fromFirstOutToNow;
135         HLOGI("pts = %{public}" PRId64 ", len = %{public}u, flags = 0x%{public}x, "
136               "cost %{public}.2f ms (%{public}.2f ms), out fps %{public}.2f",
137               info.omxBuffer->pts, info.omxBuffer->filledLen, info.omxBuffer->flag,
138               oneFrameCostMs, averageCostMs, outFps);
139     }
140 }
141 
IsValidFrame() const142 bool ImageCodec::BufferInfo::IsValidFrame() const
143 {
144     bool cond = omxBuffer->flag & OMX_BUFFERFLAG_EOS;
145     CHECK_ERROR_RETURN_RET(cond, false);
146     cond = omxBuffer->flag & OMX_BUFFERFLAG_CODECCONFIG;
147     CHECK_ERROR_RETURN_RET(cond, false);
148     cond = omxBuffer->filledLen == 0;
149     CHECK_ERROR_RETURN_RET(cond, false);
150     return true;
151 }
152 
Dump(const string & prefix,bool dumpMode) const153 void ImageCodec::BufferInfo::Dump(const string& prefix, bool dumpMode) const
154 {
155     if (dumpMode && !isInput) {
156         Dump(prefix + "_Output");
157     }
158 }
159 
Dump(const string & prefix) const160 void ImageCodec::BufferInfo::Dump(const string& prefix) const
161 {
162     if (surfaceBuffer) {
163         DumpSurfaceBuffer(prefix);
164     } else {
165         DumpLinearBuffer(prefix);
166     }
167 }
168 
DumpSurfaceBuffer(const std::string & prefix) const169 void ImageCodec::BufferInfo::DumpSurfaceBuffer(const std::string& prefix) const
170 {
171     const char* va = reinterpret_cast<const char*>(surfaceBuffer->GetVirAddr());
172     if (va == nullptr) {
173         LOGW("surface buffer has null va");
174         return;
175     }
176     bool eos = (omxBuffer->flag & OMX_BUFFERFLAG_EOS);
177     bool cond = eos || omxBuffer->filledLen == 0;
178     CHECK_ERROR_RETURN(cond);
179     int w = surfaceBuffer->GetWidth();
180     int h = surfaceBuffer->GetHeight();
181     int alignedW = surfaceBuffer->GetStride();
182     uint32_t totalSize = surfaceBuffer->GetSize();
183     if (w <= 0 || h <= 0 || alignedW <= 0 || w > alignedW) {
184         LOGW("invalid buffer dimension");
185         return;
186     }
187     std::optional<PixelFmt> fmt = TypeConverter::GraphicFmtToFmt(
188         static_cast<GraphicPixelFormat>(surfaceBuffer->GetFormat()));
189     if (fmt == nullopt) {
190         LOGW("invalid fmt=%{public}d", surfaceBuffer->GetFormat());
191         return;
192     }
193 
194     char name[128];
195     int ret = sprintf_s(name, sizeof(name), "%s/%s_%dx%d(%d)_fmt%s_pts%" PRId64 ".yuv",
196                         DUMP_PATH, prefix.c_str(), w, h, alignedW, fmt->strFmt.c_str(), omxBuffer->pts);
197     if (ret > 0) {
198         ofstream ofs(name, ios::binary);
199         if (ofs.is_open()) {
200             ofs.write(va, totalSize);
201         } else {
202             LOGW("cannot open %{public}s", name);
203         }
204     }
205     // if we unmap here, flush cache will fail
206 }
207 
DumpLinearBuffer(const string & prefix) const208 void ImageCodec::BufferInfo::DumpLinearBuffer(const string& prefix) const
209 {
210     if (imgCodecBuffer == nullptr) {
211         LOGW("invalid imgCodecBuffer");
212         return;
213     }
214     const char* va = reinterpret_cast<const char*>(imgCodecBuffer->GetAddr());
215     if (va == nullptr) {
216         LOGW("null va");
217         return;
218     }
219     bool eos = (omxBuffer->flag & OMX_BUFFERFLAG_EOS);
220     if (eos || omxBuffer->filledLen == 0) {
221         return;
222     }
223 
224     char name[128];
225     int ret = 0;
226     if (isInput) {
227         ret = sprintf_s(name, sizeof(name), "%s/%s.bin", DUMP_PATH, prefix.c_str());
228     } else {
229         ret = sprintf_s(name, sizeof(name), "%s/%s_(%d)_pts%" PRId64 ".yuv",
230                         DUMP_PATH, prefix.c_str(), imgCodecBuffer->GetStride(), omxBuffer->pts);
231     }
232     if (ret <= 0) {
233         LOGW("sprintf_s failed");
234         return;
235     }
236     std::ios_base::openmode mode = isInput ? (ios::binary | ios::app) : ios::binary;
237     ofstream ofs(name, mode);
238     if (ofs.is_open()) {
239         ofs.write(va, omxBuffer->filledLen);
240     } else {
241         LOGW("cannot open %{public}s", name);
242     }
243 }
244 } // namespace OHOS::ImagePlugin