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