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 "avmetadatahelper_impl.h"
17 
18 #include "common/media_source.h"
19 #include "media_errors.h"
20 #include "media_log.h"
21 #include "media_description.h"
22 #include "meta_utils.h"
23 #include "uri_helper.h"
24 #include "pipeline/pipeline.h"
25 #include "osal/task/pipeline_threadpool.h"
26 #include "pts_and_index_conversion.h"
27 
28 namespace {
29 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_METADATA, "AVMetadataHelperImpl" };
30 }
31 
32 namespace OHOS {
33 namespace Media {
OnError(MediaAVCodec::AVCodecErrorType errorType,int32_t errorCode)34 void AVMetadataHelperImpl::OnError(MediaAVCodec::AVCodecErrorType errorType, int32_t errorCode)
35 {
36     MEDIA_LOGE("OnError errorType:%{public}d, errorCode:%{public}d", static_cast<int32_t>(errorType), errorCode);
37     stopProcessing_ = true;
38 }
39 
AVMetadataHelperImpl()40 AVMetadataHelperImpl::AVMetadataHelperImpl()
41 {
42     MEDIA_LOGD("Constructor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
43     groupId_ = std::string("AVMeta_") + std::to_string(Pipeline::Pipeline::GetNextPipelineId());
44 }
45 
~AVMetadataHelperImpl()46 AVMetadataHelperImpl::~AVMetadataHelperImpl()
47 {
48     MEDIA_LOGD("Destructor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
49     Destroy();
50 }
51 
SetSource(const std::string & uri,int32_t usage)52 int32_t AVMetadataHelperImpl::SetSource(const std::string &uri, int32_t usage)
53 {
54     UriHelper uriHelper(uri);
55     if (uriHelper.UriType() != UriHelper::URI_TYPE_FILE && uriHelper.UriType() != UriHelper::URI_TYPE_FD) {
56         MEDIA_LOGE("Unsupported uri type : %{private}s", uri.c_str());
57         return MSERR_UNSUPPORT;
58     }
59 
60     MEDIA_LOGD("0x%{public}06" PRIXPTR " SetSource uri: %{private}s, type:%{public}d", FAKE_POINTER(this), uri.c_str(),
61         uriHelper.UriType());
62 
63     auto ret = SetSourceInternel(uri, usage == AVMetadataUsage::AV_META_USAGE_FRAME_INDEX_CONVERT);
64     CHECK_AND_RETURN_RET_LOG(usage != AVMetadataUsage::AV_META_USAGE_FRAME_INDEX_CONVERT, static_cast<int32_t>(ret),
65                              "ret = %{public}d", static_cast<int32_t>(ret));
66     CHECK_AND_RETURN_RET_LOG(ret == Status::OK, MSERR_INVALID_VAL,
67         "0x%{public}06" PRIXPTR " Failed to call SetSourceInternel", FAKE_POINTER(this));
68     CHECK_AND_RETURN_RET_LOG(MetaUtils::CheckFileType(mediaDemuxer_->GetGlobalMetaInfo()),
69         MSERR_UNSUPPORT, "0x%{public}06" PRIXPTR "SetSource unsupport", FAKE_POINTER(this));
70     return MSERR_OK;
71 }
72 
SetSource(const std::shared_ptr<IMediaDataSource> & dataSrc)73 int32_t AVMetadataHelperImpl::SetSource(const std::shared_ptr<IMediaDataSource> &dataSrc)
74 {
75     MEDIA_LOGI("0x%{public}06" PRIXPTR "SetSource dataSrc", FAKE_POINTER(this));
76     Status ret = SetSourceInternel(dataSrc);
77     CHECK_AND_RETURN_RET_LOG(ret == Status::OK, MSERR_INVALID_VAL, "Failed to call SetSourceInternel");
78 
79     CHECK_AND_RETURN_RET_LOG(MetaUtils::CheckFileType(mediaDemuxer_->GetGlobalMetaInfo()),
80         MSERR_UNSUPPORT, "0x%{public}06" PRIXPTR "SetSource unsupport", FAKE_POINTER(this));
81     MEDIA_LOGI("0x%{public}06" PRIXPTR "set source success", FAKE_POINTER(this));
82     return MSERR_OK;
83 }
84 
SetSourceInternel(const std::string & uri,bool isForFrameConvert)85 Status AVMetadataHelperImpl::SetSourceInternel(const std::string &uri, bool isForFrameConvert)
86 {
87     CHECK_AND_RETURN_RET_LOG(!isForFrameConvert, SetSourceForFrameConvert(uri), "SetSource for frame convert");
88     Reset();
89     mediaDemuxer_ = std::make_shared<MediaDemuxer>();
90     mediaDemuxer_->SetEnableOnlineFdCache(false);
91     mediaDemuxer_->SetInterruptState(isInterruptNeeded_.load());
92     mediaDemuxer_->SetPlayerId(groupId_);
93     CHECK_AND_RETURN_RET_LOG(
94         mediaDemuxer_ != nullptr, Status::ERROR_INVALID_DATA, "SetSourceInternel demuxer is nullptr");
95     Status ret = mediaDemuxer_->SetDataSource(std::make_shared<MediaSource>(uri));
96     CHECK_AND_RETURN_RET_LOG(ret == Status::OK, ret,
97         "0x%{public}06" PRIXPTR " SetSourceInternel demuxer failed to call SetDataSource", FAKE_POINTER(this));
98     return Status::OK;
99 }
100 
SetSourceForFrameConvert(const std::string & uri)101 Status AVMetadataHelperImpl::SetSourceForFrameConvert(const std::string &uri)
102 {
103     Reset();
104     isForFrameConvert_ = true;
105     conversion_ = std::make_shared<TimeAndIndexConversion>();
106     CHECK_AND_RETURN_RET_LOG(
107         conversion_ != nullptr, Status::ERROR_NO_MEMORY, "SetSourceInternel conversion_ is nullptr");
108     Status ret = conversion_->SetDataSource(std::make_shared<MediaSource>(uri));
109     CHECK_AND_RETURN_RET_LOG(ret == Status::OK, ret,
110         "0x%{public}06" PRIXPTR " SetSourceInternel conversion_ failed", FAKE_POINTER(this));
111     return Status::OK;
112 }
113 
SetSourceInternel(const std::shared_ptr<IMediaDataSource> & dataSrc)114 Status AVMetadataHelperImpl::SetSourceInternel(const std::shared_ptr<IMediaDataSource> &dataSrc)
115 {
116     Reset();
117     mediaDemuxer_ = std::make_shared<MediaDemuxer>();
118     mediaDemuxer_->SetPlayerId(groupId_);
119     CHECK_AND_RETURN_RET_LOG(
120         mediaDemuxer_ != nullptr, Status::ERROR_INVALID_DATA, "SetSourceInternel demuxer is nullptr");
121     Status ret = mediaDemuxer_->SetDataSource(std::make_shared<MediaSource>(dataSrc));
122     CHECK_AND_RETURN_RET_LOG(ret == Status::OK, ret, "Failed to call SetDataSource");
123     return Status::OK;
124 }
125 
ResolveMetadata(int32_t key)126 std::string AVMetadataHelperImpl::ResolveMetadata(int32_t key)
127 {
128     MEDIA_LOGI("enter ResolveMetadata with key: %{public}d", key);
129     auto res = InitMetadataCollector();
130     CHECK_AND_RETURN_RET(res == Status::OK, "");
131     return metadataCollector_->ExtractMetadata(key);
132 }
133 
ResolveMetadata()134 std::unordered_map<int32_t, std::string> AVMetadataHelperImpl::ResolveMetadata()
135 {
136     MEDIA_LOGD("enter ResolveMetadata");
137     auto res = InitMetadataCollector();
138     CHECK_AND_RETURN_RET(res == Status::OK, {});
139     return metadataCollector_->ExtractMetadata();
140 }
141 
FetchArtPicture()142 std::shared_ptr<AVSharedMemory> AVMetadataHelperImpl::FetchArtPicture()
143 {
144     MEDIA_LOGI("0x%{public}06" PRIXPTR " enter FetchArtPicture", FAKE_POINTER(this));
145     auto res = InitMetadataCollector();
146     CHECK_AND_RETURN_RET(res == Status::OK, nullptr);
147     return metadataCollector_->GetArtPicture();
148 }
149 
GetAVMetadata()150 std::shared_ptr<Meta> AVMetadataHelperImpl::GetAVMetadata()
151 {
152     MEDIA_LOGE("enter GetAVMetadata");
153     auto res = InitMetadataCollector();
154     CHECK_AND_RETURN_RET(res == Status::OK, nullptr);
155     return metadataCollector_->GetAVMetadata();
156 }
157 
FetchFrameAtTime(int64_t timeUs,int32_t option,const OutputConfiguration & param)158 std::shared_ptr<AVSharedMemory> AVMetadataHelperImpl::FetchFrameAtTime(
159     int64_t timeUs, int32_t option, const OutputConfiguration &param)
160 {
161     MEDIA_LOGD("enter FetchFrameAtTime");
162     auto res = InitThumbnailGenerator();
163     CHECK_AND_RETURN_RET(res == Status::OK, nullptr);
164     return thumbnailGenerator_->FetchFrameAtTime(timeUs, option, param);
165 }
166 
GetTimeByFrameIndex(uint32_t index,uint64_t & time)167 int32_t AVMetadataHelperImpl::GetTimeByFrameIndex(uint32_t index, uint64_t &time)
168 {
169     CHECK_AND_RETURN_RET(!isForFrameConvert_, GetTimeForFrameConvert(index, time));
170     auto res = InitMetadataCollector();
171     CHECK_AND_RETURN_RET_LOG(res == Status::OK, MSERR_INVALID_STATE, "Create collector failed");
172     return metadataCollector_->GetTimeByFrameIndex(index, time);
173 }
174 
GetFrameIndexByTime(uint64_t time,uint32_t & index)175 int32_t AVMetadataHelperImpl::GetFrameIndexByTime(uint64_t time, uint32_t &index)
176 {
177     CHECK_AND_RETURN_RET(!isForFrameConvert_, GetIndexForFrameConvert(time, index));
178     auto res = InitMetadataCollector();
179     CHECK_AND_RETURN_RET_LOG(res == Status::OK, MSERR_INVALID_STATE, "Create collector failed");
180     return metadataCollector_->GetFrameIndexByTime(time, index);
181 }
182 
GetTimeForFrameConvert(uint32_t index,uint64_t & time)183 int32_t AVMetadataHelperImpl::GetTimeForFrameConvert(uint32_t index, uint64_t &time)
184 {
185     CHECK_AND_RETURN_RET_LOG(conversion_ != nullptr, MSERR_INVALID_STATE, "conversion_ is nullptr");
186     uint32_t trackIndex = 0;
187     auto res = conversion_->GetFirstVideoTrackIndex(trackIndex);
188     CHECK_AND_RETURN_RET_LOG(res == Status::OK, MSERR_UNSUPPORT_FILE, "GetFirstVideoTrackIndex failed");
189     res = conversion_->GetRelativePresentationTimeUsByIndex(trackIndex, index, time);
190     MEDIA_LOGI("trackIndex: %{public}" PRIu32 ", index: %{public}" PRIu32 ", time: %{public}" PRIu64
191                 ", res: %{public}d", trackIndex, index, time, res);
192     return res == Status::OK ? MSERR_OK : MSERR_UNSUPPORT_FILE;
193 }
194 
GetIndexForFrameConvert(uint64_t time,uint32_t & index)195 int32_t AVMetadataHelperImpl::GetIndexForFrameConvert(uint64_t time, uint32_t &index)
196 {
197     CHECK_AND_RETURN_RET_LOG(conversion_ != nullptr, MSERR_INVALID_STATE, "conversion_ is nullptr");
198     uint32_t trackIndex = 0;
199     auto res = conversion_->GetFirstVideoTrackIndex(trackIndex);
200     CHECK_AND_RETURN_RET_LOG(res == Status::OK, MSERR_UNSUPPORT_FILE, "GetFirstVideoTrackIndex failed");
201     res = conversion_->GetIndexByRelativePresentationTimeUs(trackIndex, time, index);
202     MEDIA_LOGI("trackIndex: %{public}" PRIu32 ", index: %{public}" PRIu32 ", time: %{public}" PRIu64
203                 ", res: %{public}d", trackIndex, index, time, res);
204     return res == Status::OK ? MSERR_OK : MSERR_UNSUPPORT_FILE;
205 }
206 
FetchFrameYuv(int64_t timeUs,int32_t option,const OutputConfiguration & param)207 std::shared_ptr<AVBuffer> AVMetadataHelperImpl::FetchFrameYuv(
208     int64_t timeUs, int32_t option, const OutputConfiguration &param)
209 {
210     MEDIA_LOGD("enter FetchFrameAtTime");
211     auto res = InitThumbnailGenerator();
212     CHECK_AND_RETURN_RET(res == Status::OK, nullptr);
213     return thumbnailGenerator_->FetchFrameYuv(timeUs, option, param);
214 }
215 
Reset()216 void AVMetadataHelperImpl::Reset()
217 {
218     if (metadataCollector_ != nullptr) {
219         metadataCollector_->Reset();
220     }
221 
222     if (thumbnailGenerator_ != nullptr) {
223         thumbnailGenerator_->Reset();
224     }
225 
226     if (mediaDemuxer_ != nullptr) {
227         mediaDemuxer_->Reset();
228     }
229 
230     isForFrameConvert_ = false;
231 }
232 
Destroy()233 void AVMetadataHelperImpl::Destroy()
234 {
235     if (metadataCollector_ != nullptr) {
236         metadataCollector_->Destroy();
237     }
238 
239     if (thumbnailGenerator_ != nullptr) {
240         thumbnailGenerator_->Destroy();
241     }
242 
243     metadataCollector_ = nullptr;
244     thumbnailGenerator_ = nullptr;
245     PipeLineThreadPool::GetInstance().DestroyThread(groupId_);
246     MEDIA_LOGD("0x%{public}06" PRIXPTR " Finish Destroy.", FAKE_POINTER(this));
247 }
248 
InitMetadataCollector()249 Status AVMetadataHelperImpl::InitMetadataCollector()
250 {
251     CHECK_AND_RETURN_RET_LOG(
252         mediaDemuxer_ != nullptr, Status::ERROR_INVALID_STATE, "mediaDemuxer_ is nullptr");
253     if (metadataCollector_ == nullptr) {
254         metadataCollector_ = std::make_shared<AVMetaDataCollector>(mediaDemuxer_);
255     }
256     CHECK_AND_RETURN_RET_LOG(
257         metadataCollector_ != nullptr, Status::ERROR_INVALID_STATE, "Init metadata collector failed.");
258     return Status::OK;
259 }
260 
InitThumbnailGenerator()261 Status AVMetadataHelperImpl::InitThumbnailGenerator()
262 {
263     CHECK_AND_RETURN_RET_LOG(
264         mediaDemuxer_ != nullptr, Status::ERROR_INVALID_STATE, "mediaDemuxer_ is nullptr");
265     if (thumbnailGenerator_ == nullptr) {
266         thumbnailGenerator_ = std::make_shared<AVThumbnailGenerator>(mediaDemuxer_);
267     }
268     CHECK_AND_RETURN_RET_LOG(
269         thumbnailGenerator_ != nullptr, Status::ERROR_INVALID_STATE, "Init thumbnail generator failed.");
270     return Status::OK;
271 }
272 
SetInterruptState(bool isInterruptNeeded)273 void AVMetadataHelperImpl::SetInterruptState(bool isInterruptNeeded)
274 {
275     MEDIA_LOGI("Metadata set interrupt state %{public}d", isInterruptNeeded);
276     isInterruptNeeded_ = isInterruptNeeded;
277     CHECK_AND_RETURN(mediaDemuxer_ != nullptr);
278     mediaDemuxer_->SetInterruptState(isInterruptNeeded);
279 }
280 }  // namespace Media
281 }  // namespace OHOS