1 /*
2  * Copyright (c) 2024-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 #ifndef HISTREAMER_M3U8_H
17 #define HISTREAMER_M3U8_H
18 
19 #include <memory>
20 #include <string>
21 #include <list>
22 #include <unordered_map>
23 #include <functional>
24 #include <map>
25 #include "hls_tags.h"
26 #include "playlist_downloader.h"
27 #include "download/downloader.h"
28 
29 namespace OHOS {
30 namespace Media {
31 namespace Plugins {
32 namespace HttpPlugin {
33 enum class M3U8MediaType : int32_t {
34     M3U8_MEDIA_TYPE_INVALID = -1,
35     M3U8_MEDIA_TYPE_AUDIO,
36     M3U8_MEDIA_TYPE_VIDEO,
37     M3U8_MEDIA_TYPE_SUBTITLES,
38     M3U8_MEDIA_TYPE_CLOSED_CAPTIONS,
39     M3U8_N_MEDIA_TYPES,
40 };
41 
42 struct M3U8InitFile {
43     std::string uri;
44     int offset;
45     int size;
46 };
47 
48 struct M3U8Fragment {
49     M3U8Fragment(std::string uri, double duration, int sequence, bool discont);
50     M3U8Fragment(const M3U8Fragment& m3u8, const uint8_t *key, const uint8_t *iv);
51     std::string uri_;
52     double duration_;
53     int64_t sequence_;
54     bool discont_ {false};
55     uint8_t key_[16] { 0 };
56     int iv_[16] {0};
57     int offset_ {-1};
58     int size_ {0};
59 };
60 
61 struct M3U8Info {
62     std::string uri;
63     double duration = 0;
64     bool discontinuity = false;
65     bool bVod {false};
66 };
67 
68 struct M3U8 {
69     M3U8(std::string uri, std::string name);
70     ~M3U8();
71     void InitTagUpdaters();
72     void InitTagUpdatersMap();
73     bool Update(const std::string& playList, bool isNeedCleanFiles);
74     void UpdateFromTags(std::list<std::shared_ptr<Tag>>& tags);
75     void AddFile(std::shared_ptr<M3U8Fragment> fragment, size_t duration);
76     void GetExtInf(const std::shared_ptr<Tag>& tag, double& duration) const;
77     double GetDuration() const;
78     bool IsLive() const;
79 
80     std::string uri_;
81     std::string name_;
82     std::unordered_map<HlsTag, std::function<void(std::shared_ptr<Tag>&, M3U8Info&)>> tagUpdatersMap_;
83 
84     double targetDuration_ {0.0};
85     bool bLive_ {};
86     std::list<std::shared_ptr<M3U8Fragment>> files_;
87     uint64_t sequence_ {1}; // default 1
88     int discontSequence_ {0};
89     std::string playList_;
90     void ParseKey(const std::shared_ptr<AttributesTag> &tag);
91     void DownloadKey();
92     bool SaveData(uint8_t *data, uint32_t len);
93     static void OnDownloadStatus(DownloadStatus status, std::shared_ptr<Downloader> &,
94         std::shared_ptr<DownloadRequest> &request);
95     bool SetDrmInfo(std::multimap<std::string, std::vector<uint8_t>>& drmInfo);
96     void StoreDrmInfos(const std::multimap<std::string, std::vector<uint8_t>>& drmInfo);
97     void ProcessDrmInfos(void);
98 
99     std::shared_ptr<std::string> method_;
100     std::shared_ptr<std::string> keyUri_;
101     uint8_t iv_[16] { 0 };
102     uint8_t key_[16] { 0 };
103     size_t keyLen_ { 0 };
104     std::shared_ptr<Downloader> downloader_;
105     std::shared_ptr<DownloadRequest> downloadRequest_;
106     DataSaveFunc dataSave_;
107     StatusCallbackFunc statusCallback_;
108     PlayListChangeCallback *callback_ { nullptr };
109     bool startedDownloadStatus_ { false };
110     bool isDecryptAble_ { false };
111     bool isDecryptKeyReady_ { false };
112     std::multimap<std::string, std::vector<uint8_t>> localDrmInfos_;
113     M3U8Info firstFragment_;
114     std::atomic<bool> isFirstFragmentReady_ {false};
115     std::atomic<bool> isPlayTypeFound_ {false};
116     bool hasDiscontinuity_ {false};
117     std::vector<size_t> segmentOffsets_;
118     std::map<std::string, std::string> httpHeader_ {};
119 };
120 
121 struct M3U8Media {
122     M3U8MediaType type_;
123     std::string groupID_;
124     std::string name_;
125     std::string lang_;
126     std::string uri_;
127     bool isDefault_;
128     bool autoSelect_;
129     bool forced_;
130     std::shared_ptr<M3U8> m3u8_;
131 };
132 
133 struct M3U8VariantStream {
134     M3U8VariantStream(std::string name, std::string uri, std::shared_ptr<M3U8> m3u8);
135     std::string name_;
136     std::string uri_;
137     std::string codecs_;
138     uint64_t bandWidth_ {};
139     int programID_ {};
140     int width_ {};
141     int height_ {};
142     bool iframe_ {false};
143     std::shared_ptr<M3U8> m3u8_;
144     std::list<M3U8Media> media_;
145 };
146 
147 struct M3U8MasterPlaylist {
148     M3U8MasterPlaylist(const std::string& playList, const std::string& uri, uint32_t initResolution = 0,
149         const std::map<std::string, std::string>& httpHeader = std::map<std::string, std::string>());
150     void UpdateMediaPlaylist();
151     void UpdateMasterPlaylist();
152     void DownloadSessionKey(std::shared_ptr<Tag>& tag);
153     void ChooseStreamByResolution();
154     bool IsNearToInitResolution(const std::shared_ptr<M3U8VariantStream> &choosedStream,
155     const std::shared_ptr<M3U8VariantStream> &currentStream);
156     uint32_t GetResolutionDelta(uint32_t width, uint32_t height);
157     std::list<std::shared_ptr<M3U8VariantStream>> variants_;
158     std::shared_ptr<M3U8VariantStream> defaultVariant_;
159     std::string uri_;
160     std::string playList_;
161     double duration_ {0};
162     std::atomic<bool> isSimple_ {false};
163     std::atomic<bool> bLive_ {false};
164     bool isDecryptAble_ { false };
165     bool isDecryptKeyReady_ { false };
166     uint8_t iv_[16] { 0 };
167     uint8_t key_[16] { 0 };
168     size_t keyLen_ { 0 };
169     std::atomic<bool> isParseSuccess_ {true};
170     std::vector<size_t> segmentOffsets_;
171     bool hasDiscontinuity_ {false};
172     std::map<std::string, std::string> httpHeader_ {};
173     uint32_t initResolution_ {0};
174 };
175 }
176 }
177 }
178 }
179 #endif
180