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