1 /*****************************************************************************
2 * pat.c: PAT decoder/generator
3 *----------------------------------------------------------------------------
4 * Copyright (C) 2001-2012 VideoLAN
5 * $Id$
6 *
7 * Authors: Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr>
8 * Jean-Paul Saman <jpsaman@videolan.org>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 *
24 *----------------------------------------------------------------------------
25 *
26 *****************************************************************************/
27
28 #include "config.h"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdbool.h>
33
34 #if defined(HAVE_INTTYPES_H)
35 #include <inttypes.h>
36 #elif defined(HAVE_STDINT_H)
37 #include <stdint.h>
38 #endif
39
40 #include <assert.h>
41
42 #include "../dvbpsi.h"
43 #include "../dvbpsi_private.h"
44 #include "../psi.h"
45 #include "pat.h"
46 #include "pat_private.h"
47
48 /*****************************************************************************
49 * dvbpsi_pat_attach
50 *****************************************************************************
51 * Initialize a PAT decoder and return a handle on it.
52 *****************************************************************************/
dvbpsi_pat_attach(dvbpsi_t * p_dvbpsi,dvbpsi_pat_callback pf_callback,void * p_cb_data)53 bool dvbpsi_pat_attach(dvbpsi_t *p_dvbpsi, dvbpsi_pat_callback pf_callback,
54 void* p_cb_data)
55 {
56 assert(p_dvbpsi);
57 assert(p_dvbpsi->p_decoder == NULL);
58
59 /* PSI decoder configuration and initial state */
60 dvbpsi_pat_decoder_t *p_pat_decoder;
61 p_pat_decoder = (dvbpsi_pat_decoder_t*) dvbpsi_decoder_new(&dvbpsi_pat_sections_gather,
62 1024, true, sizeof(dvbpsi_pat_decoder_t));
63 if (p_pat_decoder == NULL)
64 return false;
65
66 /* PAT decoder information */
67 p_pat_decoder->pf_pat_callback = pf_callback;
68 p_pat_decoder->p_cb_data = p_cb_data;
69 p_pat_decoder->p_building_pat = NULL;
70
71 p_dvbpsi->p_decoder = DVBPSI_DECODER(p_pat_decoder);
72 return true;
73 }
74
75 /*****************************************************************************
76 * dvbpsi_pat_detach
77 *****************************************************************************
78 * Close a PAT decoder. The handle isn't valid any more.
79 *****************************************************************************/
dvbpsi_pat_detach(dvbpsi_t * p_dvbpsi)80 void dvbpsi_pat_detach(dvbpsi_t *p_dvbpsi)
81 {
82 assert(p_dvbpsi);
83 assert(p_dvbpsi->p_decoder);
84
85 dvbpsi_pat_decoder_t* p_pat_decoder = (dvbpsi_pat_decoder_t*)p_dvbpsi->p_decoder;
86 if (p_pat_decoder->p_building_pat)
87 dvbpsi_pat_delete(p_pat_decoder->p_building_pat);
88 p_pat_decoder->p_building_pat = NULL;
89
90 dvbpsi_decoder_delete(p_dvbpsi->p_decoder);
91 p_dvbpsi->p_decoder = NULL;
92 }
93
94 /*****************************************************************************
95 * dvbpsi_pat_init
96 *****************************************************************************
97 * Initialize a pre-allocated dvbpsi_pat_t structure.
98 *****************************************************************************/
dvbpsi_pat_init(dvbpsi_pat_t * p_pat,uint16_t i_ts_id,uint8_t i_version,bool b_current_next)99 void dvbpsi_pat_init(dvbpsi_pat_t* p_pat, uint16_t i_ts_id, uint8_t i_version,
100 bool b_current_next)
101 {
102 assert(p_pat);
103
104 p_pat->i_ts_id = i_ts_id;
105 p_pat->i_version = i_version;
106 p_pat->b_current_next = b_current_next;
107 p_pat->p_first_program = NULL;
108 }
109
110 /*****************************************************************************
111 * dvbpsi_pat_new
112 *****************************************************************************
113 * Allocate and Initialize a newly allocated dvbpsi_pat_t structure.
114 *****************************************************************************/
dvbpsi_pat_new(uint16_t i_ts_id,uint8_t i_version,bool b_current_next)115 dvbpsi_pat_t *dvbpsi_pat_new(uint16_t i_ts_id, uint8_t i_version,
116 bool b_current_next)
117 {
118 dvbpsi_pat_t *p_pat = (dvbpsi_pat_t*)malloc(sizeof(dvbpsi_pat_t));
119 if (p_pat)
120 dvbpsi_pat_init(p_pat, i_ts_id, i_version, b_current_next);
121 return p_pat;
122 }
123
124 /*****************************************************************************
125 * dvbpsi_pat_empty
126 *****************************************************************************
127 * Clean a dvbpsi_pat_t structure.
128 *****************************************************************************/
dvbpsi_pat_empty(dvbpsi_pat_t * p_pat)129 void dvbpsi_pat_empty(dvbpsi_pat_t* p_pat)
130 {
131 dvbpsi_pat_program_t* p_program = p_pat->p_first_program;
132
133 while(p_program != NULL)
134 {
135 dvbpsi_pat_program_t* p_tmp = p_program->p_next;
136 free(p_program);
137 p_program = p_tmp;
138 }
139 p_pat->p_first_program = NULL;
140 }
141
142 /*****************************************************************************
143 * dvbpsi_pat_delete
144 *****************************************************************************
145 * Clean and Delete dvbpsi_pat_t structure.
146 *****************************************************************************/
dvbpsi_pat_delete(dvbpsi_pat_t * p_pat)147 void dvbpsi_pat_delete(dvbpsi_pat_t *p_pat)
148 {
149 if (p_pat)
150 dvbpsi_pat_empty(p_pat);
151 free(p_pat);
152 }
153
154 /*****************************************************************************
155 * dvbpsi_pat_program_add
156 *****************************************************************************
157 * Add a program at the end of the PAT.
158 *****************************************************************************/
dvbpsi_pat_program_add(dvbpsi_pat_t * p_pat,uint16_t i_number,uint16_t i_pid)159 dvbpsi_pat_program_t* dvbpsi_pat_program_add(dvbpsi_pat_t* p_pat,
160 uint16_t i_number, uint16_t i_pid)
161 {
162 dvbpsi_pat_program_t* p_program;
163
164 /* PID = 0 is invalid for programs
165 * FIXME: check for other fixed PIDs too. */
166 if (i_pid == 0)
167 return NULL;
168
169 p_program = (dvbpsi_pat_program_t*) malloc(sizeof(dvbpsi_pat_program_t));
170 if (p_program == NULL)
171 return NULL;
172
173 p_program->i_number = i_number;
174 p_program->i_pid = i_pid;
175 p_program->p_next = NULL;
176
177 if (p_pat->p_first_program == NULL)
178 p_pat->p_first_program = p_program;
179 else
180 {
181 dvbpsi_pat_program_t* p_last_program = p_pat->p_first_program;
182 while (p_last_program->p_next != NULL)
183 p_last_program = p_last_program->p_next;
184 p_last_program->p_next = p_program;
185 }
186
187 return p_program;
188 }
189
190 /* */
dvbpsi_ReInitPAT(dvbpsi_pat_decoder_t * p_decoder,const bool b_force)191 static void dvbpsi_ReInitPAT(dvbpsi_pat_decoder_t* p_decoder, const bool b_force)
192 {
193 assert(p_decoder);
194
195 dvbpsi_decoder_reset(DVBPSI_DECODER(p_decoder), b_force);
196
197 /* Force redecoding */
198 if (b_force)
199 {
200 /* Free structures */
201 if (p_decoder->p_building_pat)
202 dvbpsi_pat_delete(p_decoder->p_building_pat);
203 }
204 p_decoder->p_building_pat = NULL;
205 }
206
dvbpsi_CheckPAT(dvbpsi_t * p_dvbpsi,dvbpsi_psi_section_t * p_section)207 static bool dvbpsi_CheckPAT(dvbpsi_t *p_dvbpsi, dvbpsi_psi_section_t *p_section)
208 {
209 bool b_reinit = false;
210 assert(p_dvbpsi->p_decoder);
211
212 dvbpsi_pat_decoder_t* p_pat_decoder;
213 p_pat_decoder = (dvbpsi_pat_decoder_t *)p_dvbpsi->p_decoder;
214
215 /* Perform a few sanity checks */
216 if (p_pat_decoder->p_building_pat->i_ts_id != p_section->i_extension)
217 {
218 /* transport_stream_id */
219 dvbpsi_error(p_dvbpsi, "PAT decoder",
220 "'transport_stream_id' differs"
221 " whereas no TS discontinuity has occured");
222 b_reinit = true;
223 }
224 else if (p_pat_decoder->p_building_pat->i_version != p_section->i_version)
225 {
226 /* version_number */
227 dvbpsi_error(p_dvbpsi, "PAT decoder",
228 "'version_number' differs"
229 " whereas no discontinuity has occured");
230 b_reinit = true;
231 }
232 else if (p_pat_decoder->i_last_section_number != p_section->i_last_number)
233 {
234 /* last_section_number */
235 dvbpsi_error(p_dvbpsi, "PAT decoder",
236 "'last_section_number' differs"
237 " whereas no discontinuity has occured");
238 b_reinit = true;
239 }
240
241 return b_reinit;
242 }
243
dvbpsi_AddSectionPAT(dvbpsi_t * p_dvbpsi,dvbpsi_pat_decoder_t * p_pat_decoder,dvbpsi_psi_section_t * p_section)244 static bool dvbpsi_AddSectionPAT(dvbpsi_t *p_dvbpsi, dvbpsi_pat_decoder_t *p_pat_decoder,
245 dvbpsi_psi_section_t* p_section)
246 {
247 assert(p_dvbpsi);
248 assert(p_pat_decoder);
249 assert(p_section);
250
251 /* Initialize the structures if it's the first section received */
252 if (p_pat_decoder->p_building_pat == NULL)
253 {
254 p_pat_decoder->p_building_pat = dvbpsi_pat_new(p_section->i_extension,
255 p_section->i_version, p_section->b_current_next);
256 if (p_pat_decoder->p_building_pat == NULL)
257 return false;
258
259 p_pat_decoder->i_last_section_number = p_section->i_last_number;
260 }
261
262 /* Add to linked list of sections */
263 if (dvbpsi_decoder_psi_section_add(DVBPSI_DECODER(p_pat_decoder), p_section))
264 dvbpsi_debug(p_dvbpsi, "PAT decoder", "overwrite section number %d",
265 p_section->i_number);
266 return true;
267 }
268
269 /*****************************************************************************
270 * dvbpsi_pat_sections_gather
271 *****************************************************************************
272 * Callback for the PSI decoder.
273 *****************************************************************************/
dvbpsi_pat_sections_gather(dvbpsi_t * p_dvbpsi,dvbpsi_psi_section_t * p_section)274 void dvbpsi_pat_sections_gather(dvbpsi_t* p_dvbpsi, dvbpsi_psi_section_t* p_section)
275 {
276 dvbpsi_pat_decoder_t* p_pat_decoder;
277
278 assert(p_dvbpsi);
279 assert(p_dvbpsi->p_decoder);
280
281 if (!dvbpsi_CheckPSISection(p_dvbpsi, p_section, 0x00, "PAT decoder"))
282 {
283 dvbpsi_DeletePSISections(p_section);
284 return;
285 }
286
287 /* Now we have a valid PAT section */
288 p_pat_decoder = (dvbpsi_pat_decoder_t *)p_dvbpsi->p_decoder;
289
290 /* TS discontinuity check */
291 if (p_pat_decoder->b_discontinuity)
292 {
293 dvbpsi_ReInitPAT(p_pat_decoder, true);
294 p_pat_decoder->b_discontinuity = false;
295 }
296 else
297 {
298 if (p_pat_decoder->p_building_pat)
299 {
300 if (dvbpsi_CheckPAT(p_dvbpsi, p_section))
301 dvbpsi_ReInitPAT(p_pat_decoder, true);
302 }
303 else
304 {
305 if( (p_pat_decoder->b_current_valid)
306 && (p_pat_decoder->current_pat.i_version == p_section->i_version)
307 && (p_pat_decoder->current_pat.b_current_next ==
308 p_section->b_current_next))
309 {
310 /* Don't decode since this version is already decoded */
311 dvbpsi_debug(p_dvbpsi, "PAT decoder",
312 "ignoring already decoded section %d",
313 p_section->i_number);
314 dvbpsi_DeletePSISections(p_section);
315 return;
316 }
317 }
318 }
319
320 /* Add section to PAT */
321 if (!dvbpsi_AddSectionPAT(p_dvbpsi, p_pat_decoder, p_section))
322 {
323 dvbpsi_error(p_dvbpsi, "PAT decoder", "failed decoding section %d",
324 p_section->i_number);
325 dvbpsi_DeletePSISections(p_section);
326 return;
327 }
328
329 /* Check if we have all the sections */
330 if (dvbpsi_decoder_psi_sections_completed(DVBPSI_DECODER(p_pat_decoder)))
331 {
332 assert(p_pat_decoder->pf_pat_callback);
333
334 /* Save the current information */
335 p_pat_decoder->current_pat = *p_pat_decoder->p_building_pat;
336
337 /* Decode the sections */
338 if (dvbpsi_pat_sections_decode(p_pat_decoder->p_building_pat,
339 p_pat_decoder->p_sections))
340 p_pat_decoder->b_current_valid = true;
341
342 /* signal the new PAT */
343 if (p_pat_decoder->b_current_valid)
344 p_pat_decoder->pf_pat_callback(p_pat_decoder->p_cb_data,
345 p_pat_decoder->p_building_pat);
346
347 /* Delete sectioins and Reinitialize the structures */
348 dvbpsi_ReInitPAT(p_pat_decoder, !p_pat_decoder->b_current_valid);
349 assert(p_pat_decoder->p_sections == NULL);
350 }
351 }
352
353 /*****************************************************************************
354 * dvbpsi_DecodePATSection
355 *****************************************************************************
356 * Decode sections into a PAT table. The function returns 'true' on success,
357 * 'false' otherwise.
358 *****************************************************************************/
dvbpsi_pat_sections_decode(dvbpsi_pat_t * p_pat,dvbpsi_psi_section_t * p_section)359 bool dvbpsi_pat_sections_decode(dvbpsi_pat_t* p_pat, dvbpsi_psi_section_t* p_section)
360 {
361 bool b_valid = false;
362 while (p_section)
363 {
364 for (uint8_t *p_byte = p_section->p_payload_start;
365 p_byte < p_section->p_payload_end;
366 p_byte += 4)
367 {
368 uint16_t i_program_number = ((uint16_t)(p_byte[0]) << 8) | p_byte[1];
369 uint16_t i_pid = ((uint16_t)(p_byte[2] & 0x1f) << 8) | p_byte[3];
370 dvbpsi_pat_program_t* p_program = dvbpsi_pat_program_add(p_pat, i_program_number, i_pid);
371 if (p_program)
372 b_valid = true;
373 }
374
375 p_section = p_section->p_next;
376 }
377 return b_valid;
378 }
379
380 /*****************************************************************************
381 * dvbpsi_pat_sections_generate
382 *****************************************************************************
383 * Generate PAT sections based on the dvbpsi_pat_t structure. The third
384 * argument is used to limit the number of program in each section (max: 253).
385 *****************************************************************************/
dvbpsi_pat_sections_generate(dvbpsi_t * p_dvbpsi,dvbpsi_pat_t * p_pat,int i_max_pps)386 dvbpsi_psi_section_t* dvbpsi_pat_sections_generate(dvbpsi_t *p_dvbpsi,
387 dvbpsi_pat_t* p_pat, int i_max_pps)
388 {
389 dvbpsi_psi_section_t* p_result = dvbpsi_NewPSISection(1024);
390 dvbpsi_psi_section_t* p_current = p_result;
391 dvbpsi_psi_section_t* p_prev;
392 dvbpsi_pat_program_t* p_program = p_pat->p_first_program;
393 int i_count = 0;
394
395 if (p_current == NULL)
396 {
397 dvbpsi_error(p_dvbpsi, "PAT encoder", "failed to allocate new PSI section");
398 return NULL;
399 }
400
401 /* A PAT section can carry up to 253 programs */
402 if((i_max_pps <= 0) || (i_max_pps > 253))
403 i_max_pps = 253;
404
405 p_current->i_table_id = 0;
406 p_current->b_syntax_indicator = true;
407 p_current->b_private_indicator = false;
408 p_current->i_length = 9; /* header + CRC_32 */
409 p_current->i_extension = p_pat->i_ts_id;
410 p_current->i_version = p_pat->i_version;
411 p_current->b_current_next = p_pat->b_current_next;
412 p_current->i_number = 0;
413 p_current->p_payload_end += 8; /* just after the header */
414 p_current->p_payload_start = p_current->p_payload_end;
415
416 /* PAT programs */
417 while (p_program != NULL)
418 {
419 /* New section if needed */
420 if (++i_count > i_max_pps)
421 {
422 p_prev = p_current;
423 p_current = dvbpsi_NewPSISection(1024);
424 if (p_current == NULL)
425 {
426 dvbpsi_error(p_dvbpsi, "PAT encoder", "failed to allocate new PSI section");
427 goto error;
428 }
429 p_prev->p_next = p_current;
430 i_count = 1;
431
432 p_current->i_table_id = 0;
433 p_current->b_syntax_indicator = true;
434 p_current->b_private_indicator = false;
435 p_current->i_length = 9; /* header + CRC_32 */
436 p_current->i_extension = p_pat->i_ts_id;
437 p_current->i_version = p_pat->i_version;
438 p_current->b_current_next = p_pat->b_current_next;
439 p_current->i_number = p_prev->i_number + 1;
440 p_current->p_payload_end += 8; /* just after the header */
441 p_current->p_payload_start = p_current->p_payload_end;
442 }
443
444 /* p_payload_end is where the program begins */
445 p_current->p_payload_end[0] = p_program->i_number >> 8;
446 p_current->p_payload_end[1] = p_program->i_number;
447 p_current->p_payload_end[2] = (p_program->i_pid >> 8) | 0xe0;
448 p_current->p_payload_end[3] = p_program->i_pid;
449
450 /* Increase length by 4 */
451 p_current->p_payload_end += 4;
452 p_current->i_length += 4;
453
454 p_program = p_program->p_next;
455 }
456
457 /* Finalization */
458 p_prev = p_result;
459 while (p_prev != NULL)
460 {
461 p_prev->i_last_number = p_current->i_number;
462 dvbpsi_BuildPSISection(p_dvbpsi, p_prev);
463 p_prev = p_prev->p_next;
464 }
465
466 return p_result;
467
468 error:
469 /* Cleanup on error */
470 p_prev = p_result;
471 dvbpsi_DeletePSISections(p_prev);
472 return NULL;
473 }
474