1 /*****************************************************************************
2  * ts.h: ISO/IEC 13818-1 Transport Stream
3  *****************************************************************************
4  * Copyright (C) 2009-2010 VideoLAN
5  *
6  * Authors: Christophe Massiot <massiot@via.ecp.fr>
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_TS_H__
34 #define __BITSTREAM_MPEG_TS_H__
35 
36 #include <stdlib.h>   /* malloc */
37 #include <stdint.h>   /* uint8_t, uint16_t, etc... */
38 #include <stdbool.h>  /* bool */
39 #include <string.h>   /* memset */
40 
41 #ifdef __cplusplus
42 extern "C"
43 {
44 #endif
45 
46 /*****************************************************************************
47  * TS header
48  *****************************************************************************/
49 #define TS_SIZE             188
50 #define TS_HEADER_SIZE      4
51 #define TS_HEADER_SIZE_AF   6
52 #define TS_HEADER_SIZE_PCR  12
53 
54 #define TS_DECLARE(p_ts)    \
55     uint8_t p_ts[TS_SIZE]
56 
ts_allocate(void)57 static inline uint8_t *ts_allocate(void)
58 {
59     return (uint8_t *)malloc(TS_SIZE * sizeof(uint8_t));
60 }
61 
ts_init(uint8_t * p_ts)62 static inline void ts_init(uint8_t *p_ts)
63 {
64     p_ts[0] = 0x47;
65     p_ts[1] = 0x0;
66     p_ts[2] = 0x0;
67     p_ts[3] = 0x0;
68 }
69 
ts_set_transporterror(uint8_t * p_ts)70 static inline void ts_set_transporterror(uint8_t *p_ts)
71 {
72     p_ts[1] |= 0x80;
73 }
74 
ts_get_transporterror(const uint8_t * p_ts)75 static inline bool ts_get_transporterror(const uint8_t *p_ts)
76 {
77     return !!(p_ts[1] & 0x80);
78 }
79 
ts_set_unitstart(uint8_t * p_ts)80 static inline void ts_set_unitstart(uint8_t *p_ts)
81 {
82     p_ts[1] |= 0x40;
83 }
84 
ts_get_unitstart(const uint8_t * p_ts)85 static inline bool ts_get_unitstart(const uint8_t *p_ts)
86 {
87     return !!(p_ts[1] & 0x40);
88 }
89 
ts_set_transportpriority(uint8_t * p_ts)90 static inline void ts_set_transportpriority(uint8_t *p_ts)
91 {
92     p_ts[1] |= 0x20;
93 }
94 
ts_get_transportpriority(const uint8_t * p_ts)95 static inline bool ts_get_transportpriority(const uint8_t *p_ts)
96 {
97     return !!(p_ts[1] & 0x20);
98 }
99 
ts_set_pid(uint8_t * p_ts,uint16_t i_pid)100 static inline void ts_set_pid(uint8_t *p_ts, uint16_t i_pid)
101 {
102     p_ts[1] &= ~0x1f;
103     p_ts[1] |= (i_pid >> 8) & 0x1f;
104     p_ts[2] = i_pid & 0xff;
105 }
106 
ts_get_pid(const uint8_t * p_ts)107 static inline uint16_t ts_get_pid(const uint8_t *p_ts)
108 {
109     return ((p_ts[1] & 0x1f) << 8) | p_ts[2];
110 }
111 
ts_set_cc(uint8_t * p_ts,uint8_t i_cc)112 static inline void ts_set_cc(uint8_t *p_ts, uint8_t i_cc)
113 {
114     p_ts[3] &= ~0xf;
115     p_ts[3] |= (i_cc & 0xf);
116 }
117 
ts_get_cc(const uint8_t * p_ts)118 static inline uint8_t ts_get_cc(const uint8_t *p_ts)
119 {
120     return p_ts[3] & 0xf;
121 }
122 
ts_set_payload(uint8_t * p_ts)123 static inline void ts_set_payload(uint8_t *p_ts)
124 {
125     p_ts[3] |= 0x10;
126 }
127 
ts_has_payload(const uint8_t * p_ts)128 static inline bool ts_has_payload(const uint8_t *p_ts)
129 {
130     return !!(p_ts[3] & 0x10);
131 }
132 
ts_set_adaptation(uint8_t * p_ts,uint8_t i_length)133 static inline void ts_set_adaptation(uint8_t *p_ts, uint8_t i_length)
134 {
135     p_ts[3] |= 0x20;
136     p_ts[4] = i_length;
137     if (i_length)
138         p_ts[5] = 0x0;
139     if (i_length > 1)
140         memset(&p_ts[6], 0xff, i_length - 1); /* stuffing */
141 }
142 
ts_has_adaptation(const uint8_t * p_ts)143 static inline bool ts_has_adaptation(const uint8_t *p_ts)
144 {
145     return !!(p_ts[3] & 0x20);
146 }
147 
ts_get_adaptation(const uint8_t * p_ts)148 static inline uint8_t ts_get_adaptation(const uint8_t *p_ts)
149 {
150     return p_ts[4];
151 }
152 
ts_set_scrambling(uint8_t * p_ts,uint8_t i_scrambling)153 static inline void ts_set_scrambling(uint8_t *p_ts, uint8_t i_scrambling)
154 {
155     p_ts[3] &= ~0xc0;
156     p_ts[3] |= i_scrambling << 6;
157 }
158 
ts_get_scrambling(const uint8_t * p_ts)159 static inline uint8_t ts_get_scrambling(const uint8_t *p_ts)
160 {
161     return (p_ts[3] & 0xc0) >> 6;
162 }
163 
ts_validate(const uint8_t * p_ts)164 static inline bool ts_validate(const uint8_t *p_ts)
165 {
166     return p_ts[0] == 0x47;
167 }
168 
169 /*****************************************************************************
170  * TS payload
171  *****************************************************************************/
ts_pad(uint8_t * p_ts)172 static inline void ts_pad(uint8_t *p_ts)
173 {
174     ts_init(p_ts);
175     ts_set_pid(p_ts, 0x1fff);
176     ts_set_cc(p_ts, 0);
177     ts_set_payload(p_ts);
178     memset(p_ts + 4, 0xff, TS_SIZE - 4);
179 }
180 
ts_payload(uint8_t * p_ts)181 static inline uint8_t *ts_payload(uint8_t *p_ts)
182 {
183     if (!ts_has_payload(p_ts))
184         return p_ts + TS_SIZE;
185     if (!ts_has_adaptation(p_ts))
186         return p_ts + TS_HEADER_SIZE;
187     return p_ts + TS_HEADER_SIZE + 1 + ts_get_adaptation(p_ts);
188 }
189 
ts_section(uint8_t * p_ts)190 static inline uint8_t *ts_section(uint8_t *p_ts)
191 {
192     if (!ts_get_unitstart(p_ts))
193         return ts_payload(p_ts);
194 
195     return ts_payload(p_ts) + 1; /* pointer_field */
196 }
197 
ts_next_section(uint8_t * p_ts)198 static inline uint8_t *ts_next_section(uint8_t *p_ts)
199 {
200     uint8_t *p_payload;
201 
202     if (!ts_get_unitstart(p_ts))
203         return p_ts + TS_SIZE;
204     p_payload = ts_payload(p_ts);
205     if (p_payload >= p_ts + TS_SIZE)
206         return p_ts + TS_SIZE;
207 
208     return p_payload + *p_payload + 1; /* pointer_field */
209 }
210 
211 /*****************************************************************************
212  * Adaptation field
213  *****************************************************************************/
tsaf_set_discontinuity(uint8_t * p_ts)214 static inline void tsaf_set_discontinuity(uint8_t *p_ts)
215 {
216     p_ts[5] |= 0x80;
217 }
218 
tsaf_clear_discontinuity(uint8_t * p_ts)219 static inline void tsaf_clear_discontinuity(uint8_t *p_ts)
220 {
221     p_ts[5] &= ~0x80;
222 }
223 
tsaf_has_discontinuity(const uint8_t * p_ts)224 static inline bool tsaf_has_discontinuity(const uint8_t *p_ts)
225 {
226     return !!(p_ts[5] & 0x80);
227 }
228 
tsaf_set_randomaccess(uint8_t * p_ts)229 static inline void tsaf_set_randomaccess(uint8_t *p_ts)
230 {
231     p_ts[5] |= 0x40;
232 }
233 
tsaf_has_randomaccess(const uint8_t * p_ts)234 static inline bool tsaf_has_randomaccess(const uint8_t *p_ts)
235 {
236     return !!(p_ts[5] & 0x40);
237 }
238 
tsaf_set_streampriority(uint8_t * p_ts)239 static inline void tsaf_set_streampriority(uint8_t *p_ts)
240 {
241     p_ts[5] |= 0x20;
242 }
243 
tsaf_set_pcr(uint8_t * p_ts,uint64_t i_pcr)244 static inline void tsaf_set_pcr(uint8_t *p_ts, uint64_t i_pcr)
245 {
246     p_ts[5] |= 0x10;
247     p_ts[6] = (i_pcr >> 25) & 0xff;
248     p_ts[7] = (i_pcr >> 17) & 0xff;
249     p_ts[8] = (i_pcr >> 9) & 0xff;
250     p_ts[9] = (i_pcr >> 1) & 0xff;
251     p_ts[10] = 0x7e | ((i_pcr << 7) & 0x80);
252     p_ts[11] = 0;
253 }
254 
tsaf_set_pcrext(uint8_t * p_ts,uint16_t i_pcr_ext)255 static inline void tsaf_set_pcrext(uint8_t *p_ts, uint16_t i_pcr_ext)
256 {
257     p_ts[10] |= (i_pcr_ext >> 8) & 0x1;
258     p_ts[11] = i_pcr_ext & 0xff;
259 }
260 
tsaf_has_pcr(const uint8_t * p_ts)261 static inline bool tsaf_has_pcr(const uint8_t *p_ts)
262 {
263     return !!(p_ts[5] & 0x10);
264 }
265 
tsaf_get_pcr(const uint8_t * p_ts)266 static inline uint64_t tsaf_get_pcr(const uint8_t *p_ts)
267 {
268     return ((uint64_t) p_ts[6] << 25) | (p_ts[7] << 17) | (p_ts[8] << 9) | (p_ts[9] << 1) |
269            (p_ts[10] >> 7);
270 }
271 
tsaf_get_pcrext(const uint8_t * p_ts)272 static inline uint64_t tsaf_get_pcrext(const uint8_t *p_ts)
273 {
274     return ((p_ts[10] & 1) << 8) | p_ts[11];
275 }
276 
277 /*****************************************************************************
278  * TS payload gathering
279  *****************************************************************************/
ts_check_duplicate(uint8_t i_cc,uint8_t i_last_cc)280 static inline bool ts_check_duplicate(uint8_t i_cc, uint8_t i_last_cc)
281 {
282     return i_last_cc == i_cc;
283 }
284 
ts_check_discontinuity(uint8_t i_cc,uint8_t i_last_cc)285 static inline bool ts_check_discontinuity(uint8_t i_cc, uint8_t i_last_cc)
286 {
287     return (i_last_cc + 17 - i_cc) % 16;
288 }
289 
290 #ifdef __cplusplus
291 }
292 #endif
293 
294 #endif
295