/src/libheif/libheif/sequences/track.h
Line | Count | Source |
1 | | /* |
2 | | * HEIF image base codec. |
3 | | * Copyright (c) 2024 Dirk Farin <dirk.farin@gmail.com> |
4 | | * |
5 | | * This file is part of libheif. |
6 | | * |
7 | | * libheif is free software: you can redistribute it and/or modify |
8 | | * it under the terms of the GNU Lesser General Public License as |
9 | | * published by the Free Software Foundation, either version 3 of |
10 | | * the License, or (at your option) any later version. |
11 | | * |
12 | | * libheif is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public License |
18 | | * along with libheif. If not, see <http://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | #ifndef LIBHEIF_TRACK_H |
22 | | #define LIBHEIF_TRACK_H |
23 | | |
24 | | #include "error.h" |
25 | | #include "api_structs.h" |
26 | | #include "libheif/heif_plugin.h" |
27 | | #include "libheif/heif_sequences.h" |
28 | | #include <string> |
29 | | #include <memory> |
30 | | #include <vector> |
31 | | |
32 | | class HeifContext; |
33 | | |
34 | | class HeifPixelImage; |
35 | | |
36 | | class Chunk; |
37 | | |
38 | | class Box_trak; |
39 | | |
40 | | |
41 | | class SampleAuxInfoHelper |
42 | | { |
43 | | public: |
44 | | SampleAuxInfoHelper(bool interleaved = false); |
45 | | |
46 | | void set_aux_info_type(uint32_t aux_info_type, uint32_t aux_info_type_parameter = 0); |
47 | | |
48 | | Error add_sample_info(const std::vector<uint8_t>& data); |
49 | | |
50 | | void add_nonpresent_sample(); |
51 | | |
52 | | void write_interleaved(const std::shared_ptr<HeifFile>& file); |
53 | | |
54 | | void write_all(const std::shared_ptr<Box>& parent, const std::shared_ptr<HeifFile>& file); |
55 | | |
56 | | private: |
57 | | std::shared_ptr<Box_saiz> m_saiz; |
58 | | std::shared_ptr<Box_saio> m_saio; |
59 | | |
60 | | std::vector<uint8_t> m_data; |
61 | | |
62 | | bool m_interleaved; |
63 | | }; |
64 | | |
65 | | |
66 | | class SampleAuxInfoReader |
67 | | { |
68 | | public: |
69 | | SampleAuxInfoReader(std::shared_ptr<Box_saiz>, |
70 | | std::shared_ptr<Box_saio>, |
71 | | const std::vector<std::shared_ptr<Chunk>>& chunks); |
72 | | |
73 | | heif_sample_aux_info_type get_type() const; |
74 | | |
75 | | Result<std::vector<uint8_t>> get_sample_info(const HeifFile* file, uint32_t sample_idx); |
76 | | |
77 | | private: |
78 | | std::shared_ptr<Box_saiz> m_saiz; |
79 | | std::shared_ptr<Box_saio> m_saio; |
80 | | |
81 | | // If there is only one chunk and the SAI data sizes are constant, we do not need an offset table. |
82 | | // We just store the base offset and can directly calculate the sample offset from that. |
83 | | bool m_contiguous_and_constant_size=false; |
84 | | uint64_t m_singleChunk_offset=0; |
85 | | |
86 | | // For chunked data or non-constant sample sizes, we use a table with the offsets for all SAI samples. |
87 | | std::vector<uint64_t> m_sample_offsets; |
88 | | }; |
89 | | |
90 | | |
91 | | /** |
92 | | * This structure specifies what will be written in a track and how it will be laid out in the file. |
93 | | */ |
94 | | struct TrackOptions |
95 | | { |
96 | | ~TrackOptions() |
97 | 324 | { |
98 | 324 | heif_tai_clock_info_release(tai_clock_info); |
99 | 324 | } |
100 | | |
101 | | // Timescale (clock ticks per second) for this track. |
102 | | uint32_t track_timescale = 90000; |
103 | | |
104 | | // If 'true', the aux_info data blocks will be interleaved with the compressed image. |
105 | | // This has the advantage that the aux_info is localized near the image data. |
106 | | // |
107 | | // If 'false', all aux_info will be written as one block after the compressed image data. |
108 | | // This has the advantage that no aux_info offsets have to be written. |
109 | | bool write_sample_aux_infos_interleaved = false; |
110 | | |
111 | | |
112 | | // --- TAI timestamps for samples |
113 | | heif_sample_aux_info_presence with_sample_tai_timestamps = heif_sample_aux_info_presence_none; |
114 | | heif_tai_clock_info* tai_clock_info = nullptr; |
115 | | |
116 | | // --- GIMI content IDs for samples |
117 | | |
118 | | heif_sample_aux_info_presence with_sample_content_ids = heif_sample_aux_info_presence_none; |
119 | | |
120 | | // --- GIMI content ID for the track |
121 | | |
122 | | std::string gimi_track_content_id; |
123 | | |
124 | | TrackOptions& operator=(const TrackOptions&); |
125 | | }; |
126 | | |
127 | | |
128 | | const char* get_track_auxiliary_info_type(heif_compression_format format); |
129 | | |
130 | | |
131 | | class Track : public ErrorBuffer { |
132 | | public: |
133 | | //Track(HeifContext* ctx); |
134 | | |
135 | | Track(HeifContext* ctx, uint32_t track_id, const TrackOptions* info, uint32_t handler_type); |
136 | | |
137 | | Track(HeifContext* ctx); |
138 | | |
139 | 324 | virtual ~Track() = default; |
140 | | |
141 | | // Allocate a Track of the correct sub-class (visual or metadata). |
142 | | // For tracks with an unsupported handler type, heif_error_Unsupported_feature/heif_suberror_Unsupported_track_type is returned. |
143 | | static Result<std::shared_ptr<Track>> alloc_track(HeifContext*, const std::shared_ptr<Box_trak>&); |
144 | | |
145 | | // load track from file |
146 | | virtual Error load(const std::shared_ptr<Box_trak>&); |
147 | | |
148 | | // This is called after creating all Track objects when reading a HEIF file. |
149 | | // We can now do initializations that require access to all tracks. |
150 | 3 | [[nodiscard]] virtual Error initialize_after_parsing(HeifContext*, const std::vector<std::shared_ptr<Track>>& all_tracks) { return {}; } |
151 | | |
152 | 105 | heif_item_id get_id() const { return m_id; } |
153 | | |
154 | | std::shared_ptr<HeifFile> get_file() const; |
155 | | |
156 | 46 | uint32_t get_handler() const { return m_handler_type; } |
157 | | |
158 | | heif_auxiliary_track_info_type get_auxiliary_info_type() const; |
159 | | |
160 | 0 | std::string get_auxiliary_info_type_urn() const { return m_auxiliary_info_type; } |
161 | | |
162 | | void set_auxiliary_info_type(heif_auxiliary_track_info_type); |
163 | | |
164 | 0 | void set_auxiliary_info_type_urn(std::string t) { m_auxiliary_info_type = t; } |
165 | | |
166 | | bool is_visual_track() const; |
167 | | |
168 | 0 | virtual bool has_alpha_channel() const { return false; } |
169 | | |
170 | | uint32_t get_first_cluster_sample_entry_type() const; |
171 | | |
172 | | Result<std::string> get_first_cluster_urim_uri() const; |
173 | | |
174 | | uint64_t get_duration_in_media_units() const; |
175 | | |
176 | | uint32_t get_timescale() const; |
177 | | |
178 | | // The context will compute the duration in global movie units and set this. |
179 | | void set_track_duration_in_movie_units(uint64_t total_duration, uint64_t segment_duration); |
180 | | |
181 | | void enable_edit_list_repeat_mode(bool enable); |
182 | | |
183 | 0 | std::shared_ptr<Box_taic> get_first_cluster_taic() { return m_first_taic; } |
184 | | |
185 | | bool end_of_sequence_reached() const; |
186 | | |
187 | | // See m_num_repetitions for the meaning of the return value. |
188 | 0 | uint32_t get_number_of_repetitions() const { return m_num_repetitions; } |
189 | | |
190 | | // Compute some parameters after all frames have been encoded (for example: track duration). |
191 | | virtual Error finalize_track(); |
192 | | |
193 | 0 | const TrackOptions& get_track_info() const { return m_track_info; } |
194 | | |
195 | | void add_reference_to_track(uint32_t referenceType, uint32_t to_track_id); |
196 | | |
197 | 0 | std::shared_ptr<const Box_tref> get_tref_box() const { return m_tref; } |
198 | | |
199 | | Result<heif_raw_sequence_sample*> get_next_sample_raw_data(const heif_decoding_options* options); |
200 | | |
201 | | std::vector<heif_sample_aux_info_type> get_sample_aux_info_types() const; |
202 | | |
203 | | protected: |
204 | | HeifContext* m_heif_context = nullptr; |
205 | | uint32_t m_id = 0; |
206 | | uint32_t m_handler_type = 0; |
207 | | |
208 | | TrackOptions m_track_info; |
209 | | |
210 | | uint32_t m_num_samples = 0; |
211 | | |
212 | | struct SampleTiming { |
213 | | uint32_t sampleIdx = 0; |
214 | | uint32_t sampleInChunkIdx = 0; |
215 | | uint32_t chunkIdx = 0; |
216 | | uint64_t presentation_time = 0; // TODO |
217 | | uint64_t media_composition_time = 0; // TODO |
218 | | uint64_t media_decoding_time = 0; |
219 | | uint32_t sample_duration_media_time = 0; |
220 | | uint32_t sample_duration_presentation_time = 0; // TODO |
221 | | }; |
222 | | std::vector<SampleTiming> m_presentation_timeline; |
223 | | uint64_t m_num_output_samples = 0; // Can be larger than the vector. It then repeats the playback. |
224 | | |
225 | | // How many times the media timeline is repeated. |
226 | | // 0 = editlist is present but its pattern is not understood (caller should assume a single playback). |
227 | | // 1 = no editlist: media plays exactly once. |
228 | | // UINT32_MAX = infinite (mvhd duration is the indefinite-sentinel and the editlist is in repeat mode). |
229 | | // N = the media segment is played N times. |
230 | | uint32_t m_num_repetitions = 1; |
231 | | |
232 | | // Continuous counting through all repetitions. You have to take the modulo operation to get the |
233 | | // index into m_presentation_timeline SampleTiming table. |
234 | | // (At 30 fps, this 32 bit integer will overflow in >4 years. I think this is acceptable.) |
235 | | uint32_t m_next_sample_to_be_decoded = 0; |
236 | | |
237 | | // Total sequence output index. |
238 | | uint32_t m_next_sample_to_be_output = 0; |
239 | | bool m_decoder_is_flushed = false; |
240 | | |
241 | | Error init_sample_timing_table(); |
242 | | |
243 | | std::vector<std::shared_ptr<Chunk>> m_chunks; |
244 | | std::vector<uint8_t> m_chunk_data; |
245 | | |
246 | | std::shared_ptr<Box_moov> m_moov; |
247 | | std::shared_ptr<Box_trak> m_trak; |
248 | | std::shared_ptr<Box_tkhd> m_tkhd; |
249 | | std::shared_ptr<Box_minf> m_minf; |
250 | | std::shared_ptr<Box_mdhd> m_mdhd; |
251 | | std::shared_ptr<Box_hdlr> m_hdlr; |
252 | | std::shared_ptr<Box_stbl> m_stbl; |
253 | | std::shared_ptr<Box_stsd> m_stsd; |
254 | | std::shared_ptr<Box_stsc> m_stsc; |
255 | | std::shared_ptr<Box_stco> m_stco; |
256 | | std::shared_ptr<Box_stts> m_stts; |
257 | | std::shared_ptr<Box_ctts> m_ctts; // optional box, TODO: add only if needed |
258 | | std::shared_ptr<Box_stss> m_stss; |
259 | | std::shared_ptr<Box_stsz> m_stsz; |
260 | | std::shared_ptr<Box_elst> m_elst; |
261 | | |
262 | | std::shared_ptr<class Box_tref> m_tref; // optional |
263 | | |
264 | | std::string m_auxiliary_info_type; // only for auxiliary tracks |
265 | | |
266 | | // --- sample auxiliary information |
267 | | |
268 | | std::unique_ptr<SampleAuxInfoHelper> m_aux_helper_tai_timestamps; |
269 | | std::unique_ptr<SampleAuxInfoHelper> m_aux_helper_content_ids; |
270 | | |
271 | | std::unique_ptr<SampleAuxInfoReader> m_aux_reader_tai_timestamps; |
272 | | std::unique_ptr<SampleAuxInfoReader> m_aux_reader_content_ids; |
273 | | |
274 | | std::shared_ptr<class Box_taic> m_first_taic; // the TAIC of the first chunk |
275 | | |
276 | | |
277 | | // --- Helper functions for writing samples. |
278 | | |
279 | | // Call when we begin a new chunk of samples, e.g. because the compression format changed |
280 | | void add_chunk(heif_compression_format format); |
281 | | |
282 | | // Call to set the sample_description_box for the last added chunk. |
283 | | // Has to be called when we call add_chunk(). |
284 | | // It is not merged with add_chunk() because the sample_description_box may need information from the |
285 | | // first encoded frame. |
286 | | void set_sample_description_box(std::shared_ptr<Box> sample_description_box); |
287 | | |
288 | | // Write the actual sample data. `tai` may be null and `gimi_contentID` may be empty. |
289 | | // In these cases, no timestamp or no contentID will be written, respectively. |
290 | | Error write_sample_data(const std::vector<uint8_t>& raw_data, |
291 | | uint32_t sample_duration, |
292 | | int32_t composition_time_offset, |
293 | | bool is_sync_sample, |
294 | | const heif_tai_timestamp_packet* tai, |
295 | | const std::optional<std::string>& gimi_contentID); |
296 | | }; |
297 | | |
298 | | |
299 | | #endif //LIBHEIF_TRACK_H |