1 /*
2 * Copyright (c) 2025 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 "cj_avmetadataextractor.h"
17 #include "media_log.h"
18 #include "pixel_map_impl.h"
19
20 namespace {
21 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_METADATA, "CJAVMetadataExtractorImpl" };
22 }
23
24 namespace OHOS {
25 namespace Media {
26
CreateCString(std::string value,char ** result)27 bool CreateCString(std::string value, char** result)
28 {
29 *result = static_cast<char *>(malloc((value.size() + 1) * sizeof(char)));
30 if (*result == nullptr) {
31 return false;
32 }
33 if (memcpy_s(*result, (value.size() + 1) * sizeof(char), value.c_str(), value.size()) != 0) {
34 MEDIA_LOGE("Failed to create string.");
35 free(*result);
36 return false;
37 }
38 (*result)[value.size()] = 0;
39 return true;
40 }
41
CreateMapPair(std::string key,std::string value,char ** keyPtr,char ** valuePtr)42 bool CreateMapPair(std::string key, std::string value, char** keyPtr, char** valuePtr)
43 {
44 bool ret = CreateCString(key, keyPtr);
45 CHECK_AND_RETURN_RET_LOG(ret, ret, "Create map key failed, key %{public}s", key.c_str());
46 ret = CreateCString(value, valuePtr);
47 if (ret == false) {
48 free(*keyPtr);
49 keyPtr = nullptr;
50 }
51 return ret;
52 }
53
CreateCustomInfo(std::shared_ptr<Meta> & meta,CCustomInfo & info)54 bool CreateCustomInfo(std::shared_ptr<Meta>& meta, CCustomInfo& info)
55 {
56 bool ret = true;
57 int64_t index = 0;
58 for (auto iter = meta->begin(); iter != meta->end(); iter++) { index++; }
59 info.size = index;
60 if (index == 0) {
61 return false;
62 }
63
64 info.key = static_cast<char **>(malloc(index * sizeof(char*)));
65 if (info.key == nullptr) {
66 info.size = 0;
67 return false;
68 }
69 info.value = static_cast<char **>(malloc(index * sizeof(char*)));
70 if (info.value == nullptr) {
71 free(info.key);
72 info.size = 0;
73 return false;
74 }
75 index = 0;
76 for (auto iter = meta->begin(); iter != meta->end(); iter++) {
77 AnyValueType type = meta->GetValueType(iter->first);
78 CHECK_AND_CONTINUE_LOG(type == AnyValueType::STRING, "key %{public}s is not string", iter->first.c_str());
79 std::string sValue;
80 ret = meta->GetData(iter->first, sValue);
81 CHECK_AND_CONTINUE_LOG(ret, "GetData failed, key %{public}s", iter->first.c_str());
82 ret = CreateMapPair(iter->first, sValue, &(info.key[index]), &(info.value[index]));
83 CHECK_AND_CONTINUE_LOG(ret, "Create data failed, key %{public}s", iter->first.c_str());
84 index++;
85 }
86 return true;
87 }
88
CreateLocation(std::shared_ptr<Meta> & meta,CLocation & loc,std::string key)89 bool CreateLocation(std::shared_ptr<Meta>& meta, CLocation& loc, std::string key)
90 {
91 bool ret = true;
92 float dValue;
93 ret = meta->GetData(key, dValue);
94 CHECK_AND_RETURN_RET_LOG(ret, ret, "GetData failed, key %{public}s", key.c_str());
95 if (key == "latitude") {
96 loc.latitude = dValue;
97 }
98 if (key == "longitude") {
99 loc.longitude = dValue;
100 }
101 return ret;
102 }
103
SetHdrType(std::shared_ptr<Meta> & meta,std::string key,CAVMetadata & result)104 bool SetHdrType(std::shared_ptr<Meta>& meta, std::string key, CAVMetadata& result)
105 {
106 bool ret = true;
107 int32_t value;
108 ret = meta->GetData(key, value);
109 CHECK_AND_RETURN_RET_LOG(ret, ret, "GetData failed, key %{public}s", key.c_str());
110 result.hdrType = value;
111 return ret;
112 }
113
CAVMetadataGetStrValue(CAVMetadata & data,const std::string key)114 char** CAVMetadataGetStrValue(CAVMetadata& data, const std::string key)
115 {
116 char** ret = nullptr;
117 if (key == "album") { ret = &(data.album); }
118 if (key == "albumArtist") { ret = &(data.albumArtist); }
119 if (key == "artist") { ret = &(data.artist); }
120 if (key == "author") { ret = &(data.author); }
121 if (key == "dateTime") { ret = &(data.dateTime); }
122 if (key == "dateTimeFormat") { ret = &(data.dateTimeFormat); }
123 if (key == "composer") { ret = &(data.composer); }
124 if (key == "duration") { ret = &(data.duration); }
125 if (key == "genre") { ret = &(data.genre); }
126 if (key == "hasAudio") { ret = &(data.hasAudio); }
127 if (key == "hasVideo") { ret = &(data.hasVideo); }
128 if (key == "mimeType") { ret = &(data.mimeType); }
129 if (key == "trackCount") { ret = &(data.trackCount); }
130 if (key == "sampleRate") { ret = &(data.sampleRate); }
131 if (key == "title") { ret = &(data.title); }
132 if (key == "videoHeight") { ret = &(data.videoHeight); }
133 if (key == "videoWidth") { ret = &(data.videoWidth); }
134 if (key == "videoOrientation") { ret = &(data.videoOrientation); }
135 return ret;
136 }
137
SetMetadata(std::shared_ptr<Meta> & meta,std::string key,CAVMetadata & result)138 bool SetMetadata(std::shared_ptr<Meta>& meta, std::string key, CAVMetadata& result)
139 {
140 bool ret = true;
141 std::string sValue;
142 ret = meta->GetData(key, sValue);
143 CHECK_AND_RETURN_RET_LOG(ret, ret, "GetData failed, key %{public}s", key.c_str());
144 auto ptr = CAVMetadataGetStrValue(result, key);
145 if (ptr == nullptr) {
146 MEDIA_LOGE("GetValue failed, key %{public}s", key.c_str());
147 return false;
148 }
149 CHECK_AND_RETURN_RET_LOG(CreateCString(sValue, ptr), false,
150 "Failed to set value, key %{public}s", key.c_str());
151 return ret;
152 }
153
ConvertMemToPixelMap(std::shared_ptr<AVSharedMemory> sharedMemory)154 static std::unique_ptr<PixelMap> ConvertMemToPixelMap(std::shared_ptr<AVSharedMemory> sharedMemory)
155 {
156 CHECK_AND_RETURN_RET_LOG(sharedMemory != nullptr, nullptr, "SharedMem is nullptr");
157 MEDIA_LOGI("FetchArtPicture size: %{public}d", sharedMemory->GetSize());
158 SourceOptions sourceOptions;
159 uint32_t errorCode = 0;
160 std::unique_ptr<ImageSource> imageSource =
161 ImageSource::CreateImageSource(sharedMemory->GetBase(), sharedMemory->GetSize(), sourceOptions, errorCode);
162 CHECK_AND_RETURN_RET_LOG(imageSource != nullptr, nullptr, "Failed to create imageSource.");
163 DecodeOptions decodeOptions;
164 std::unique_ptr<PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOptions, errorCode);
165 CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, nullptr, "Failed to decode imageSource");
166 return pixelMap;
167 }
168
InitAVMetadata(CAVMetadata * data)169 void InitAVMetadata(CAVMetadata* data)
170 {
171 data->album = nullptr;
172 data->albumArtist = nullptr;
173 data->artist = nullptr;
174 data->author = nullptr;
175 data->dateTime = nullptr;
176 data->dateTimeFormat = nullptr;
177 data->composer = nullptr;
178 data->duration = nullptr;
179 data->genre = nullptr;
180 data->hasAudio = nullptr;
181 data->hasVideo = nullptr;
182 data->mimeType = nullptr;
183 data->trackCount = nullptr;
184 data->sampleRate = nullptr;
185 data->title = nullptr;
186 data->videoHeight = nullptr;
187 data->videoWidth = nullptr;
188 data->videoOrientation = nullptr;
189 data->hdrType = 0;
190 data->location.latitude = 0.0;
191 data->location.longitude = 0.0;
192 data->customInfo.key = nullptr;
193 data->customInfo.value = nullptr;
194 data->customInfo.size = 0;
195 }
196
Create()197 sptr<CJAVMetadataExtractorImpl> CJAVMetadataExtractorImpl::Create()
198 {
199 auto instance = FFI::FFIData::Create<CJAVMetadataExtractorImpl>();
200 if (instance == nullptr) {
201 MEDIA_LOGE("Failed to new CJAVMetadataExtractorImpl");
202 return nullptr;
203 }
204 instance->helper_ = AVMetadataHelperFactory::CreateAVMetadataHelper();
205 if (instance->helper_ == nullptr) {
206 MEDIA_LOGE("Failed to CreateMetadataHelper");
207 FFI::FFIData::Release(instance->GetID());
208 return nullptr;
209 }
210 return instance;
211 }
212
CJAVMetadataExtractorImpl()213 CJAVMetadataExtractorImpl::CJAVMetadataExtractorImpl()
214 {
215 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
216 }
217
~CJAVMetadataExtractorImpl()218 CJAVMetadataExtractorImpl::~CJAVMetadataExtractorImpl()
219 {
220 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
221 }
222
FetchMetadata(CAVMetadata * data)223 int32_t CJAVMetadataExtractorImpl::FetchMetadata(CAVMetadata* data)
224 {
225 bool ret = true;
226 if (data == nullptr) {
227 return MSERR_INVALID_VAL;
228 }
229 InitAVMetadata(data);
230 if (state_ != HelperState::HELPER_STATE_RUNNABLE) {
231 MEDIA_LOGE("Current state is not runnable, can't fetchFrame.");
232 return MSERR_EXT_API9_OPERATE_NOT_PERMIT;
233 }
234 auto metadata = helper_->GetAVMetadata();
235 for (const auto &key : g_Metadata) {
236 if (metadata->Find(key) == metadata->end()) {
237 MEDIA_LOGE("failed to find key: %{public}s", key.c_str());
238 continue;
239 }
240 MEDIA_LOGI("success to find key: %{public}s", key.c_str());
241 if (key == "latitude" || key == "longitude") {
242 ret = CreateLocation(metadata, data->location, key);
243 CHECK_AND_CONTINUE_LOG(ret, "GetData failed, key %{public}s", key.c_str());
244 continue;
245 }
246 if (key == "hdrType") {
247 ret = SetHdrType(metadata, key, *data);
248 CHECK_AND_CONTINUE_LOG(ret, "GetData failed, key hdrType");
249 continue;
250 }
251 if (key == "customInfo") {
252 std::shared_ptr<Meta> customData = std::make_shared<Meta>();
253 ret = metadata->GetData(key, customData);
254 CHECK_AND_CONTINUE_LOG(ret, "GetData failed, key %{public}s", key.c_str());
255 ret = CreateCustomInfo(customData, data->customInfo);
256 continue;
257 }
258 ret = SetMetadata(metadata, key, *data);
259 CHECK_AND_CONTINUE_LOG(ret, "GetData failed, key %{public}s", key.c_str());
260 }
261 return MSERR_OK;
262 }
263
FetchAlbumCover()264 int64_t CJAVMetadataExtractorImpl::FetchAlbumCover()
265 {
266 if (state_ != HelperState::HELPER_STATE_RUNNABLE) {
267 MEDIA_LOGE("Current state is not runnable, can't fetchFrame.");
268 return 0;
269 }
270 auto sharedMemory = helper_->FetchArtPicture();
271 auto pixelMap = ConvertMemToPixelMap(sharedMemory);
272 if (pixelMap == nullptr) {
273 MEDIA_LOGE("Failed to fetchAlbumCover.");
274 return 0;
275 }
276 auto result = FFI::FFIData::Create<PixelMapImpl>(move(pixelMap));
277 if (result == nullptr) {
278 return 0;
279 }
280 return result->GetID();
281 }
282
SetAVFileDescriptor(CAVFileDescriptor file)283 int32_t CJAVMetadataExtractorImpl::SetAVFileDescriptor(CAVFileDescriptor file)
284 {
285 fileDescriptor_.fd = file.fd;
286 fileDescriptor_.offset = file.offset;
287 fileDescriptor_.length = file.length;
288 MEDIA_LOGD("get fd argument, fd = %{public}d, offset = %{public}" PRIi64 ", size = %{public}" PRIi64 "",
289 fileDescriptor_.fd, fileDescriptor_.offset, fileDescriptor_.length);
290 auto res = helper_->SetSource(fileDescriptor_.fd, fileDescriptor_.offset, fileDescriptor_.length);
291 state_ = res == MSERR_OK ? HelperState::HELPER_STATE_RUNNABLE : HelperState::HELPER_ERROR;
292 return MSERR_OK;
293 }
294
GetAVFileDescriptor(CAVFileDescriptor * file)295 int32_t CJAVMetadataExtractorImpl::GetAVFileDescriptor(CAVFileDescriptor* file)
296 {
297 if (file == nullptr) {
298 return MSERR_INVALID_VAL;
299 }
300 file->fd = fileDescriptor_.fd;
301 file->offset = fileDescriptor_.offset;
302 file->length = fileDescriptor_.length;
303 return MSERR_OK;
304 }
305
SetAVDataSrcDescriptor(CAVDataSrcDescriptor data)306 int32_t CJAVMetadataExtractorImpl::SetAVDataSrcDescriptor(CAVDataSrcDescriptor data)
307 {
308 if (state_ != HelperState::HELPER_STATE_IDLE) {
309 MEDIA_LOGE("Has set source once, unsupport set again.");
310 return MSERR_OK;
311 }
312 if (helper_ == nullptr) {
313 MEDIA_LOGE("Invalid CJAVMetadataExtractorImpl.");
314 return MSERR_UNKNOWN;
315 }
316 dataSrcDescriptor_.fileSize = data.fileSize;
317 if (dataSrcDescriptor_.fileSize <= 0) {
318 return MSERR_OK;
319 }
320 MEDIA_LOGI("Recvive filesize is %{public}" PRId64 "", dataSrcDescriptor_.fileSize);
321 dataSrcDescriptor_.callback = data.callback;
322 dataSrcCb_ = std::make_shared<CJHelperDataSourceCallback>(dataSrcDescriptor_.fileSize);
323 const std::string callbackName = "readAt";
324 if (dataSrcCb_->SaveCallbackReference(callbackName, dataSrcDescriptor_.callback) != MSERR_OK) {
325 MEDIA_LOGE("Set callback failed.");
326 return MSERR_UNKNOWN;
327 }
328 auto res = helper_->SetSource(dataSrcCb_);
329 state_ = res == MSERR_OK ? HelperState::HELPER_STATE_RUNNABLE : HelperState::HELPER_ERROR;
330 MEDIA_LOGI("SetAVDataSrcDescriptor Out");
331 return MSERR_OK;
332 }
333
GetAVDataSrcDescriptor(CAVDataSrcDescriptor * data)334 int32_t CJAVMetadataExtractorImpl::GetAVDataSrcDescriptor(CAVDataSrcDescriptor* data)
335 {
336 if (data == nullptr) {
337 return MSERR_INVALID_VAL;
338 }
339 dataSrcCb_->GetSize(dataSrcDescriptor_.fileSize);
340 dataSrcCb_->GetCallbackId(dataSrcDescriptor_.callback);
341 data->fileSize = dataSrcDescriptor_.fileSize;
342 data->callback = dataSrcDescriptor_.callback;
343 return MSERR_OK;
344 }
345
Release()346 void CJAVMetadataExtractorImpl::Release()
347 {
348 if (state_ == HelperState::HELPER_STATE_RELEASED) {
349 MEDIA_LOGE("Has released once, can't release again.");
350 return;
351 }
352 if (dataSrcCb_ != nullptr) {
353 dataSrcCb_->ClearCallbackReference();
354 dataSrcCb_ = nullptr;
355 }
356 helper_->Release();
357 }
358
359 } // namespace Media
360 } // namespace OHOS
361