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#include "OHAVMetadataBuilder.h"
16#include "avsession_log.h"
17
18using namespace OHOS::AVSession;
19
20AVMetadata_Result OHAVMetadataBuilder::SetTitle(const std::string &title)
21{
22    title_ = title;
23    return AVMETADATA_SUCCESS;
24}
25
26AVMetadata_Result OHAVMetadataBuilder::SetArtist(const std::string &artist)
27{
28    artist_ = artist;
29    return AVMETADATA_SUCCESS;
30}
31
32AVMetadata_Result OHAVMetadataBuilder::SetAuthor(const std::string &author)
33{
34    author_ = author;
35    return AVMETADATA_SUCCESS;
36}
37
38AVMetadata_Result OHAVMetadataBuilder::SetAlbum(const std::string &album)
39{
40    album_ = album;
41    return AVMETADATA_SUCCESS;
42}
43
44AVMetadata_Result OHAVMetadataBuilder::SetWriter(const std::string &writer)
45{
46    writer_ = writer;
47    return AVMETADATA_SUCCESS;
48}
49
50AVMetadata_Result OHAVMetadataBuilder::SetComposer(const std::string &composer)
51{
52    composer_ = composer;
53    return AVMETADATA_SUCCESS;
54}
55
56AVMetadata_Result OHAVMetadataBuilder::SetDuration(int64_t duration)
57{
58    duration_ = duration;
59    return AVMETADATA_SUCCESS;
60}
61
62AVMetadata_Result OHAVMetadataBuilder::SetMediaImageUri(const std::string &mediaImageUri)
63{
64    mediaImageUri_ = mediaImageUri;
65    return AVMETADATA_SUCCESS;
66}
67
68AVMetadata_Result OHAVMetadataBuilder::SetSubtitle(const std::string &subtitle)
69{
70    subtitle_ = subtitle;
71    return AVMETADATA_SUCCESS;
72}
73
74AVMetadata_Result OHAVMetadataBuilder::SetDescription(const std::string &description)
75{
76    description_ = description;
77    return AVMETADATA_SUCCESS;
78}
79
80AVMetadata_Result OHAVMetadataBuilder::SetLyric(const std::string &lyric)
81{
82    lyric_ = lyric;
83    return AVMETADATA_SUCCESS;
84}
85
86AVMetadata_Result OHAVMetadataBuilder::SetAssetId(const std::string &assetId)
87{
88    assetId_ = assetId;
89    return AVMETADATA_SUCCESS;
90}
91
92AVMetadata_Result OHAVMetadataBuilder::SetSkipIntervals(AVMetadata_SkipIntervals intervals)
93{
94    switch (intervals) {
95        case SECONDS_10:
96        case SECONDS_15:
97        case SECONDS_30:
98            intervals_ = intervals;
99            return AVMETADATA_SUCCESS;
100        default:
101            SLOGE("Failed to set skip intervals: Invalid skip intervals value: %d", intervals);
102            return AVMETADATA_ERROR_INVALID_PARAM;
103    }
104}
105
106AVMetadata_Result OHAVMetadataBuilder::SetDisplayTags(int32_t tags)
107{
108    tags_ = tags;
109    return AVMETADATA_SUCCESS;
110}
111
112size_t OHAVMetadataBuilder::WriteCallback(std::uint8_t *ptr, size_t size, size_t nmemb,
113                                          std::vector<std::uint8_t> *imgBuffer)
114{
115    size_t realsize = size * nmemb;
116    imgBuffer->reserve(realsize + imgBuffer->capacity());
117    for (size_t i = 0; i < realsize; i++) {
118        imgBuffer->push_back(ptr[i]);
119    }
120    return realsize;
121}
122
123bool OHAVMetadataBuilder::CurlSetRequestOptions(std::vector<std::uint8_t>& imgBuffer, const std::string uri)
124{
125    CURL *easyHandle_ = curl_easy_init();
126    if (easyHandle_) {
127        // set request options
128        curl_easy_setopt(easyHandle_, CURLOPT_URL, uri.c_str());
129        curl_easy_setopt(easyHandle_, CURLOPT_CONNECTTIMEOUT, OHAVMetadataBuilder::TIME_OUT_SECOND);
130        curl_easy_setopt(easyHandle_, CURLOPT_SSL_VERIFYPEER, 0L);
131        curl_easy_setopt(easyHandle_, CURLOPT_SSL_VERIFYHOST, 0L);
132        curl_easy_setopt(easyHandle_, CURLOPT_CAINFO, "/etc/ssl/certs/" "cacert.pem");
133        curl_easy_setopt(easyHandle_, CURLOPT_HTTPGET, 1L);
134        curl_easy_setopt(easyHandle_, CURLOPT_WRITEFUNCTION, OHAVMetadataBuilder::WriteCallback);
135        curl_easy_setopt(easyHandle_, CURLOPT_WRITEDATA, &imgBuffer);
136
137        // perform request
138        CURLcode res = curl_easy_perform(easyHandle_);
139        if (res != CURLE_OK) {
140            SLOGI("DoDownload curl easy_perform failure: %{public}s\n", curl_easy_strerror(res));
141            curl_easy_cleanup(easyHandle_);
142            easyHandle_ = nullptr;
143            return false;
144        } else {
145            int64_t httpCode = 0;
146            curl_easy_getinfo(easyHandle_, CURLINFO_RESPONSE_CODE, &httpCode);
147            SLOGI("DoDownload Http result " "%{public}" PRId64, httpCode);
148            CHECK_AND_RETURN_RET_LOG(httpCode < OHAVMetadataBuilder::HTTP_ERROR_CODE, false, "recv Http ERROR");
149            curl_easy_cleanup(easyHandle_);
150            easyHandle_ = nullptr;
151            return true;
152        }
153    }
154    return false;
155}
156
157bool OHAVMetadataBuilder::DoDownloadInCommon(std::shared_ptr<Media::PixelMap>& pixelMap, const std::string uri)
158{
159    std::vector<std::uint8_t> imgBuffer(0);
160    if (CurlSetRequestOptions(imgBuffer, uri) == true) {
161        std::uint8_t* buffer = (std::uint8_t*) calloc(imgBuffer.size(), sizeof(uint8_t));
162        if (buffer == nullptr) {
163            SLOGE("buffer malloc fail");
164            free(buffer);
165            return false;
166        }
167        std::copy(imgBuffer.begin(), imgBuffer.end(), buffer);
168        uint32_t errorCode = 0;
169        Media::SourceOptions opts;
170        SLOGD("DoDownload get size %{public}d", static_cast<int>(imgBuffer.size()));
171        auto imageSource = Media::ImageSource::CreateImageSource(buffer, imgBuffer.size(), opts, errorCode);
172        free(buffer);
173        if (errorCode || !imageSource) {
174            SLOGE("DoDownload create imageSource fail: %{public}u", errorCode);
175            return false;
176        }
177        Media::DecodeOptions decodeOpts;
178        pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode);
179        if (errorCode || pixelMap == nullptr) {
180            SLOGE("DoDownload creatPix fail: %{public}u, %{public}d", errorCode, static_cast<int>(pixelMap != nullptr));
181            return false;
182        }
183        return true;
184    }
185    return false;
186}
187
188int32_t OHAVMetadataBuilder::DoDownload(AVMetaData& metadata, const std::string uri)
189{
190    std::shared_ptr<Media::PixelMap> pixelMap = nullptr;
191    bool ret = OHAVMetadataBuilder::DoDownloadInCommon(pixelMap, uri);
192    if (ret && pixelMap != nullptr) {
193        SLOGI("DoDownload success");
194        metadata.SetMediaImage(AVSessionPixelMapAdapter::ConvertToInner(pixelMap));
195        return AV_SESSION_ERR_SUCCESS;
196    }
197
198    return AV_SESSION_ERR_SERVICE_EXCEPTION;
199}
200
201AVMetadata_Result OHAVMetadataBuilder::GenerateAVMetadata(OH_AVMetadata** avMetadata)
202{
203    CHECK_AND_RETURN_RET_LOG(avMetadata != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "avMetadata is null");
204
205    AVMetaData* metadata = new AVMetaData();
206    if (metadata == nullptr) {
207        SLOGE("Failed to allocate memory for AVMetaData");
208        *avMetadata = nullptr;
209        return AVMETADATA_ERROR_NO_MEMORY;
210    }
211
212    switch (intervals_) {
213        case SECONDS_10:
214            metadata->SetSkipIntervals(AVMetaData::SECONDS_10);
215            break;
216        case SECONDS_15:
217            metadata->SetSkipIntervals(AVMetaData::SECONDS_15);
218            break;
219        case SECONDS_30:
220            metadata->SetSkipIntervals(AVMetaData::SECONDS_30);
221            break;
222        default:
223            SLOGE("Failed to generate avMetadata: Unsupported skip intervals: %d", intervals_);
224            delete metadata;
225            metadata = nullptr;
226            *avMetadata = nullptr;
227            return AVMETADATA_ERROR_INVALID_PARAM;
228    }
229
230    metadata->SetTitle(title_);
231    metadata->SetArtist(artist_);
232    metadata->SetAuthor(author_);
233    metadata->SetAlbum(album_);
234    metadata->SetWriter(writer_);
235    metadata->SetComposer(composer_);
236    metadata->SetDuration(duration_);
237    metadata->SetMediaImageUri(mediaImageUri_);
238    metadata->SetSubTitle(subtitle_);
239    metadata->SetDescription(description_);
240    metadata->SetLyric(lyric_);
241    metadata->SetAssetId(assetId_);
242    metadata->SetDisplayTags(tags_);
243
244    DoDownload(*metadata, mediaImageUri_);
245
246    *avMetadata = reinterpret_cast<OH_AVMetadata*>(metadata);
247
248    return AVMETADATA_SUCCESS;
249}
250
251AVMetadata_Result OH_AVMetadataBuilder_Create(OH_AVMetadataBuilder** builder)
252{
253    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
254
255    OHAVMetadataBuilder* metadata = new OHAVMetadataBuilder();
256    if (metadata == nullptr) {
257        SLOGE("Failed to allocate memory for OHAVMetadataBuilder");
258        return AVMETADATA_ERROR_NO_MEMORY;
259    }
260
261    *builder = reinterpret_cast<OH_AVMetadataBuilder*>(metadata);
262    return AVMETADATA_SUCCESS;
263}
264
265AVMetadata_Result OH_AVMetadataBuilder_Destroy(OH_AVMetadataBuilder* builder)
266{
267    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
268    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
269    delete metadata;
270    metadata = nullptr;
271    return AVMETADATA_SUCCESS;
272}
273
274AVMetadata_Result OH_AVMetadataBuilder_SetTitle(OH_AVMetadataBuilder* builder, const char* title)
275{
276    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
277    CHECK_AND_RETURN_RET_LOG(title != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "title is null");
278    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
279    return metadata->SetTitle(title);
280}
281
282AVMetadata_Result OH_AVMetadataBuilder_SetArtist(OH_AVMetadataBuilder* builder, const char* artist)
283{
284    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
285    CHECK_AND_RETURN_RET_LOG(artist != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "artist is null");
286    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
287    return metadata->SetArtist(artist);
288}
289
290AVMetadata_Result OH_AVMetadataBuilder_SetAuthor(OH_AVMetadataBuilder* builder, const char* author)
291{
292    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
293    CHECK_AND_RETURN_RET_LOG(author != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "author is null");
294    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
295    return metadata->SetAuthor(author);
296}
297
298AVMetadata_Result OH_AVMetadataBuilder_SetAlbum(OH_AVMetadataBuilder* builder, const char* album)
299{
300    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
301    CHECK_AND_RETURN_RET_LOG(album != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "album is null");
302    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
303    return metadata->SetAlbum(album);
304}
305
306AVMetadata_Result OH_AVMetadataBuilder_SetWriter(OH_AVMetadataBuilder* builder, const char* writer)
307{
308    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
309    CHECK_AND_RETURN_RET_LOG(writer != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "writer is null");
310    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
311    return metadata->SetWriter(writer);
312}
313
314AVMetadata_Result OH_AVMetadataBuilder_SetComposer(OH_AVMetadataBuilder* builder, const char* composer)
315{
316    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
317    CHECK_AND_RETURN_RET_LOG(composer != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "composer is null");
318    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
319    return metadata->SetComposer(composer);
320}
321
322AVMetadata_Result OH_AVMetadataBuilder_SetDuration(OH_AVMetadataBuilder* builder, int64_t duration)
323{
324    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
325    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
326    return metadata->SetDuration(duration);
327}
328
329AVMetadata_Result OH_AVMetadataBuilder_SetMediaImageUri(OH_AVMetadataBuilder* builder, const char* mediaImageUri)
330{
331    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
332    CHECK_AND_RETURN_RET_LOG(mediaImageUri != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "mediaImageUri is null");
333    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
334    return metadata->SetMediaImageUri(mediaImageUri);
335}
336
337AVMetadata_Result OH_AVMetadataBuilder_SetSubtitle(OH_AVMetadataBuilder* builder, const char* subtitle)
338{
339    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
340    CHECK_AND_RETURN_RET_LOG(subtitle != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "subtitle is null");
341    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
342    return metadata->SetSubtitle(subtitle);
343}
344
345AVMetadata_Result OH_AVMetadataBuilder_SetDescription(OH_AVMetadataBuilder* builder, const char* description)
346{
347    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
348    CHECK_AND_RETURN_RET_LOG(description != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "description is null");
349    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
350    return metadata->SetDescription(description);
351}
352
353AVMetadata_Result OH_AVMetadataBuilder_SetLyric(OH_AVMetadataBuilder* builder, const char* lyric)
354{
355    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
356    CHECK_AND_RETURN_RET_LOG(lyric != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "lyric is null");
357    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
358    return metadata->SetLyric(lyric);
359}
360
361AVMetadata_Result OH_AVMetadataBuilder_SetAssetId(OH_AVMetadataBuilder* builder, const char* assetId)
362{
363    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
364    CHECK_AND_RETURN_RET_LOG(assetId != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "assetId is null");
365    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
366    return metadata->SetAssetId(assetId);
367}
368
369AVMetadata_Result OH_AVMetadataBuilder_SetSkipIntervals(OH_AVMetadataBuilder* builder,
370                                                        AVMetadata_SkipIntervals intervals)
371{
372    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
373    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
374    return metadata->SetSkipIntervals(intervals);
375}
376
377AVMetadata_Result OH_AVMetadataBuilder_SetDisplayTags(OH_AVMetadataBuilder* builder, int32_t tags)
378{
379    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
380    if (tags != AVSESSION_DISPLAYTAG_AUDIO_VIVID) {
381        return AVMETADATA_ERROR_INVALID_PARAM;
382    }
383    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
384    return metadata->SetDisplayTags(tags);
385}
386
387AVMetadata_Result OH_AVMetadataBuilder_GenerateAVMetadata(OH_AVMetadataBuilder* builder,
388                                                          OH_AVMetadata** avMetadata)
389{
390    CHECK_AND_RETURN_RET_LOG(builder != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "builder is null");
391    CHECK_AND_RETURN_RET_LOG(avMetadata != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "avMetadata is null");
392    OHAVMetadataBuilder* metadata = reinterpret_cast<OHAVMetadataBuilder*>(builder);
393    return metadata->GenerateAVMetadata(avMetadata);
394}
395
396AVMetadata_Result OH_AVMetadata_Destroy(OH_AVMetadata* avMetadata)
397{
398    CHECK_AND_RETURN_RET_LOG(avMetadata != nullptr, AVMETADATA_ERROR_INVALID_PARAM, "avMetadata is null");
399    AVMetaData* metadata = reinterpret_cast<AVMetaData*>(avMetadata);
400    delete metadata;
401    metadata = nullptr;
402    return AVMETADATA_SUCCESS;
403}