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 "mock_heif_hw_decode_flow.h"
17 #include "hardware/imagecodec/image_codec_log.h"
18 #include "media_errors.h"
19 #include <map>
20 #include <fstream>
21 #include <filesystem>
22 #include <dirent.h>
23 #include <sys/stat.h>
24 #include <algorithm>
25
26 namespace OHOS::ImagePlugin {
27 using namespace std;
28
SplitString(const std::string & src,char sep,std::vector<std::string> & vec)29 void HeifHwDecoderFlow::InputParser::SplitString(const std::string& src, char sep, std::vector<std::string>& vec)
30 {
31 vec.clear();
32 string::size_type startPos = 0;
33 while (true) {
34 string::size_type endPos = src.find_first_of(sep, startPos);
35 if (endPos == string::npos) {
36 break;
37 }
38 vec.emplace_back(src.substr(startPos, endPos - startPos));
39 startPos = endPos + 1;
40 }
41 if (startPos != string::npos) {
42 vec.emplace_back(src.substr(startPos));
43 }
44 }
45
JoinPath(const std::string & base,const std::string & append)46 std::string HeifHwDecoderFlow::InputParser::JoinPath(const std::string& base, const std::string& append)
47 {
48 return (filesystem::path(base) / append).string();
49 }
50
ParseGridInfo(GridInfo & gridInfo)51 bool HeifHwDecoderFlow::InputParser::ParseGridInfo(GridInfo& gridInfo)
52 {
53 // source_ demo:
54 // 1. has grid: 3072x4096_grid_512x512_6x8
55 // 2. no grid: 3072x4096_nogrid
56 string baseDir = filesystem::path(source_).filename().string();
57 vector<string> vec;
58 SplitString(baseDir, MAIN_SEP, vec);
59 IF_TRUE_RETURN_VAL_WITH_MSG(vec.size() < MIN_MAIN_SEG_CNT, false,
60 "invalid source: %{public}s", source_.c_str());
61
62 vector<string> vecTmp;
63 SplitString(vec[DISPLAY_SIZE], SUB_SEP, vecTmp);
64 IF_TRUE_RETURN_VAL_WITH_MSG(vecTmp.size() != SUB_SEG_CNT, false, "invalid source: %{public}s", source_.c_str());
65 gridInfo.displayWidth = static_cast<uint32_t>(stol(vecTmp[HORIZONTAL].c_str()));
66 gridInfo.displayHeight = static_cast<uint32_t>(stol(vecTmp[VERTICAL].c_str()));
67
68 if (vec[GRID_FLAG].find(NO_GRID_INDICATOR) != string::npos) {
69 gridInfo.enableGrid = false;
70 gridInfo.cols = 0;
71 gridInfo.rows = 0;
72 gridInfo.tileWidth = 0;
73 gridInfo.tileHeight = 0;
74 } else {
75 IF_TRUE_RETURN_VAL_WITH_MSG(vec.size() < MAX_MAIN_SEG_CNT, false,
76 "invalid source: %{public}s", source_.c_str());
77
78 gridInfo.enableGrid = true;
79
80 SplitString(vec[TILE_SIZE], SUB_SEP, vecTmp);
81 IF_TRUE_RETURN_VAL_WITH_MSG(vecTmp.size() != SUB_SEG_CNT, false,
82 "invalid source: %{public}s", source_.c_str());
83 gridInfo.tileWidth = static_cast<uint32_t>(stol(vecTmp[HORIZONTAL].c_str()));
84 gridInfo.tileHeight = static_cast<uint32_t>(stol(vecTmp[VERTICAL].c_str()));
85
86 SplitString(vec[GRID_SIZE], SUB_SEP, vecTmp);
87 IF_TRUE_RETURN_VAL_WITH_MSG(vecTmp.size() != SUB_SEG_CNT, false,
88 "invalid source: %{public}s", source_.c_str());
89 gridInfo.cols = static_cast<uint32_t>(stol(vecTmp[HORIZONTAL].c_str()));
90 gridInfo.rows = static_cast<uint32_t>(stol(vecTmp[VERTICAL].c_str()));
91 }
92 return true;
93 }
94
FindXpsAndIFrameFile()95 void HeifHwDecoderFlow::InputParser::FindXpsAndIFrameFile()
96 {
97 DIR *dirp = opendir(source_.c_str());
98 IF_TRUE_RETURN_VOID_WITH_MSG(dirp == nullptr, "failed to open: %{public}s, errno=%{public}d",
99 source_.c_str(), errno);
100 struct dirent *dp;
101 while ((dp = readdir(dirp)) != nullptr) {
102 if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
103 continue;
104 }
105 string path = JoinPath(source_, dp->d_name);
106 struct stat st{};
107 if (stat(path.c_str(), &st) != 0 || !S_ISREG(st.st_mode)) {
108 continue;
109 }
110 string fileName(dp->d_name);
111 if (fileName.find(XPS_INDICATOR) != string::npos) {
112 xpsFile_ = path;
113 } else if (fileName.find(I_FRAME_INDICATOR) != string::npos) {
114 iFrameFile_.emplace_back(path);
115 }
116 }
117 closedir(dirp);
118 }
119
ReadFileToVec(const string & filePath,vector<vector<uint8_t>> & inputs)120 bool HeifHwDecoderFlow::InputParser::ReadFileToVec(const string& filePath, vector<vector<uint8_t>>& inputs)
121 {
122 ifstream ifs(filePath, ios::binary);
123 IF_TRUE_RETURN_VAL_WITH_MSG(!ifs.is_open(), false, "failed to open file: %{public}s", filePath.c_str());
124
125 ifs.seekg(0, ifstream::end);
126 size_t fileSize = static_cast<size_t>(ifs.tellg());
127 ifs.seekg(0, ifstream::beg);
128
129 vector<uint8_t> vec(fileSize);
130 ifs.read(reinterpret_cast<char*>(vec.data()), static_cast<streamsize>(fileSize));
131 ifs.close();
132 inputs.emplace_back(vec);
133 return true;
134 }
135
ExtractIFrameNum(const string & filePath)136 int HeifHwDecoderFlow::InputParser::ExtractIFrameNum(const string& filePath)
137 {
138 string fileName = filesystem::path(filePath).filename().string();
139 string::size_type pos = fileName.find(I_FRAME_INDICATOR);
140 if (pos == string::npos) {
141 return -1;
142 }
143 return stoi(fileName.substr(pos + string(I_FRAME_INDICATOR).size()));
144 }
145
ReadInput(vector<vector<uint8_t>> & inputs)146 bool HeifHwDecoderFlow::InputParser::ReadInput(vector<vector<uint8_t>>& inputs)
147 {
148 FindXpsAndIFrameFile();
149 IF_TRUE_RETURN_VAL_WITH_MSG(xpsFile_.empty(), false, "no xps file in %{public}s", source_.c_str());
150 IF_TRUE_RETURN_VAL_WITH_MSG(iFrameFile_.empty(), false, "no iframe file in %{public}s", source_.c_str());
151
152 IF_TRUE_RETURN_VAL_WITH_MSG(!ReadFileToVec(xpsFile_, inputs), false,
153 "failed to read xps file: %{public}s", xpsFile_.c_str());
154 std::sort(iFrameFile_.begin(), iFrameFile_.end(), [](const string& a, const string& b) {
155 return ExtractIFrameNum(a) < ExtractIFrameNum(b);
156 });
157 for (const string& one : iFrameFile_) {
158 IF_TRUE_RETURN_VAL_WITH_MSG(!ReadFileToVec(one, inputs), false,
159 "failed to read iframe file: %{public}s", one.c_str());
160 }
161 return true;
162 }
163
~HeifHwDecoderFlow()164 HeifHwDecoderFlow::~HeifHwDecoderFlow()
165 {
166 output_ = nullptr;
167 }
168
Run(const CommandOpt & opt)169 bool HeifHwDecoderFlow::Run(const CommandOpt& opt)
170 {
171 bool ret = PrepareInput(opt.inputPath);
172 ret = ret && AllocOutput(opt.pixelFormat);
173 ret = ret && DoDecode();
174 if (ret) {
175 LOGI("demo succeed");
176 } else {
177 LOGE("demo failed");
178 }
179 return ret;
180 }
181
PrepareInput(const std::string & inputPath)182 bool HeifHwDecoderFlow::PrepareInput(const std::string& inputPath)
183 {
184 InputParser parser(inputPath);
185 bool ret = parser.ParseGridInfo(gridInfo_);
186 ret = ret && parser.ReadInput(input_);
187 return ret;
188 }
189
AllocOutput(UserPixelFormat userPixelFormat)190 bool HeifHwDecoderFlow::AllocOutput(UserPixelFormat userPixelFormat)
191 {
192 static const map<UserPixelFormat, GraphicPixelFormat> userPixelFmtToGraphicPixelFmt = {
193 { UserPixelFormat::NV12, GRAPHIC_PIXEL_FMT_YCBCR_420_SP },
194 { UserPixelFormat::NV21, GRAPHIC_PIXEL_FMT_YCRCB_420_SP },
195 { UserPixelFormat::NV12_10bit, GRAPHIC_PIXEL_FMT_YCBCR_P010 },
196 { UserPixelFormat::NV21_10bit, GRAPHIC_PIXEL_FMT_YCRCB_P010 },
197 };
198 auto iter = userPixelFmtToGraphicPixelFmt.find(userPixelFormat);
199 if (iter == userPixelFmtToGraphicPixelFmt.end()) {
200 LOGE("unsupported pixel format: %{public}d", static_cast<int>(userPixelFormat));
201 return false;
202 }
203 GraphicPixelFormat pixelFmt = iter->second;
204 output_ = hwDecoder_.AllocateOutputBuffer(gridInfo_.displayWidth, gridInfo_.displayHeight, pixelFmt);
205 if (output_ == nullptr) {
206 LOGE("failed to alloc output");
207 return false;
208 }
209 return true;
210 }
211
DoDecode()212 bool HeifHwDecoderFlow::DoDecode()
213 {
214 uint32_t ret = hwDecoder_.DoDecode(gridInfo_, input_, output_);
215 if (ret != Media::SUCCESS) {
216 LOGE("failed to decode");
217 return false;
218 }
219 return true;
220 }
221 } // namespace OHOS::ImagePlugin