1 /*****************************************************************************
2 * desc_24.h: ISO/IEC 13818-1 Descriptor 0x24 (Content labeling descriptor)
3 *****************************************************************************
4 * Copyright (C) 2011 Unix Solutions Ltd.
5 *
6 * Authors: Georgi Chorbadzhiyski <georgi@unixsol.org>
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject
14 * to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *****************************************************************************/
27
28 /*
29 * Normative references:
30 * - ISO/IEC 13818-1:2007(E) (MPEG-2 Systems)
31 */
32
33 #ifndef __BITSTREAM_MPEG_DESC_24_H__
34 #define __BITSTREAM_MPEG_DESC_24_H__
35
36 #include <inttypes.h> /* PRIu64 */
37
38 #include <bitstream/common.h>
39 #include <bitstream/mpeg/psi/descriptors.h>
40
41 #ifdef __cplusplus
42 extern "C"
43 {
44 #endif
45
46 /*****************************************************************************
47 * Descriptor 0x24 (Content labeling descriptor)
48 *****************************************************************************/
49 #define DESC24_HEADER_SIZE (DESC_HEADER_SIZE + 3)
50
desc24_init(uint8_t * p_desc)51 static inline void desc24_init(uint8_t *p_desc)
52 {
53 desc_set_tag(p_desc, 0x24);
54 }
55
desc24_get_metadata_application_format(const uint8_t * p_desc)56 static inline uint16_t desc24_get_metadata_application_format(const uint8_t *p_desc)
57 {
58 return (p_desc[2] << 8) | p_desc[3];
59 }
60
desc24_set_metadata_application_format(uint8_t * p_desc,uint16_t i_format)61 static inline void desc24_set_metadata_application_format(uint8_t *p_desc, uint16_t i_format)
62 {
63 p_desc[2] = (i_format >> 8) & 0xff;
64 p_desc[3] = i_format & 0xff;
65 }
66
desc24_get_metadata_application_format_identifier(const uint8_t * p_desc)67 static inline uint32_t desc24_get_metadata_application_format_identifier(const uint8_t *p_desc)
68 {
69 if (desc24_get_metadata_application_format(p_desc) == 0xffff)
70 return (p_desc[4] << 24) | (p_desc[5] << 16) | (p_desc[6] << 8) | p_desc[7];
71 else
72 return 0;
73 }
74
desc24_set_metadata_application_format_identifier(uint8_t * p_desc,uint32_t i_identifier)75 static inline void desc24_set_metadata_application_format_identifier(uint8_t *p_desc, uint32_t i_identifier)
76 {
77 if (desc24_get_metadata_application_format(p_desc) != 0xffff)
78 return;
79 p_desc[4] = (i_identifier >> 24) & 0xff;
80 p_desc[5] = (i_identifier >> 16) & 0xff;
81 p_desc[6] = (i_identifier >> 8) & 0xff;
82 p_desc[7] = i_identifier & 0xff;
83 }
84
85 #define __ofs1 \
86 (4 + (desc24_get_metadata_application_format(p_desc) == 0xffff ? 4 : 0))
87
desc24_get_content_reference_id_record_flag(const uint8_t * p_desc)88 static inline bool desc24_get_content_reference_id_record_flag(const uint8_t *p_desc)
89 {
90 return (p_desc[__ofs1] & 0x80) == 0x80;
91 }
92
desc24_set_content_reference_id_record_flag(uint8_t * p_desc,bool b_flag)93 static inline void desc24_set_content_reference_id_record_flag(uint8_t *p_desc, bool b_flag)
94 {
95 uint8_t ofs = __ofs1;
96 p_desc[ofs] = (b_flag ? (p_desc[ofs] | 0x80) : (p_desc[ofs] &~ 0x80)) | 0x07;
97 }
98
desc24_get_content_time_base_indicator(const uint8_t * p_desc)99 static inline uint8_t desc24_get_content_time_base_indicator(const uint8_t *p_desc)
100 {
101 return (p_desc[__ofs1] >> 3) & 0x0f;
102 }
103
desc24_set_content_time_base_indicator(uint8_t * p_desc,uint8_t i_indicator)104 static inline void desc24_set_content_time_base_indicator(uint8_t *p_desc, uint8_t i_indicator)
105 {
106 uint8_t ofs = __ofs1;
107 p_desc[ofs] = (p_desc[ofs] & 0x80) | ((i_indicator & 0x0f) << 3) | 0x07;
108 }
109
desc24_get_content_reference_id_length(const uint8_t * p_desc)110 static inline uint8_t desc24_get_content_reference_id_length(const uint8_t *p_desc)
111 {
112 return desc24_get_content_reference_id_record_flag(p_desc) ? p_desc[__ofs1 + 1] : 0;
113 }
114
desc24_get_content_reference_id_data(const uint8_t * p_desc)115 static inline const uint8_t *desc24_get_content_reference_id_data(const uint8_t *p_desc)
116 {
117 return desc24_get_content_reference_id_record_flag(p_desc) ? p_desc + __ofs1 + 2 : NULL;
118 }
119
desc24_get_content_reference_id(const uint8_t * p_desc,uint8_t * i_length)120 static inline const uint8_t *desc24_get_content_reference_id(const uint8_t *p_desc, uint8_t *i_length)
121 {
122 *i_length = desc24_get_content_reference_id_length(p_desc);
123 return desc24_get_content_reference_id_data(p_desc);
124 }
125
desc24_set_content_reference_id_record(uint8_t * p_desc,uint8_t i_length,uint8_t * p_data)126 static inline void desc24_set_content_reference_id_record(uint8_t *p_desc, uint8_t i_length, uint8_t *p_data)
127 {
128 if (desc24_get_content_reference_id_record_flag(p_desc)) {
129 uint8_t ofs = __ofs1;
130 p_desc[ofs + 1] = i_length;
131 memcpy(p_desc + ofs + 2, p_data, i_length);
132 }
133 }
134
135
136 #define __ofs2 \
137 (__ofs1 + 1 + \
138 (desc24_get_content_reference_id_record_flag(p_desc) \
139 ? 1 + desc24_get_content_reference_id_length(p_desc) \
140 : 0 \
141 ) \
142 )
143
desc24_get_content_time_base_value(const uint8_t * p_desc)144 static inline uint64_t desc24_get_content_time_base_value(const uint8_t *p_desc)
145 {
146 uint8_t i_indicator = desc24_get_content_time_base_indicator(p_desc);
147 if (i_indicator == 1 || i_indicator == 2) {
148 uint8_t ofs = __ofs2;
149 return (uint64_t)(
150 (((uint64_t)p_desc[ofs] & 0x01ull) << 32) |
151 ((uint64_t)p_desc[ofs + 1] << 24) |
152 ((uint64_t)p_desc[ofs + 2] << 16) |
153 ((uint64_t)p_desc[ofs + 3] << 8) |
154 (uint64_t)p_desc[ofs + 4]
155 );
156 } else {
157 return 0;
158 }
159 }
160
desc24_set_content_time_base_value(uint8_t * p_desc,uint64_t i_value)161 static inline void desc24_set_content_time_base_value(uint8_t *p_desc, uint64_t i_value)
162 {
163 uint8_t i_indicator = desc24_get_content_time_base_indicator(p_desc);
164 if (i_indicator == 1 || i_indicator == 2) {
165 uint8_t ofs = __ofs2;
166 p_desc[ofs + 0] = 0xfe | ((i_value >> 32) & 0x01);
167 p_desc[ofs + 1] = (i_value >> 24) & 0xff;
168 p_desc[ofs + 2] = (i_value >> 16) & 0xff;
169 p_desc[ofs + 3] = (i_value >> 8) & 0xff;
170 p_desc[ofs + 4] = i_value & 0xff;
171 }
172 }
173
desc24_get_metadata_time_base_value(const uint8_t * p_desc)174 static inline uint64_t desc24_get_metadata_time_base_value(const uint8_t *p_desc)
175 {
176 uint8_t i_indicator = desc24_get_content_time_base_indicator(p_desc);
177 if (i_indicator == 1 || i_indicator == 2) {
178 uint8_t ofs = __ofs2 + 5;
179 return (uint64_t)(
180 (((uint64_t)p_desc[ofs] & 0x01ull) << 32) |
181 ((uint64_t)p_desc[ofs + 1] << 24) |
182 ((uint64_t)p_desc[ofs + 2] << 16) |
183 ((uint64_t)p_desc[ofs + 3] << 8) |
184 (uint64_t)p_desc[ofs + 4]
185 );
186 } else {
187 return 0;
188 }
189 }
190
desc24_set_metadata_time_base_value(uint8_t * p_desc,uint64_t i_value)191 static inline void desc24_set_metadata_time_base_value(uint8_t *p_desc, uint64_t i_value)
192 {
193 uint8_t i_indicator = desc24_get_content_time_base_indicator(p_desc);
194 if (i_indicator == 1 || i_indicator == 2) {
195 uint8_t ofs = __ofs2 + 5;
196 p_desc[ofs + 0] = 0xfe | ((i_value >> 32) & 0x01);
197 p_desc[ofs + 1] = (i_value >> 24) & 0xff;
198 p_desc[ofs + 2] = (i_value >> 16) & 0xff;
199 p_desc[ofs + 3] = (i_value >> 8) & 0xff;
200 p_desc[ofs + 4] = i_value & 0xff;
201 }
202 }
203
204
desc24_get_content_id(const uint8_t * p_desc)205 static inline uint8_t desc24_get_content_id(const uint8_t *p_desc)
206 {
207 uint8_t i_indicator = desc24_get_content_time_base_indicator(p_desc);
208 if (i_indicator == 2) {
209 uint8_t ofs = __ofs2 + 10;
210 return p_desc[ofs] & 0x7f;
211 } else {
212 return 0;
213 }
214 }
215
desc24_set_content_id(uint8_t * p_desc,uint8_t i_content_id)216 static inline void desc24_set_content_id(uint8_t *p_desc, uint8_t i_content_id)
217 {
218 uint8_t i_indicator = desc24_get_content_time_base_indicator(p_desc);
219 if (i_indicator == 2) {
220 uint8_t ofs = __ofs2 + 10;
221 p_desc[ofs + 0] = 0x80 | i_content_id;
222 }
223 }
224
225
desc24_get_time_base_association_data_length(const uint8_t * p_desc)226 static inline uint8_t desc24_get_time_base_association_data_length(const uint8_t *p_desc)
227 {
228 uint8_t i_indicator = desc24_get_content_time_base_indicator(p_desc);
229 return (i_indicator >= 3 && i_indicator <= 7) ? p_desc[__ofs2] : 0;
230 }
231
desc24_get_time_base_association_data(const uint8_t * p_desc)232 static inline const uint8_t *desc24_get_time_base_association_data(const uint8_t *p_desc)
233 {
234 uint8_t i_indicator = desc24_get_content_time_base_indicator(p_desc);
235 return (i_indicator >= 3 && i_indicator <= 7) ? p_desc + 1 + __ofs2 : NULL;
236 }
237
desc24_get_time_base_association(const uint8_t * p_desc,uint8_t * i_length)238 static inline const uint8_t *desc24_get_time_base_association(const uint8_t *p_desc, uint8_t *i_length)
239 {
240 *i_length = desc24_get_time_base_association_data_length(p_desc);
241 return desc24_get_time_base_association_data(p_desc);
242 }
243
desc24_set_time_base_association(uint8_t * p_desc,uint8_t i_length,uint8_t * p_data)244 static inline void desc24_set_time_base_association(uint8_t *p_desc, uint8_t i_length, uint8_t *p_data)
245 {
246 uint8_t i_indicator = desc24_get_content_time_base_indicator(p_desc);
247 if (i_indicator >= 3 && i_indicator <= 7) {
248 uint8_t ofs = __ofs2;
249 p_desc[ofs] = i_length;
250 memcpy(p_desc + ofs + 1, p_data, i_length);
251 }
252 }
253
254 #undef __ofs1
255 #undef __ofs2
256
desc24_calc_length(const uint8_t * p_desc)257 static inline int desc24_calc_length(const uint8_t *p_desc)
258 {
259 int i_length = DESC24_HEADER_SIZE - DESC_HEADER_SIZE;
260 uint8_t i_indicator = desc24_get_content_time_base_indicator(p_desc);
261 if (desc24_get_metadata_application_format(p_desc) == 0xffff)
262 i_length += 4;
263 if (desc24_get_content_reference_id_record_flag(p_desc))
264 i_length += 1 + desc24_get_content_reference_id_length(p_desc);
265 if (i_indicator == 1 || i_indicator == 2)
266 i_length += 10;
267 if (i_indicator == 2)
268 i_length += 1;
269 if (i_indicator >= 3 && i_indicator <= 7)
270 i_length += 1 + desc24_get_time_base_association_data_length(p_desc);
271 return i_length;
272 }
273
desc24_validate(const uint8_t * p_desc)274 static inline bool desc24_validate(const uint8_t *p_desc)
275 {
276 return desc24_calc_length(p_desc) <= desc_get_length(p_desc);
277 }
278
desc24_set_length(uint8_t * p_desc)279 static inline void desc24_set_length(uint8_t *p_desc)
280 {
281 desc_set_length(p_desc, desc24_calc_length(p_desc));
282 }
283
desc24_print(const uint8_t * p_desc,f_print pf_print,void * opaque,print_type_t i_print_type)284 static inline void desc24_print(const uint8_t *p_desc, f_print pf_print,
285 void *opaque, print_type_t i_print_type)
286 {
287 uint8_t i;
288 uint8_t i_content_reference_id_length;
289 uint8_t i_time_base_association_data_length;
290 const uint8_t *p_content_reference_id = desc24_get_content_reference_id(p_desc, &i_content_reference_id_length);
291 const uint8_t *p_time_base_association_data = desc24_get_time_base_association(p_desc, &i_time_base_association_data_length);
292 char psz_content[2 * 255 + 1];
293 char psz_time_base[2 * 255 + 1];
294
295 for (i = 0; i < i_content_reference_id_length; i++)
296 sprintf(psz_content + 2 * i, "%02x", p_content_reference_id[i]);
297 psz_content[2 * i] = '\0';
298
299 for (i = 0; i < i_time_base_association_data_length; i++)
300 sprintf(psz_time_base + 2 * i, "%02x", p_time_base_association_data[i]);
301 psz_time_base[2 * i] = '\0';
302
303
304 switch (i_print_type) {
305 case PRINT_XML:
306 pf_print(opaque,
307 "<CONTENT_LABELING_DESC metadata_application_format=\"0x%04x\""
308 " metadata_application_format_identifier=\"0x%08x\""
309 " content_reference_id_record_flag=\"%u\""
310 " content_reference_id_record_length=\"%u\""
311 " content_reference_id_record=\"%s\""
312 " content_time_base_indicator=\"%u\""
313 " content_time_base_value=\"%" PRIu64 "\""
314 " metadata_time_base_value=\"%" PRIu64 "\""
315 " content_id=\"%u\""
316 " time_base_association_data_length=\"%u\""
317 " time_base_association_data=\"%s\"/>",
318 desc24_get_metadata_application_format(p_desc),
319 desc24_get_metadata_application_format_identifier(p_desc),
320 desc24_get_content_reference_id_record_flag(p_desc),
321 desc24_get_content_reference_id_length(p_desc),
322 psz_content, // desc24_get_content_reference_id_data(p_desc)
323 desc24_get_content_time_base_indicator(p_desc),
324 desc24_get_content_time_base_value(p_desc),
325 desc24_get_metadata_time_base_value(p_desc),
326 desc24_get_content_id(p_desc),
327 desc24_get_time_base_association_data_length(p_desc),
328 psz_time_base // desc24_get_time_base_association_data(p_desc)
329 );
330 break;
331 default:
332 pf_print(opaque,
333 " - desc 24 content_labeling metadata_application_format=0x%04x"
334 " metadata_application_format_identifier=0x%08x"
335 " content_reference_id_record_flag=%u"
336 " content_reference_id_record_length=%u"
337 " content_reference_id_record=\"%s\""
338 " content_time_base_indicator=%u"
339 " content_time_base_value=\"%" PRIu64 "\""
340 " metadata_time_base_value=\"%" PRIu64 "\""
341 " content_id=%u"
342 " time_base_association_data_length=%u"
343 " time_base_association_data=\"%s\"",
344 desc24_get_metadata_application_format(p_desc),
345 desc24_get_metadata_application_format_identifier(p_desc),
346 desc24_get_content_reference_id_record_flag(p_desc),
347 desc24_get_content_reference_id_length(p_desc),
348 psz_content, // desc24_get_content_reference_id_data(p_desc)
349 desc24_get_content_time_base_indicator(p_desc),
350 desc24_get_content_time_base_value(p_desc),
351 desc24_get_metadata_time_base_value(p_desc),
352 desc24_get_content_id(p_desc),
353 desc24_get_time_base_association_data_length(p_desc),
354 psz_time_base // desc24_get_time_base_association_data(p_desc)
355 );
356 }
357 }
358
359 #ifdef __cplusplus
360 }
361 #endif
362
363 #endif
364