source: svn/trunk/newcon3bcm2_21bu/BSEAV/lib/tspsi/tspsimgr.c

Last change on this file was 2, checked in by jglee, 11 years ago

first commit

  • Property svn:executable set to *
File size: 28.4 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2002-2010, Broadcom Corporation
3 *     All Rights Reserved
4 *     Confidential Property of Broadcom Corporation
5 *
6 *  THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE
7 *  AGREEMENT  BETWEEN THE USER AND BROADCOM.  YOU HAVE NO RIGHT TO USE OR
8 *  EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT.
9 *
10 * $brcm_Workfile: tspsimgr.c $
11 * $brcm_Revision: 21 $
12 * $brcm_Date: 4/26/10 1:20p $
13 *
14 * Module Description:
15 *
16 * Revision History:
17 *
18 * $brcm_Log: /BSEAV/lib/tspsi/tspsimgr.c $
19 *
20 * 21   4/26/10 1:20p erickson
21 * SW7405-3942: linux 2.6.31 BKNI_Sleep(1) appears to take only 1
22 * millisecond (as advertised). 400 BKNI_Sleep(1)'s is therefore not 4000
23 * msec. So, we need to change to BKNI_Sleep(10).
24 *
25 * 20   3/3/10 12:01p vsilyaev
26 * SW7405-3990: Added stream_type for DTS audio
27 *
28 * 19   11/23/09 5:51p katrep
29 * SW7405-3457:Add DRA support
30 *
31 * 18   8/14/09 3:51p erickson
32 * PR55994: fix #include for bsettop.h
33 *
34 * 17   1/20/08 10:59p katrep
35 * PR38591: Added support for AVS streams.
36 *
37 * 16   10/15/07 4:04p vishk
38 * PR 35263: IB-Converity (CID 420): OVERRUN_STATIC,
39 *
40 * 15   10/12/07 3:41p vishk
41 * PR 35263: IB-Converity (CID 420): OVERRUN_STATIC,
42 *
43 * 14   7/10/07 3:01p erickson
44 * PR31916: update tspsimgr for wider range of specs and codecs.
45 * consolidated duplicate code.
46 *
47 * 13   1/18/07 12:08p ahulse
48 * PR27186: Differentiate between parser and input bands. AKA, fixing
49 * bmessage from playback source
50 *
51 * 12   12/14/06 11:59a jjordan
52 * PR26473: add get timeout capability
53 *
54 * 11   11/16/06 4:02p erickson
55 * PR25993: remove bad/broken B_HAS_RAVE code. this is now defaulted in
56 * bmessage_stream_params_init.
57 *
58 * 10   7/28/06 12:39p erickson
59 * PR15309: must use filtergroups for RAVE platforms because multiple pid
60 * channels for the same band and pid are not allowed.
61 *
62 * 9   6/13/06 2:40p erickson
63 * PR18488: temporarily increasing timeout for 740x platforms
64 *
65 * 8   2/22/06 5:12p arbisman
66 * PR19269: Add support for ISO 14496-3 audio type
67 *
68 * 7   8/25/05 4:25p erickson
69 * PR16866: increase PAT and PMT default timeouts
70 *
71 * 6   8/12/05 3:28p erickson
72 * PR16659: added more debug
73 *
74 * 5   8/10/05 5:00p erickson
75 * PR16295: cleanup warning
76 *
77 * 4   8/10/05 11:38a erickson
78 * PR16295: insert programs into CHANNEL_INFO_T using program_number for
79 * consistency of scan order
80 *
81 * 3   3/15/05 2:52p erickson
82 * PR13415: changed bmessage_format parameter, added some debug
83 *
84 * 2   2/17/05 5:13p erickson
85 * PR14180: cleanup warning
86 *
87 * 1   2/7/05 11:34p dlwin
88 * Merge down for release 2005_REFSW_MERGETOMAIN:
89 *
90 * Irvine_BSEAVSW_Devel/11   2/7/05 4:58p erickson
91 * PR13908: fix warning
92 *
93 * Irvine_BSEAVSW_Devel/10   2/7/05 4:35p erickson
94 * PR13908: fix warnings
95 *
96 * Irvine_BSEAVSW_Devel/9   12/29/04 7:24p marcusk
97 * PR13701: Updated with support for H.264 Stream Type (0xB1)
98 *
99 * Irvine_BSEAVSW_Devel/8   12/20/04 1:56p erickson
100 * PR13595: removed error printout when you can't find the PAT
101 *
102 * Irvine_BSEAVSW_Devel/7   11/4/04 1:02p erickson
103 * PR13141: added pmt pid to PMT callback
104 *
105 * Irvine_BSEAVSW_Devel/6   7/29/04 7:39a erickson
106 * PR11682: no memcpy needed for parsing PMT information. Just call
107 * bmessage_stop after processing data. Transport message overflows
108 * aren't important and it will be quick anyway.
109 *
110 * Irvine_BSEAVSW_Devel/5   7/23/04 9:25a erickson
111 * PR11682: debug cleanup
112 *
113 * Irvine_BSEAVSW_Devel/4   7/21/04 12:07p erickson
114 * PR11682: refactored so that finer-grain control is available, without
115 * breaking existing api
116 *
117 * Irvine_BSEAVSW_Devel/3   7/6/04 3:56p erickson
118 * PR11771: settop api dataflow redesign
119 *
120 * Irvine_BSEAVSW_Devel/2   5/4/04 1:52p erickson
121 * PR10938: added bounds checking and PMT and PAT validation in order to
122 * prevent segfaults on bad data
123 *
124 * Irvine_BSEAVSW_Devel/12   2/5/04 11:54a erickson
125 * PR9497: usleep is not portable, so use the magnum kernel interface
126 *
127 * Irvine_BSEAVSW_Devel/11   12/19/03 3:47p erickson
128 * PR8731: need semicolon after BDBG_MODULE statement
129 *
130 * Irvine_BSEAVSW_Devel/10   12/8/03 4:16p marcusk
131 * PR 8895: Properly pack filter bytes properly (filter should always be
132 * passed in as byte ordered array)
133 *
134 * Irvine_BSEAVSW_Devel/9   11/24/03 10:17a erickson
135 * PR8714: program numbers can be 16 bit and we were only filtering on the
136 * lower 8 bits. This problem was introduced when converting to settop
137 * api.
138 *
139 * Irvine_BSEAVSW_Devel/8   10/31/03 1:28p erickson
140 * converted TODO into warning.
141 *
142 * Irvine_BSEAVSW_Devel/7   10/31/03 11:58a erickson
143 * settop api changes after internal review
144 *
145 * Irvine_BSEAVSW_Devel/6   10/28/03 11:28a erickson
146 * settop api reworks after internal design view
147 *
148 * Irvine_BSEAVSW_Devel/5   10/22/03 11:23a erickson
149 * settop api pass-through type conversion
150 *
151 * Irvine_BSEAVSW_Devel/4   9/19/03 2:31p erickson
152 * PR8074 - uninitialized memory
153 *
154 * Irvine_BSEAVSW_Devel/3   9/10/03 5:36p marcusk
155 * Updated to use new path
156 *
157 * Irvine_BSEAVSW_Devel/2   9/10/03 5:12p erickson
158 * various fixes, now works on 7328
159 *
160 * Irvine_BSEAVSW_Devel/1   9/10/03 4:33p marcusk
161 * initial version
162 *
163 ****************************************************************/
164#include "bstd.h"
165#include "bsettop.h"
166#include "tspsimgr.h"
167#include "bsettop_message.h"
168#include "ts_psi.h"
169#include "ts_pat.h"
170#include "ts_pmt.h"
171BDBG_MODULE(tspsimgr);
172
173#include "bkni.h"
174#include <stdlib.h> /* malloc, free */
175#include <string.h> /* memset */
176
177#define PSI_BFR_SIZE    TS_PSI_MAX_PSI_TABLE_SIZE
178
179/* Note that the following timeouts are not 400 milliseconds.
180It is 400 BKNI_Sleep(10)'s, which will be about 4000 ms (4 seconds) on linux.
181Also, the original default of 200 was found to be too short for some customer streams. The downside
182of having too large a timeout value is usually app delays when scanning non-existent streamers
183or streams with no PSI information. Not critical. */
184static int tsPsi_patTimeout = 400;
185
186/* PR 18488 - temporarily increasing timeout for 740x platforms. */
187static int tsPsi_pmtTimeout = 600;
188
189static void tsPsi_procProgDescriptors( const uint8_t *p_bfr, unsigned bfrSize, PROGRAM_INFO_T *progInfo );
190static void tsPsi_procStreamDescriptors( const uint8_t *p_bfr, unsigned bfrSize, int streamNum, EPID *ePidData );
191static bresult tsPsi_getProgramMaps( bband_t band, const void *p_patBfr, unsigned pat_bfrSize,
192    CHANNEL_INFO_T *p_chanInfo, bstream_t stream);
193static void tsPsi_p_dumpBuffer(const uint8_t *p_bfr, unsigned bfrSize);
194
195#if BDBG_DEBUG_BUILD
196#define B_ERROR(ERR) (BDBG_ERR(("%s at line %d", #ERR, __LINE__)), (ERR))
197#else
198#define B_ERROR(ERR) (ERR)
199#endif
200
201int tsPsi_getPAT(bband_t band, void *p_bfr, unsigned bfrSize, bstream_t stream)
202{
203    bmessage_stream_t patStream;
204    bmessage_stream_params params;
205    int timeout;
206    bresult result;
207    unsigned patSize = 0;
208
209    patStream = bmessage_open(bmessage_format_psi);
210    if (!patStream) return -1;
211
212    bmessage_stream_params_init(&params, patStream);
213    params.band = band;
214    params.stream = stream;
215    params.pid = 0x0;
216
217    result = bmessage_start(patStream, &params);
218    if (result) return -1;
219
220    BDBG_MSG(("Looking for PAT"));
221    for( timeout = tsPsi_patTimeout; timeout > 0 && patSize == 0; timeout-- )
222    {
223        const void *buffer;
224        if (bmessage_get_buffer(patStream, &buffer, &patSize))
225            return -1;
226        if (patSize) {
227            if (patSize > bfrSize)
228                patSize = bfrSize;
229            BKNI_Memcpy(p_bfr, buffer, patSize);
230            /* don't call bmessage_read_complete because we're stopping anyway */
231        }
232        else {
233            BKNI_Sleep(10);
234        }
235    }
236    bmessage_close(patStream);
237
238    /* validate before returning it */
239    if (patSize && !TS_PAT_validate(p_bfr, patSize)) {
240        tsPsi_p_dumpBuffer(p_bfr, patSize);
241        BDBG_WRN(("Invalid PAT data detected"));
242        return -1;
243    }
244
245    return patSize;
246}
247
248bresult tsPsi_getChannelInfo(CHANNEL_INFO_T *p_chanInfo, bband_t band, bstream_t stream )
249{
250    uint8_t     pat[PSI_BFR_SIZE];
251    size_t      patSize;
252    TS_PSI_header header;
253
254    /* Blocking call to get PAT */
255    patSize = tsPsi_getPAT(band, pat, PSI_BFR_SIZE, stream);
256    /* If there's no PAT, return but don't print an error because this can happen
257    normally. */
258    if (patSize <= 0)
259        return berr_external_error;
260
261    TS_PSI_getSectionHeader( pat, &header );
262    p_chanInfo->version                 = header.version_number;
263    p_chanInfo->transport_stream_id     = header.table_id_extension;
264    p_chanInfo->num_programs            = 0;
265
266    BDBG_MSG(("Parsing PAT"));
267    return tsPsi_getProgramMaps( band, pat, patSize, p_chanInfo, stream );
268}
269
270#define ADD_VIDEO_PID(P_INFO, PID, TYPE, PMT, PMTSIZE, INDEX) \
271    do { \
272    if( (P_INFO)->num_video_pids < MAX_PROGRAM_MAP_PIDS ) \
273    { \
274    BDBG_MSG(("  vpid[%d] 0x%x, type 0x%x", (P_INFO)->num_video_pids, (PID), (TYPE))); \
275    (P_INFO)->video_pids[(P_INFO)->num_video_pids].pid = (PID); \
276    (P_INFO)->video_pids[(P_INFO)->num_video_pids].streamType = (TYPE); \
277    tsPsi_procStreamDescriptors((PMT), (PMTSIZE), (INDEX), &(P_INFO)->video_pids[(P_INFO)->num_video_pids] ); \
278    (P_INFO)->num_video_pids++; \
279    } \
280    } while (0)
281#define ADD_AUDIO_PID(P_INFO, PID, TYPE, PMT, PMTSIZE, INDEX) \
282    do { \
283    if( (P_INFO)->num_audio_pids < MAX_PROGRAM_MAP_PIDS ) \
284    { \
285    BDBG_MSG(("  apid[%d] 0x%x, type 0x%x", (P_INFO)->num_audio_pids, (PID), (TYPE))); \
286    (P_INFO)->audio_pids[(P_INFO)->num_audio_pids].pid = (PID); \
287    (P_INFO)->audio_pids[(P_INFO)->num_audio_pids].streamType = (TYPE); \
288    tsPsi_procStreamDescriptors((PMT), (PMTSIZE), (INDEX), &(P_INFO)->audio_pids[(P_INFO)->num_audio_pids] ); \
289    (P_INFO)->num_audio_pids++; \
290    } \
291    } while (0)
292#define ADD_OTHER_PID(P_INFO, PID, TYPE, PMT, PMTSIZE, INDEX) \
293    do { \
294    if( (P_INFO)->num_other_pids < MAX_PROGRAM_MAP_PIDS ) \
295    { \
296    BDBG_MSG(("  opid[%d] 0x%x, type 0x%x", (P_INFO)->num_audio_pids, (PID), (TYPE))); \
297    (P_INFO)->other_pids[(P_INFO)->num_other_pids].pid = (PID); \
298    (P_INFO)->other_pids[(P_INFO)->num_other_pids].streamType = (TYPE); \
299    tsPsi_procStreamDescriptors((PMT), (PMTSIZE), (INDEX), &(P_INFO)->other_pids[(P_INFO)->num_other_pids] ); \
300    (P_INFO)->num_other_pids++; \
301    } \
302    } while (0)
303
304void tsPsi_parsePMT( const void *pmt, unsigned pmtSize, PROGRAM_INFO_T *p_programInfo)
305{
306    int i;
307    TS_PMT_stream pmt_stream;
308    TS_PSI_header header;
309
310    TS_PSI_getSectionHeader(pmt, &header );
311
312    /* Store the main information about the program */
313    p_programInfo->program_number   = header.table_id_extension;
314    p_programInfo->version          = header.version_number;
315    p_programInfo->pcr_pid          = TS_PMT_getPcrPid(pmt, pmtSize);
316
317    /* find and process Program descriptors */
318    tsPsi_procProgDescriptors(pmt, pmtSize, p_programInfo );
319
320    /* Find the video and audio pids... */
321    p_programInfo->num_video_pids   = 0;
322    p_programInfo->num_audio_pids   = 0;
323    p_programInfo->num_other_pids   = 0;
324
325    for( i = 0; i < TS_PMT_getNumStreams(pmt, pmtSize); i++ )
326    {
327        int descIdx = 0;
328        if (TS_PMT_getStream(pmt, pmtSize, i, &pmt_stream )) {
329            BDBG_WRN(("Invalid PMT data detected"));
330            continue;
331        }
332
333        switch( pmt_stream.stream_type )
334        {
335        /* video formats */
336        case TS_PSI_ST_11172_2_Video:  /* MPEG-1 */
337            ADD_VIDEO_PID(p_programInfo, pmt_stream.elementary_PID, bvideo_codec_mpeg1, pmt, pmtSize, i);
338            break;
339        case TS_PSI_ST_ATSC_Video:   /* ATSC MPEG-2 */
340            ADD_VIDEO_PID(p_programInfo, pmt_stream.elementary_PID, bvideo_codec_mpeg2, pmt, pmtSize, i);
341            break;
342        case TS_PSI_ST_13818_2_Video: /* MPEG-2 */
343            ADD_VIDEO_PID(p_programInfo, pmt_stream.elementary_PID, bvideo_codec_mpeg2, pmt, pmtSize, i);
344            break;
345        case TS_PSI_ST_14496_2_Video: /* MPEG-4 Part 2 */
346            ADD_VIDEO_PID(p_programInfo, pmt_stream.elementary_PID, bvideo_codec_mpeg4_part2, pmt, pmtSize, i);
347            break;
348        case TS_PSI_ST_14496_10_Video: /* H.264/AVC */
349            ADD_VIDEO_PID(p_programInfo, pmt_stream.elementary_PID, bvideo_codec_h264, pmt, pmtSize, i);
350            break;
351        case TS_PSI_ST_AVS_Video: /* AVS */
352            ADD_VIDEO_PID(p_programInfo, pmt_stream.elementary_PID, bvideo_codec_avs, pmt, pmtSize, i);
353            break;
354        case TS_PSI_ST_SMPTE_VC1:      /* VC-1 */
355            /* need to parse descriptor and then subdescriptor to determine profile */
356            for (;;) {
357                TS_PSI_descriptor desc = TS_PMT_getStreamDescriptor(pmt, pmtSize, i, descIdx);
358                if (desc == NULL) break;
359                descIdx++;
360
361                switch(desc[0]) {
362                case TS_PSI_DT_Registration:
363                    /* calculate and check format_identifier */
364                    {
365                    uint32_t format_identifier = (desc[2] << 24) + (desc[3] << 16) + (desc[4] << 8) + desc[5];
366                    if (format_identifier == 0x56432D31) {
367                        /* check that proper sub-descriptor exists */
368                        int subdescriptor_tag = desc[6];
369                        if (subdescriptor_tag == 0x01) {
370                            int profile_level = desc[7];
371                            if (profile_level >= 0x90)  /* Advanced Profile ES */
372                                ADD_VIDEO_PID(p_programInfo, pmt_stream.elementary_PID, bvideo_codec_vc1, pmt, pmtSize, i);
373                            else /* Simple/Main Profile ES */
374                                ADD_VIDEO_PID(p_programInfo, pmt_stream.elementary_PID, bvideo_codec_vc1_sm, pmt, pmtSize, i);
375                        }
376                    }
377                    }
378                    break;
379                default:
380                    break;
381                }
382            }
383            break;
384
385        /* audio formats */
386        case TS_PSI_ST_11172_3_Audio: /* MPEG-1 */
387            ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_mpeg, pmt, pmtSize, i);  /* Same baudio_format for MPEG-1 or MPEG-2 audio */
388            break;
389        case TS_PSI_ST_13818_3_Audio: /* MPEG-2 */
390            ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_mpeg, pmt, pmtSize, i);  /* Same baudio_format for MPEG-1 or MPEG-2 audio */
391            break;
392        case TS_PSI_ST_13818_7_AAC:  /* MPEG-2 AAC */
393            ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_aac, pmt, pmtSize, i);    /* Note baudio_format_aac = MPEG-2 AAC */
394            break;
395        case TS_PSI_ST_14496_3_Audio: /* MPEG-4 AAC */
396            ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_aac_plus, pmt, pmtSize, i);   /* Note baudio_format_aac_plus = MPEG-4 AAC */
397            break;
398        case TS_PSI_ST_ATSC_AC3:      /* ATSC AC-3 */
399            ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_ac3, pmt, pmtSize, i);
400            break;
401        case TS_PSI_ST_ATSC_EAC3:     /* ATSC Enhanced AC-3 */
402            ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_ac3_plus, pmt, pmtSize, i);
403            break;
404        case TS_PSI_ST_ATSC_DTS:     /* ASTC ??? DTS audio */
405            ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_dts, pmt, pmtSize, i);
406            break;
407        case TS_PSI_ST_AVS_Audio:     /* AVS */
408            ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_avs, pmt, pmtSize, i);
409            break;
410        case TS_PSI_ST_DRA_Audio:     /* DRA */
411            ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_dra, pmt, pmtSize, i);
412            break;
413
414
415        /* video or audio */
416        case TS_PSI_ST_13818_1_PrivatePES:  /* examine descriptors to handle private data */
417            for (;;) {
418                TS_PSI_descriptor desc = TS_PMT_getStreamDescriptor(pmt, pmtSize, i, descIdx);
419                if (desc == NULL) break;
420                descIdx++;
421
422                switch(desc[0]) {
423                /* video formats */
424                case TS_PSI_DT_VideoStream:
425                    /* MPEG_1_only_flag is bit 2 of desc[2], this determines MPEG-1/2 */
426                    if ((desc[2] & 0x04) == 1)
427                        ADD_VIDEO_PID(p_programInfo, pmt_stream.elementary_PID, bvideo_codec_mpeg1, pmt, pmtSize, i);
428                    else
429                        ADD_VIDEO_PID(p_programInfo, pmt_stream.elementary_PID, bvideo_codec_mpeg2, pmt, pmtSize, i);
430                    break;
431                case TS_PSI_DT_MPEG4_Video:
432                    ADD_VIDEO_PID(p_programInfo, pmt_stream.elementary_PID, bvideo_codec_mpeg4_part2, pmt, pmtSize, i);
433                    break;
434                case TS_PSI_DT_AVC:
435                    ADD_VIDEO_PID(p_programInfo, pmt_stream.elementary_PID, bvideo_codec_h264, pmt, pmtSize, i);
436                    break;
437                case TS_PSI_DT_AVS_Video:
438                    ADD_VIDEO_PID(p_programInfo, pmt_stream.elementary_PID, bvideo_codec_avs, pmt, pmtSize, i);
439                    break;
440
441                /* audio formats */
442                case TS_PSI_DT_AudioStream:
443                    ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_mpeg, pmt, pmtSize, i);   /* Same baudio_format for MPEG-1 or MPEG-2 audio */
444                    break;
445                case TS_PSI_DT_MPEG2_AAC:
446                    ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_aac, pmt, pmtSize, i);   /* Note baudio_format_aac = MPEG-2 AAC */
447                    break;
448                case TS_PSI_DT_MPEG4_Audio:
449                    ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_aac_plus, pmt, pmtSize, i); /* Note baudio_format_aac_plus = MPEG-4 AAC */
450                    break;
451                case TS_PSI_DT_DVB_AAC:
452                    ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_aac_plus, pmt, pmtSize, i); /* Note baudio_format_aac_plus = MPEG-4 AAC */
453                    break;
454                case TS_PSI_DT_DVB_AC3:
455                    ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_ac3, pmt, pmtSize, i);
456                    break;
457                case TS_PSI_DT_DVB_EnhancedAC3:
458                    ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_ac3_plus, pmt, pmtSize, i);
459                    break;
460                case TS_PSI_DT_DVB_DTS:
461                    ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_dts, pmt, pmtSize, i);
462                    break;
463                case TS_PSI_DT_DVB_DRA:
464                    ADD_AUDIO_PID(p_programInfo, pmt_stream.elementary_PID, baudio_format_dra, pmt, pmtSize, i);
465                    break;
466                default:
467                    BDBG_MSG(("Unsupported private descriptor 0x%x",desc[0]));
468                    break;
469                }
470            }
471            break;
472        default:
473            if( p_programInfo->num_other_pids < MAX_PROGRAM_MAP_PIDS )
474            {
475                ADD_OTHER_PID(p_programInfo, pmt_stream.elementary_PID, pmt_stream.stream_type, pmt, pmtSize, i);
476            }
477            break;
478        }
479        /* If we get any data our status is complete! */
480    } /* EFOR Program map loop */
481}
482
483static void tsPsi_p_addChanInfo(void *context, uint16_t pmt_pid, const void *pmt, unsigned size)
484{
485    CHANNEL_INFO_T *p_chanInfo = (CHANNEL_INFO_T*)context;
486    PROGRAM_INFO_T programInfo;
487    int i;
488
489    BKNI_Memset(&programInfo, 0, sizeof(programInfo));
490
491    /* If this isn't true, then the logic at the top of tsPsi_getPMTs has failed,
492    or we haven't stopped each msgstream after reading one and only one item. */
493    BDBG_ASSERT(p_chanInfo->num_programs < MAX_PROGRAMS_PER_CHANNEL);
494
495    /* The "if" comparision below is present to silence the Coverity from choosing the false path in the above "BDBG_ASSERT" line of code. */
496    if(p_chanInfo->num_programs < MAX_PROGRAMS_PER_CHANNEL){
497        tsPsi_parsePMT(pmt, size, &programInfo);
498        programInfo.map_pid = pmt_pid;
499
500        /* now that we know the program_number, insert it into the array */
501        for (i=0;i<p_chanInfo->num_programs;i++) {
502            if (programInfo.program_number < p_chanInfo->program_info[i].program_number)
503                break;
504        }
505        /* make room for an insertion */
506        if (i < p_chanInfo->num_programs) {
507            unsigned char *ptr = (unsigned char *)&p_chanInfo->program_info[i];
508            BKNI_Memmove(ptr + sizeof(PROGRAM_INFO_T), ptr, sizeof(PROGRAM_INFO_T) * (p_chanInfo->num_programs - i));
509        }
510        /* now copy into place */
511        BKNI_Memcpy(&p_chanInfo->program_info[i], &programInfo, sizeof(PROGRAM_INFO_T));
512        p_chanInfo->num_programs++;
513    }
514}
515
516static bresult  tsPsi_getProgramMaps( bband_t band, const void *p_patBfr, unsigned pat_bfrSize,
517    CHANNEL_INFO_T *p_chanInfo, bstream_t stream )
518{
519    return tsPsi_getPMTs(band, p_patBfr, pat_bfrSize, tsPsi_p_addChanInfo, p_chanInfo, stream);
520}
521
522bresult tsPsi_getPMTs(bband_t band, const void *p_patBfr, unsigned pat_bfrSize,
523    tsPsi_PMT_callback callback, void *context, bstream_t stream)
524{
525    bresult         result = b_ok;
526    int             i;
527    size_t          bfrSize;
528    int             num_programs;
529    int             num_programs_to_get;
530    int             num_messages_received;
531    bool            message_received;
532    int             timeout;
533    bmessage_stream_t   *pmtStreamArray;
534    uint16_t        *pmt_pidArray;
535    TS_PAT_program  program;
536    int             curProgramNum = 0;
537
538    num_programs = TS_PAT_getNumPrograms(p_patBfr);
539    BDBG_MSG(("num_programs %d", num_programs));
540    if( num_programs > MAX_PROGRAMS_PER_CHANNEL )
541    {
542        BDBG_WRN(("Maximum number of programs exceeded in tspsimgr: %d > %d",
543            num_programs, MAX_PROGRAMS_PER_CHANNEL));
544        num_programs = MAX_PROGRAMS_PER_CHANNEL;
545    }
546
547    pmtStreamArray = (bmessage_stream_t *)malloc( sizeof(bmessage_stream_t) * num_programs );
548    memset(pmtStreamArray, 0, sizeof(bmessage_stream_t) * num_programs);
549
550    pmt_pidArray = (uint16_t *)malloc( sizeof(uint16_t) * num_programs );
551    memset(pmt_pidArray, 0, sizeof(uint16_t) * num_programs);
552
553    result = TS_PAT_getProgram( p_patBfr, pat_bfrSize, curProgramNum, &program );
554    curProgramNum++;
555
556    if( result == b_ok )
557    {
558        while( num_programs )
559        {
560            /* Always try to read the max number of pids at the same time */
561            num_programs_to_get = num_programs;
562            num_messages_received = 0;
563
564            for( i = 0; i < num_programs_to_get; i++ )
565            {
566                if( program.program_number == 0 )
567                {
568                    /* This is the network PID, so ignore it */
569                    num_messages_received++;
570                }
571                else
572                {
573                    bmessage_stream_params params;
574
575                    pmtStreamArray[i] = bmessage_open(bmessage_format_psi);
576                    if( pmtStreamArray[i] == NULL )
577                    {
578                        /* Decrease the number of programs to get in this loop due to transport resources */
579                        num_programs_to_get = i-1;
580
581                        if( num_programs_to_get == 0 )
582                        {
583                            /* Abort due to not being able to enable messages */
584/*                          BRCM_DBG_MSG(("Unable to enable any messages!")); */
585                            num_programs = 0;
586                        }
587                        break;
588                    }
589
590                    bmessage_stream_params_init(&params, pmtStreamArray[i]);
591                    params.band = band;
592                    params.stream = stream;
593                    params.pid = program.PID;
594                    /* these fields must match */
595                    params.filter.mask[0] = 0x00;
596                    params.filter.mask[3] = 0x00;
597                    params.filter.mask[4] = 0x00;
598
599                    /* they must match these values */
600                    params.filter.coef[0] = 0x02;
601                    params.filter.coef[3] = (program.program_number & 0xFF00) >> 8;
602                    params.filter.coef[4] = program.program_number & 0xFF;
603
604                    BDBG_MSG(("filter pid %#x, program %#x", params.pid, program.program_number));
605
606                    pmt_pidArray[i] = program.PID;
607                    if (bmessage_start(pmtStreamArray[i], &params)) {
608                        bmessage_close(pmtStreamArray[i]);
609                        pmtStreamArray[i] = NULL;
610                        pmt_pidArray[i] = 0;
611                    }
612                }
613
614                /* We are finished with this program association so go to the next */
615
616                /* TODO: Check for error */
617                TS_PAT_getProgram( p_patBfr, pat_bfrSize, curProgramNum, &program );
618                curProgramNum++;
619            }
620
621            /* Now we have enabled our pid channels, so wait for each one to get some data */
622            timeout = tsPsi_pmtTimeout;
623            while( num_messages_received != num_programs_to_get && timeout != 0 )
624            {
625                message_received = 0;
626                /* Check each of the pid channels we are waiting for */
627                for( i = 0; i < num_programs_to_get; i++ )
628                {
629                    const void *buffer;
630                    if (pmtStreamArray[i] &&
631                        !bmessage_get_buffer(pmtStreamArray[i], &buffer, &bfrSize ) &&
632                        bfrSize)
633                    {
634                        /* don't call bmessage_read_complete because we're stopping anyway */
635
636                        message_received = true;
637                        num_messages_received++;
638
639                        BDBG_MSG(("PMT: %d %d (%02x %02x %02x)", i, bfrSize,
640                            ((unsigned char *)buffer)[0],((unsigned char *)buffer)[1],((unsigned char *)buffer)[2]));
641
642                        if (!TS_PMT_validate(buffer, bfrSize)) {
643                            BDBG_WRN(("Invalid PMT data detected: ch %d, bfrSize 0x%x", i, bfrSize));
644                            tsPsi_p_dumpBuffer(buffer, bfrSize);
645                        }
646                        else {
647                            /* Give the PMT to the callback */
648                            (*callback)(context, pmt_pidArray[i], buffer, bfrSize);
649                        }
650
651                        /* cannot stop until after the data has been parsed because
652                        we're not copying the data into a local buffer */
653                        bmessage_stop(pmtStreamArray[i]);
654                    }
655                }
656                if( !message_received )
657                {
658                    BKNI_Sleep(10);
659                    timeout--;
660                }
661            }
662
663            /* Now disable our pid channels */
664            for( i = 0; i < num_programs_to_get; i++ )
665            {
666                if (pmtStreamArray[i])
667                    bmessage_close(pmtStreamArray[i]);
668            }
669            num_programs -= num_programs_to_get;
670        }
671    }
672
673    free( pmtStreamArray );
674    free(pmt_pidArray);
675
676    return result;
677}
678
679void tsPsi_procProgDescriptors( const uint8_t *p_bfr, unsigned bfrSize, PROGRAM_INFO_T *progInfo )
680{
681    int i;
682    TS_PSI_descriptor descriptor;
683
684    for( i = 0, descriptor = TS_PMT_getDescriptor( p_bfr, bfrSize, i );
685        descriptor != NULL;
686        i++, descriptor = TS_PMT_getDescriptor( p_bfr, bfrSize, i ) )
687    {
688        switch (descriptor[0])
689        {
690        case TS_PSI_DT_CA:
691            progInfo->ca_pid = ((descriptor[4] & 0x1F) << 8) + descriptor[5];
692            break;
693
694        default:
695            break;
696        }
697    }
698}
699
700void tsPsi_procStreamDescriptors( const uint8_t *p_bfr, unsigned bfrSize, int streamNum, EPID *ePidData )
701{
702    int i;
703    TS_PSI_descriptor descriptor;
704
705    for( i = 0, descriptor = TS_PMT_getStreamDescriptor( p_bfr, bfrSize, streamNum, i );
706        descriptor != NULL;
707        i++, descriptor = TS_PMT_getStreamDescriptor( p_bfr, bfrSize, streamNum, i ) )
708    {
709        switch (descriptor[0])
710        {
711        case TS_PSI_DT_CA:
712            ePidData->ca_pid = ((descriptor[4] & 0x1F) << 8) + descriptor[5];
713            break;
714
715        default:
716            break;
717        }
718    }
719}
720
721void tsPsi_setTimeout( int patTimeout, int pmtTimeout )
722{
723    tsPsi_patTimeout = patTimeout;
724    tsPsi_pmtTimeout = pmtTimeout;
725}
726
727void tsPsi_getTimeout( int *patTimeout, int *pmtTimeout )
728{
729    *patTimeout = tsPsi_patTimeout;
730    *pmtTimeout = tsPsi_pmtTimeout;
731}
732
733static void tsPsi_p_dumpBuffer(const uint8_t *p_bfr, unsigned bfrSize)
734{
735    unsigned i;
736    for (i=0;i<bfrSize;i++)
737        BKNI_Printf("%02X", p_bfr[i]);
738    BKNI_Printf("\n");
739}
Note: See TracBrowser for help on using the repository browser.