1 /*
2 * Copyright (C) 2021 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 #define MLOG_TAG "Scanner"
16
17 #include "metadata_extractor.h"
18
19 #include <fcntl.h>
20 #include "hitrace_meter.h"
21 #include "media_log.h"
22 #include "medialibrary_db_const.h"
23 #include "medialibrary_errno.h"
24 #include "medialibrary_tracer.h"
25
26 namespace OHOS {
27 namespace Media {
28 using namespace std;
29
30 template <class Type>
stringToNum(const string & str)31 static Type stringToNum(const string &str)
32 {
33 std::istringstream iss(str);
34 Type num;
35 iss >> num;
36 return num;
37 }
38
convertTimeStr2TimeStamp(string & timeStr)39 static time_t convertTimeStr2TimeStamp(string &timeStr)
40 {
41 struct tm timeinfo;
42 strptime(timeStr.c_str(), "%Y-%m-%d %H:%M:%S", &timeinfo);
43 time_t timeStamp = mktime(&timeinfo);
44 return timeStamp;
45 }
46
ExtractImageMetadata(std::unique_ptr<Metadata> & data)47 int32_t MetadataExtractor::ExtractImageMetadata(std::unique_ptr<Metadata> &data)
48 {
49 uint32_t err = 0;
50
51 SourceOptions opts;
52 opts.formatHint = "image/" + data->GetFileExtension();
53 std::unique_ptr<ImageSource> imageSource =
54 ImageSource::CreateImageSource(data->GetFilePath(), opts, err);
55 if (err != 0 || imageSource == nullptr) {
56 MEDIA_ERR_LOG("Failed to obtain image source, err = %{public}d", err);
57 return E_OK;
58 }
59
60 ImageInfo imageInfo;
61 err = imageSource->GetImageInfo(0, imageInfo);
62 if (err == 0) {
63 data->SetFileWidth(imageInfo.size.width);
64 data->SetFileHeight(imageInfo.size.height);
65 } else {
66 MEDIA_ERR_LOG("Failed to get image info, err = %{public}d", err);
67 }
68
69 string propertyStr;
70 int64_t int64TempMeta = 0;
71 err = imageSource->GetImagePropertyString(0, MEDIA_DATA_IMAGE_DATE_TIME_ORIGINAL, propertyStr);
72 if (err == 0) {
73 int64TempMeta = convertTimeStr2TimeStamp(propertyStr);
74 if (int64TempMeta < 0) {
75 data->SetDateTaken(data->GetFileDateModified());
76 } else {
77 data->SetDateTaken(int64TempMeta);
78 }
79 } else {
80 // use modified time as date taken time when date taken not set
81 data->SetDateTaken(data->GetFileDateModified());
82 }
83
84 int32_t intTempMeta = 0;
85 err = imageSource->GetImagePropertyInt(0, MEDIA_DATA_IMAGE_ORIENTATION, intTempMeta);
86 if (err == 0) {
87 data->SetOrientation(intTempMeta);
88 }
89
90 double dbleTempMeta = -1;
91 err = imageSource->GetImagePropertyString(0, MEDIA_DATA_IMAGE_GPS_LONGITUDE, propertyStr);
92 if (err == 0) {
93 dbleTempMeta = stringToNum<double>(propertyStr);
94 data->SetLongitude(dbleTempMeta);
95 }
96
97 err = imageSource->GetImagePropertyString(0, MEDIA_DATA_IMAGE_GPS_LATITUDE, propertyStr);
98 if (err == 0) {
99 dbleTempMeta = stringToNum<double>(propertyStr);
100 data->SetLatitude(dbleTempMeta);
101 }
102
103 return E_OK;
104 }
105
FillExtractedMetadata(const std::unordered_map<int32_t,std::string> & resultMap,std::unique_ptr<Metadata> & data)106 void MetadataExtractor::FillExtractedMetadata(const std::unordered_map<int32_t, std::string> &resultMap,
107 std::unique_ptr<Metadata> &data)
108 {
109 string strTemp;
110 int32_t intTempMeta;
111 int64_t int64TempMeta;
112
113 strTemp = resultMap.at(AV_KEY_ALBUM);
114 if (strTemp != "") {
115 data->SetAlbum(strTemp);
116 }
117
118 strTemp = resultMap.at(AV_KEY_ARTIST);
119 if (strTemp != "") {
120 data->SetFileArtist(strTemp);
121 }
122
123 strTemp = resultMap.at(AV_KEY_DURATION);
124 if (strTemp != "") {
125 intTempMeta = stringToNum<int32_t>(strTemp);
126 data->SetFileDuration(intTempMeta);
127 }
128
129 strTemp = resultMap.at(AV_KEY_VIDEO_HEIGHT);
130 if (strTemp != "") {
131 intTempMeta = stringToNum<int32_t>(strTemp);
132 data->SetFileHeight(intTempMeta);
133 }
134
135 strTemp = resultMap.at(AV_KEY_VIDEO_WIDTH);
136 if (strTemp != "") {
137 intTempMeta = stringToNum<int32_t>(strTemp);
138 data->SetFileWidth(intTempMeta);
139 }
140
141 strTemp = resultMap.at(AV_KEY_MIME_TYPE);
142 if (strTemp != "") {
143 data->SetFileMimeType(strTemp);
144 }
145
146 strTemp = resultMap.at(AV_KEY_DATE_TIME_FORMAT);
147 if (strTemp != "") {
148 int64TempMeta = convertTimeStr2TimeStamp(strTemp);
149 if (int64TempMeta < 0) {
150 data->SetDateTaken(data->GetFileDateModified());
151 } else {
152 data->SetDateTaken(int64TempMeta);
153 }
154 } else {
155 // use modified time as date taken time when date taken not set
156 data->SetDateTaken(data->GetFileDateModified());
157 }
158
159 strTemp = resultMap.at(AV_KEY_VIDEO_ORIENTATION);
160 if (strTemp == "") {
161 intTempMeta = 0;
162 } else {
163 intTempMeta = stringToNum<int32_t>(strTemp);
164 }
165 data->SetOrientation(intTempMeta);
166
167 strTemp = resultMap.at(AV_KEY_TITLE);
168 if (!strTemp.empty()) {
169 data->SetFileTitle(strTemp);
170 }
171 }
172
ExtractAVMetadata(std::unique_ptr<Metadata> & data)173 int32_t MetadataExtractor::ExtractAVMetadata(std::unique_ptr<Metadata> &data)
174 {
175 MediaLibraryTracer tracer;
176 tracer.Start("ExtractAVMetadata");
177
178 tracer.Start("CreateAVMetadataHelper");
179 std::shared_ptr<AVMetadataHelper> avMetadataHelper = AVMetadataHelperFactory::CreateAVMetadataHelper();
180 tracer.Finish();
181 if (avMetadataHelper == nullptr) {
182 MEDIA_ERR_LOG("AV metadata helper is null");
183 return E_AVMETADATA;
184 }
185
186 string filePath = data->GetFilePath();
187 if(filePath.empty()){
188 MEDIA_ERR_LOG("AV metadata file path is empty");
189 return E_AVMETADATA;
190 }
191
192 int32_t fd = open(filePath.c_str(), O_RDONLY);
193 if (fd <= 0) {
194 MEDIA_ERR_LOG("Open file descriptor failed, errno = %{public}d", errno);
195 return E_SYSCALL;
196 }
197
198 struct stat64 st;
199 if (fstat64(fd, &st) != 0) {
200 MEDIA_ERR_LOG("Get file state failed for the given fd");
201 (void)close(fd);
202 return E_SYSCALL;
203 }
204
205 tracer.Start("avMetadataHelper->SetSource");
206 int32_t err = avMetadataHelper->SetSource(fd, 0, static_cast<int64_t>(st.st_size), AV_META_USAGE_META_ONLY);
207 tracer.Finish();
208 if (err != 0) {
209 MEDIA_ERR_LOG("SetSource failed for the given file descriptor, err = %{public}d", err);
210 (void)close(fd);
211 return E_AVMETADATA;
212 } else {
213 tracer.Start("avMetadataHelper->ResolveMetadata");
214 std::unordered_map<int32_t, std::string> resultMap = avMetadataHelper->ResolveMetadata();
215 tracer.Finish();
216 if (!resultMap.empty()) {
217 FillExtractedMetadata(resultMap, data);
218 }
219 }
220
221 (void)close(fd);
222
223 return E_OK;
224 }
225
Extract(std::unique_ptr<Metadata> & data)226 int32_t MetadataExtractor::Extract(std::unique_ptr<Metadata> &data)
227 {
228 if (data->GetFileMediaType() == MEDIA_TYPE_IMAGE) {
229 return ExtractImageMetadata(data);
230 } else {
231 return ExtractAVMetadata(data);
232 }
233 }
234 } // namespace Media
235 } // namespace OHOS
236