/src/libheif/libheif/api/libheif/heif_tai_timestamps.cc
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * HEIF codec. |
3 | | * Copyright (c) 2025 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 | | #include <libheif/heif_tai_timestamps.h> |
22 | | #include "api_structs.h" |
23 | | #include "box.h" |
24 | | #include "file.h" |
25 | | #include <memory> |
26 | | |
27 | | |
28 | | void initialize_heif_tai_clock_info(heif_tai_clock_info* taic) |
29 | 6 | { |
30 | 6 | taic->version = 1; |
31 | 6 | taic->time_uncertainty = heif_tai_clock_info_time_uncertainty_unknown; |
32 | 6 | taic->clock_resolution = 0; |
33 | 6 | taic->clock_drift_rate = heif_tai_clock_info_clock_drift_rate_unknown; |
34 | 6 | taic->clock_type = heif_tai_clock_info_clock_type_unknown; |
35 | 6 | } |
36 | | |
37 | | heif_tai_clock_info* heif_tai_clock_info_alloc() |
38 | 0 | { |
39 | 0 | auto* taic = new heif_tai_clock_info; |
40 | 0 | initialize_heif_tai_clock_info(taic); |
41 | |
|
42 | 0 | return taic; |
43 | 0 | } |
44 | | |
45 | | |
46 | | void initialize_heif_tai_timestamp_packet(heif_tai_timestamp_packet* itai) |
47 | 10 | { |
48 | 10 | itai->version = 1; |
49 | 10 | itai->tai_timestamp = 0; |
50 | 10 | itai->synchronization_state = false; |
51 | 10 | itai->timestamp_generation_failure = false; |
52 | 10 | itai->timestamp_is_modified = false; |
53 | 10 | } |
54 | | |
55 | | heif_tai_timestamp_packet* heif_tai_timestamp_packet_alloc() |
56 | 0 | { |
57 | 0 | auto* itai = new heif_tai_timestamp_packet; |
58 | 0 | initialize_heif_tai_timestamp_packet(itai); |
59 | |
|
60 | 0 | return itai; |
61 | 0 | } |
62 | | |
63 | | |
64 | | |
65 | | void heif_tai_timestamp_packet_copy(heif_tai_timestamp_packet* dst, const heif_tai_timestamp_packet* src) |
66 | 0 | { |
67 | 0 | if (dst->version >= 1 && src->version >= 1) { |
68 | 0 | dst->tai_timestamp = src->tai_timestamp; |
69 | 0 | dst->synchronization_state = src->synchronization_state; |
70 | 0 | dst->timestamp_is_modified = src->timestamp_is_modified; |
71 | 0 | dst->timestamp_generation_failure = src->timestamp_generation_failure; |
72 | 0 | } |
73 | | |
74 | | // in the future when copying with "src->version > dst->version", |
75 | | // the remaining dst fields have to be filled with defaults |
76 | 0 | } |
77 | | |
78 | | void heif_tai_clock_info_copy(heif_tai_clock_info* dst, const heif_tai_clock_info* src) |
79 | 0 | { |
80 | 0 | if (dst->version >= 1 && src->version >= 1) { |
81 | 0 | dst->time_uncertainty = src->time_uncertainty; |
82 | 0 | dst->clock_resolution = src->clock_resolution; |
83 | 0 | dst->clock_drift_rate = src->clock_drift_rate; |
84 | 0 | dst->clock_type = src->clock_type; |
85 | 0 | } |
86 | | |
87 | | // in the future when copying with "src->version > dst->version", |
88 | | // the remaining dst fields have to be filled with defaults |
89 | 0 | } |
90 | | |
91 | | |
92 | | struct heif_error heif_item_set_property_tai_clock_info(struct heif_context* ctx, |
93 | | heif_item_id itemId, |
94 | | const heif_tai_clock_info* clock, |
95 | | heif_property_id* out_propertyId) |
96 | 0 | { |
97 | 0 | if (!ctx || !clock) { |
98 | 0 | return {heif_error_Usage_error, heif_suberror_Null_pointer_argument, "NULL passed"}; |
99 | 0 | } |
100 | | |
101 | | // Check if itemId exists |
102 | 0 | auto file = ctx->context->get_heif_file(); |
103 | 0 | if (!file->item_exists(itemId)) { |
104 | 0 | return {heif_error_Input_does_not_exist, heif_suberror_Invalid_parameter_value, "itemId does not exist"}; |
105 | 0 | } |
106 | | |
107 | | // make sure that we do not add two taic boxes to one image |
108 | | |
109 | 0 | if (auto img= ctx->context->get_image(itemId, false)) { |
110 | 0 | auto existing_taic = img->get_property<Box_taic>(); |
111 | 0 | if (existing_taic) { |
112 | 0 | return {heif_error_Usage_error, heif_suberror_Invalid_parameter_value, "item already has an taic property"}; |
113 | 0 | } |
114 | 0 | } |
115 | | |
116 | | // Create new taic (it will be deduplicated automatically in add_property()) |
117 | | |
118 | 0 | auto taic = std::make_shared<Box_taic>(); |
119 | 0 | taic->set_from_tai_clock_info(clock); |
120 | |
|
121 | 0 | heif_property_id id = ctx->context->add_property(itemId, taic, false); |
122 | |
|
123 | 0 | if (out_propertyId) { |
124 | 0 | *out_propertyId = id; |
125 | 0 | } |
126 | |
|
127 | 0 | return heif_error_success; |
128 | 0 | } |
129 | | |
130 | | |
131 | | struct heif_error heif_item_get_property_tai_clock_info(const struct heif_context* ctx, |
132 | | heif_item_id itemId, |
133 | | heif_tai_clock_info** out_clock) |
134 | 0 | { |
135 | 0 | if (!ctx) { |
136 | 0 | return {heif_error_Usage_error, heif_suberror_Invalid_parameter_value, "NULL heif_context passed in"}; |
137 | 0 | } |
138 | 0 | else if (!out_clock) { |
139 | 0 | return {heif_error_Input_does_not_exist, heif_suberror_Invalid_parameter_value, "NULL heif_tai_clock_info passed in"}; |
140 | 0 | } |
141 | | |
142 | 0 | *out_clock = nullptr; |
143 | | |
144 | | // Check if itemId exists |
145 | 0 | auto file = ctx->context->get_heif_file(); |
146 | 0 | if (!file->item_exists(itemId)) { |
147 | 0 | return {heif_error_Input_does_not_exist, heif_suberror_Invalid_parameter_value, "item ID does not exist"}; |
148 | 0 | } |
149 | | |
150 | | // Check if taic exists for itemId |
151 | 0 | auto taic = file->get_property_for_item<Box_taic>(itemId); |
152 | 0 | if (!taic) { |
153 | | // return NULL heif_tai_clock_info |
154 | 0 | return heif_error_success; |
155 | 0 | } |
156 | | |
157 | 0 | *out_clock = new heif_tai_clock_info; |
158 | 0 | **out_clock = *taic->get_tai_clock_info(); |
159 | |
|
160 | 0 | return heif_error_success; |
161 | 0 | } |
162 | | |
163 | | |
164 | | void heif_tai_clock_info_release(struct heif_tai_clock_info* clock_info) |
165 | 0 | { |
166 | 0 | delete clock_info; |
167 | 0 | } |
168 | | |
169 | | |
170 | | void heif_tai_timestamp_packet_release(struct heif_tai_timestamp_packet* tai) |
171 | 20.4k | { |
172 | 20.4k | delete tai; |
173 | 20.4k | } |
174 | | |
175 | | |
176 | | struct heif_error heif_item_set_property_tai_timestamp(struct heif_context* ctx, |
177 | | heif_item_id itemId, |
178 | | const heif_tai_timestamp_packet* timestamp, |
179 | | heif_property_id* out_propertyId) |
180 | 0 | { |
181 | 0 | if (!ctx) { |
182 | 0 | return {heif_error_Usage_error, heif_suberror_Null_pointer_argument, "NULL passed"}; |
183 | 0 | } |
184 | | |
185 | | // Check if itemId exists |
186 | 0 | auto file = ctx->context->get_heif_file(); |
187 | 0 | if (!file->item_exists(itemId)) { |
188 | 0 | return {heif_error_Input_does_not_exist, heif_suberror_Invalid_parameter_value, "item does not exist"}; |
189 | 0 | } |
190 | | |
191 | | // make sure that we do not add two TAI timestamps to one image |
192 | | |
193 | 0 | if (auto img= ctx->context->get_image(itemId, false)) { |
194 | 0 | auto existing_itai = img->get_property<Box_itai>(); |
195 | 0 | if (existing_itai) { |
196 | 0 | return {heif_error_Usage_error, heif_suberror_Invalid_parameter_value, "item already has an itai property"}; |
197 | 0 | } |
198 | 0 | } |
199 | | |
200 | | // Create new itai (it will be deduplicated automatically in add_property()) |
201 | | |
202 | 0 | auto itai = std::make_shared<Box_itai>(); |
203 | 0 | itai->set_from_tai_timestamp_packet(timestamp); |
204 | |
|
205 | 0 | heif_property_id id = ctx->context->add_property(itemId, itai, false); |
206 | |
|
207 | 0 | if (out_propertyId) { |
208 | 0 | *out_propertyId = id; |
209 | 0 | } |
210 | |
|
211 | 0 | return heif_error_success; |
212 | 0 | } |
213 | | |
214 | | |
215 | | struct heif_error heif_item_get_property_tai_timestamp(const struct heif_context* ctx, |
216 | | heif_item_id itemId, |
217 | | struct heif_tai_timestamp_packet** out_timestamp) |
218 | 0 | { |
219 | 0 | if (!ctx) { |
220 | 0 | return {heif_error_Usage_error, heif_suberror_Invalid_parameter_value, "NULL passed"}; |
221 | 0 | } |
222 | 0 | else if (!out_timestamp) { |
223 | 0 | return {heif_error_Input_does_not_exist, heif_suberror_Invalid_parameter_value, "NULL heif_tai_timestamp_packet passed in"}; |
224 | 0 | } |
225 | | |
226 | 0 | *out_timestamp = nullptr; |
227 | | |
228 | | // Check if itemId exists |
229 | 0 | auto file = ctx->context->get_heif_file(); |
230 | 0 | if (!file->item_exists(itemId)) { |
231 | 0 | return {heif_error_Input_does_not_exist, heif_suberror_Invalid_parameter_value, "item does not exist"}; |
232 | 0 | } |
233 | | |
234 | | // Check if itai exists for itemId |
235 | 0 | auto itai = file->get_property_for_item<Box_itai>(itemId); |
236 | 0 | if (!itai) { |
237 | | // return NULL heif_tai_timestamp_packet; |
238 | 0 | return heif_error_success; |
239 | 0 | } |
240 | | |
241 | 0 | *out_timestamp = new heif_tai_timestamp_packet; |
242 | 0 | **out_timestamp = *itai->get_tai_timestamp_packet(); |
243 | |
|
244 | 0 | return heif_error_success; |
245 | 0 | } |
246 | | |
247 | | |
248 | | struct heif_error heif_image_set_tai_timestamp(struct heif_image* img, |
249 | | const struct heif_tai_timestamp_packet* timestamp) |
250 | 0 | { |
251 | 0 | Error err = img->image->set_tai_timestamp(timestamp); |
252 | 0 | if (err) { |
253 | 0 | return err.error_struct(img->image.get()); |
254 | 0 | } |
255 | 0 | else { |
256 | 0 | return heif_error_success; |
257 | 0 | } |
258 | 0 | } |
259 | | |
260 | | |
261 | | struct heif_error heif_image_get_tai_timestamp(const struct heif_image* img, |
262 | | struct heif_tai_timestamp_packet** out_timestamp) |
263 | 0 | { |
264 | 0 | if (!out_timestamp) { |
265 | 0 | return {heif_error_Input_does_not_exist, heif_suberror_Invalid_parameter_value, "NULL heif_tai_timestamp_packet passed in"}; |
266 | 0 | } |
267 | | |
268 | 0 | *out_timestamp = nullptr; |
269 | |
|
270 | 0 | auto* tai = img->image->get_tai_timestamp(); |
271 | 0 | if (!tai) { |
272 | 0 | *out_timestamp = nullptr; |
273 | 0 | return heif_error_success; |
274 | 0 | } |
275 | | |
276 | 0 | *out_timestamp = new heif_tai_timestamp_packet; |
277 | 0 | **out_timestamp = *tai; |
278 | |
|
279 | 0 | return heif_error_success; |
280 | 0 | } |
281 | | |