source: svn/trunk/newcon3bcm2_21bu/BSEAV/lib/bcmplayer/src/tsindexer.c @ 2

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

1.phkim

  1. revision copy newcon3sk r27
  • Property svn:executable set to *
File size: 40.1 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: tsindexer.c $
11 * $brcm_Revision: 5 $
12 * $brcm_Date: 4/30/10 11:53a $
13 *
14 * Module Description:
15 *
16 * Revision History:
17 *
18 * $brcm_Log: /BSEAV/lib/bcmplayer/src/tsindexer.c $
19 *
20 * 5   4/30/10 11:53a erickson
21 * SW7405-4105: remove support for non-RAVE style SCT. set PTS and all 8
22 * bytes of payload in RAVE-style SCT.
23 *
24 * 4   3/16/10 2:16p erickson
25 * CDSTRMANA-294: allow the capture of start codes (e.g. B5) between start
26 * codes 00 and 01
27 *
28 * 3   2/23/10 2:37p erickson
29 * SW7400-2694: only add random access indicator (RAI) SCT for AVC
30 * streams. the bcmindexer MPEG feed doesn't parse it.
31 *
32 * 2   2/12/08 1:23p gmohile
33 * PR 38979 : Create Random Access Indicator Entry
34 *
35 * Irvine_BSEAVSW_Devel/32   6/30/06 2:39p erickson
36 * PR21941: fixed warning
37 *
38 * Irvine_BSEAVSW_Devel/31   7/15/05 8:04p erickson
39 * PR16210: when we hit the end of a PES packet, we need to complete any
40 * pending SC capture
41 *
42 * Irvine_BSEAVSW_Devel/30   4/21/05 4:52p erickson
43 * PR14451: handle start codes beginning while still capturing payload
44 * data. this requires two additional state variables.
45 *
46 * Irvine_BSEAVSW_Devel/29   3/18/05 10:00a erickson
47 * PR14451: fixed 6word SCT, non-AVC support
48 *
49 * Irvine_BSEAVSW_Devel/28   3/14/05 4:59p erickson
50 * PR14451: add 6-word SCT support, extend alloc/reset api, add AVC start
51 * code support
52 *
53 * Irvine_BSEAVSW_Devel/27   2/14/05 1:24p erickson
54 * PR14017: default to no-timestamp
55 *
56 * Irvine_BSEAVSW_Devel/26   2/3/05 3:26p erickson
57 * PR14017: fixed bug related to 192 byte timestamped packet suppot
58 *
59 * Irvine_BSEAVSW_Devel/25   2/3/05 1:36p erickson
60 * PR13017: added 192 byte timestamped packet support
61 *
62 * Irvine_BSEAVSW_Devel/24   2/21/03 9:45a marcusk
63 * Updated comments in tsindex_feedVob() function.
64 *
65 * Irvine_BSEAVSW_Devel/23   2/21/03 9:37a marcusk
66 * Fixed compiler error.
67 *
68 * Irvine_BSEAVSW_Devel/22   2/20/03 4:35p marcusk
69 * Added support for VOB (DVD program stream) indexing.
70 *
71 * Irvine_BSEAVSW_Devel/21   2/4/03 2:47p erickson
72 * Only look for most significant nibble of pesStreamId, then store the
73 * actualPesStreamId for later use.
74 *
75 * Irvine_HDDemo_Devel\20   4/16/02 10:32a marcusk
76 * Updated to use unified interfaces with bcmindexer.
77 *
78 * Irvine_HDDemo_Devel\1   4/16/02 12:55p erickson
79 * Moved from SetTop/dvrtable
80 *
81 * Irvine_HDDemo_Devel\19   4/8/02 12:40p marcusk
82 * Fixed linux compiler warning.
83 *
84 * Irvine_HDDemo_Devel\18   4/2/02 11:53a marcusk
85 * Fixed warnings.
86 *
87 ***************************************************************************/
88#ifdef CMDLINE_TEST
89#include <stdlib.h>
90#include <memory.h>
91void *bcmKNImalloc( size_t size ){ return malloc( size ); }
92void bcmKNIfree( void * ptr ){ free( ptr ); }
93#include <stdio.h>
94#define TS_DBGMSG(a,b)  if (a > 2) printf b
95#else
96#include "bcmkernel.h"
97#define TS_DBGMSG(a,b)  if (a > 2) DBGMSG b
98#endif
99
100#include "tsindexer.h"
101#include "mpeg2types.h"
102
103#define VERSION 0101
104
105/**
106 * If you want to process 192 byte timestamped TS packets, define
107 * this variable. There is no runtime control for this.
108#define TIMESTAMP_PACKETS
109 **/
110
111struct sTsIndexer
112{
113#define VOB_PACKET_SIZE         2048
114#ifdef TIMESTAMP_PACKETS
115#define TIMESTAMP_SIZE          4
116#define TS_PACKET_SIZE          192
117#else
118#define TIMESTAMP_SIZE          0
119#define TS_PACKET_SIZE          188
120#endif
121#define NUM_PES_BYTES_TO_CACHE      30
122
123      tsindex_settings settings;
124
125      unsigned char     pesStreamId;
126      char              PesParseMode;           /* Are we parsing PES or TS - used to determine proper offsets */
127      char              validPesPacket;         /* Determines if the start codes for this pes packet with be stored */
128
129      unsigned char     TransPacket[TS_PACKET_SIZE];    /* Cached transport packet */
130      unsigned long     TransPacketValidCount;          /* Number of valid bytes in the cached transport packet */
131
132      unsigned long     TransRecordByteCountHi;         /* Running counter of number of bytes recorded (hi word) */
133      unsigned long     TransRecordByteCount;           /* Running counter of number of bytes recorded */
134      unsigned long     TransByteOffset;                    /* Running count of number of bytes processed in cur packet */
135
136      char              PesMode;                        /* 1 (Parsing PES header), 0 (Parsing ES data) */
137      unsigned long     PesHeaderByteCount;             /* Num of pes header bytes cached */
138      unsigned long     PesHeaderSize;          /* Total size of pes header */
139      char              PesPtsFlag;                     /* Flag indicated PTS present */
140      unsigned char     PesHeader[NUM_PES_BYTES_TO_CACHE];
141
142      char              EsStoreNextSlice;                   /* 1 (Next Slice SC will the stored), 0 (next Slice SC will be ignored) */
143      char              EsStoreNextNonSlice;            /* 1 (Next non-Slice SC will the stored), 0 (next non-Slice SC will be ignored) */
144      unsigned long     EsNumZeroBytes;         /* Running count of number of consecutive bytes of zero */
145      unsigned long     EsNumStartCodeBytes;            /* Running count of bytes extracted of current start code */
146      unsigned long     EsRecordByteCount;              /* Offset into total record of last found zero */
147      unsigned long     EsStartCodeBytes;               /* Offset into trans packet of last found zero */
148      unsigned long     savePacketOffset;               /* save the value of EsRecordByteCount at the time
149                                                           we might be beginning a start code */
150      unsigned long     saveStreamOffset;               /* save the value of EsStartCodeBytes at the time
151                                                           we might be beginning a start code */
152
153      sIndexEntry           curEntry;                   /* Start Code entry that gets filled in as indexer goes */
154      sSixWordIndexEntry    sixWordEntry;
155
156      int               currentVersion;
157      unsigned long     actualPesStreamId;
158      unsigned long     sctType;
159};
160
161/*---------------------------------------------------------------
162- PRIVATE FUNCTIONS
163---------------------------------------------------------------*/
164static unsigned char    tsindex_readByte( const unsigned char *p_bfr, const long offset );
165static unsigned short   tsindex_readShort( const unsigned char *p_bfr, const long offset );
166static unsigned long    tsindex_readLong( const unsigned char *p_bfr, const long offset );
167static long             tsindex_processPes( sTsIndexer * const p_tsi, const unsigned char *p_bfr, const long offset, long numBytes );
168static long             tsindex_processEs( sTsIndexer * const p_tsi, const unsigned char *p_bfr, const long offset, long numBytes );
169
170/* TODO: how should this be called? */
171long                    tsindex_updateRecordByteCountHi( sTsIndexer * const p_tsi, sIndexEntry *p_entry, long numEntries );
172
173/*! Function Definitions */
174
175/******************************************************************************
176* INPUTS:   cb = pointer to a function that stores table entries (same format as fwrite)
177*           fp = general pointer that is passed in as param 3 into cb function
178*           pid = pid of the transport stream used for table generation
179* OUTPUTS:  None.
180* RETURNS:  pointer to sTsIndexer structure
181* FUNCTION: This function allocates and initializes an indexer structure.
182******************************************************************************/
183sTsIndexer *tsindex_allocate( INDEX_WRITE_CB cb, void *fp, unsigned short pid, int version )
184{
185    tsindex_settings settings;
186    tsindex_settings_init(&settings);
187    settings.cb = cb;
188    settings.fp = fp;
189    settings.pid = pid;
190    settings.version = version;
191    return tsindex_allocate_ex(&settings);
192}
193
194
195int tsindex_reset( sTsIndexer * p_tsi, INDEX_WRITE_CB cb, void *fp, unsigned short pid, int version )
196{
197    tsindex_settings settings;
198    tsindex_settings_init(&settings);
199    settings.cb = cb;
200    settings.fp = fp;
201    settings.pid = pid;
202    settings.version = version;
203    return tsindex_reset_ex(p_tsi, &settings);
204}
205
206void tsindex_settings_init(tsindex_settings *settings)
207{
208    memset(settings, 0, sizeof(*settings));
209    settings->version = 0101;
210    settings->entry_size = 4;
211    settings->start_code_lo = 0xB0;
212    settings->start_code_hi = 0xB8;
213}
214
215/**
216Summary:
217Allocate a tsindex object using the settings structure.
218Description:
219This is preferred to tsindex_allocate because it can be extended. The old
220API is fixed.
221**/
222sTsIndexer  *tsindex_allocate_ex(const tsindex_settings *settings)
223{
224    sTsIndexer *p_tsi;
225    p_tsi = (sTsIndexer *)bcmKNImalloc( sizeof( sTsIndexer ) );
226    if (tsindex_reset_ex(p_tsi, settings)) {
227        bcmKNIfree(p_tsi);
228        p_tsi = NULL;
229    }
230    return p_tsi;
231}
232
233int tsindex_reset_ex(sTsIndexer *p_tsi, const tsindex_settings *settings)
234{
235    int result;
236
237    memset( p_tsi, 0, sizeof( sTsIndexer ) );
238
239    p_tsi->settings = *settings;
240
241    p_tsi->PesMode = 0;
242    p_tsi->pesStreamId = 0xE0; /* only most-significant nibble matters */
243    p_tsi->validPesPacket = 0;
244
245    /* Store any type of start code in the beginning */
246    p_tsi->EsStoreNextSlice = 1;
247    p_tsi->EsStoreNextNonSlice = 1;
248
249    switch (settings->version) {
250    case -1:
251    case VERSION:
252        p_tsi->currentVersion = settings->version;
253        result = 0;
254        break;
255    default:
256        result = -1;
257        break;
258    }
259
260    return result;
261}
262
263/******************************************************************************
264* INPUTS:   p_tsi = pointer to a previously allocated sTsIndexer structure
265* OUTPUTS:  None.
266* RETURNS:  None.
267* FUNCTION: This function frees any memory used by an indexer structure.
268******************************************************************************/
269void tsindex_free( sTsIndexer *p_tsi )
270{
271    bcmKNIfree( (void *)p_tsi );
272}
273
274static void tsindex_p_callback(sTsIndexer * const p_tsi)
275{
276    if (p_tsi->settings.entry_size == 6) {
277        /* merge curEntry into sixWordEntry. by deferring this until we're ready to fire callback,
278        it simplifies calling code. */
279        p_tsi->sixWordEntry.word0 = p_tsi->sctType;
280        p_tsi->sixWordEntry.word1 = 0;
281        p_tsi->sixWordEntry.startCodeBytes = p_tsi->curEntry.startCodeBytes;
282        p_tsi->sixWordEntry.recordByteCount = p_tsi->curEntry.recordByteCount;
283        p_tsi->sixWordEntry.recordByteCountHi = p_tsi->curEntry.recordByteCountHi;
284        p_tsi->sixWordEntry.flags = p_tsi->curEntry.flags;
285        (*p_tsi->settings.cb)(&p_tsi->sixWordEntry, 1, sizeof( sSixWordIndexEntry ), p_tsi->settings.fp );
286        memset(&p_tsi->sixWordEntry, 0, sizeof(p_tsi->sixWordEntry));
287        memset(&p_tsi->curEntry, 0, sizeof(p_tsi->curEntry));
288    }
289    else {
290        (*p_tsi->settings.cb)(&(p_tsi->curEntry), 1, sizeof( sIndexEntry ), p_tsi->settings.fp );
291    }
292}
293
294/******************************************************************************
295* INPUTS:   p_tsi = pointer to a previously allocated sTsIndexer structure
296*           pesStreamId = stream id of the pes packet that is to be indexed (default is 0xE0)
297* OUTPUTS:  None.
298* RETURNS:  None.
299* FUNCTION: This function frees any memory used by an indexer structure.
300******************************************************************************/
301void tsindex_setPesId( sTsIndexer *p_tsi, unsigned char pesStreamId )
302{
303    /* only most-significant nibble matters */
304    p_tsi->pesStreamId = pesStreamId;
305}
306
307/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
308+ INPUTS:   p_bfr = buffer pointer,
309+           offset  = offset into the buffer in bytes
310+ OUTPUTS:  None.
311+ RETURNS:  This function returns an 8 bit value.
312+ FUNCTION: Return an 8 bit value assuming the proper byte swapping. Assumes offset
313+           is in bounds and p_bfr ends on a 4 byte boundry.
314+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
315unsigned char tsindex_readByte( const unsigned char *p_bfr, const long offset )
316{
317#ifdef SWAPPED_STREAM
318    unsigned long offset_to_word = (offset / 4) * 4;
319    unsigned long rem = (offset % 4);
320    return (unsigned char)p_bfr[offset_to_word + (3 - rem)];
321#else
322    return (unsigned char)p_bfr[offset];
323#endif
324}
325
326/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
327+ INPUTS:   p_bfr = buffer pointer
328+           offset  = offset into the buffer in bytes
329+ OUTPUTS:  None.
330+ RETURNS:  16 bit value
331+ FUNCTION: This function returns a 16 bit value from the first two bytes
332+           pointed to by p_bfr if p_bfr is big endian and returns the 16
333+           bit value that would have been return if the stream was big endian if
334+           the stream has every 32-bit word byte swapped.
335+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
336#ifdef SWAPPED_STREAM
337static char smap[4][2] = { {3,2}, {2,1}, {1,0}, {0,7} };
338#endif
339unsigned short tsindex_readShort( const unsigned char *p_bfr, const long offset )
340{
341    unsigned short value;
342#ifdef SWAPPED_STREAM
343    unsigned long offset_to_word = (offset / 4) * 4;
344    unsigned long word_offset = (offset % 4);
345
346    value = p_bfr[offset_to_word + smap[word_offset][0]];
347    value <<= 8;
348    value |= p_bfr[offset_to_word + smap[word_offset][1]];
349#else
350    value = p_bfr[offset + 0];
351    value <<= 8;
352    value |= p_bfr[offset + 1];
353#endif
354
355    return value;
356}
357
358/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
359+ INPUTS:   p_bfr = buffer pointer
360+           offset  = offset into the buffer in bytes
361+ OUTPUTS:  None.
362+ RETURNS:  32 bit value
363+ FUNCTION: This function returns a 32 bit value from the first four bytes
364+           pointed to by p_bfr if p_bfr is big endian and returns the 32
365+           bit value that would have been return if the stream was big endian if
366+           the stream has every 32-bit word byte swapped.
367+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
368#ifdef SWAPPED_STREAM
369static char lmap[4][4] = { {3,2,1,0}, {2,1,0,7}, {1,0,7,6}, {0,7,6,5} };
370#endif
371unsigned long tsindex_readLong( const unsigned char *p_bfr, const long offset )
372{
373    unsigned long value;
374#ifdef SWAPPED_STREAM
375    unsigned long offset_to_word = (offset / 4) * 4;
376    unsigned long word_offset = (offset % 4);
377
378    value = p_bfr[offset_to_word + lmap[word_offset][0]];
379    value <<= 8;
380    value |= p_bfr[offset_to_word + lmap[word_offset][1]];
381    value <<= 8;
382    value |= p_bfr[offset_to_word + lmap[word_offset][2]];
383    value <<= 8;
384    value |= p_bfr[offset_to_word + lmap[word_offset][3]];
385#else
386    value = p_bfr[offset + 0];
387    value <<= 8;
388    value |= p_bfr[offset + 1];
389    value <<= 8;
390    value |= p_bfr[offset + 2];
391    value <<= 8;
392    value |= p_bfr[offset + 3];
393#endif
394    return value;
395}
396
397/******************************************************************************
398* INPUTS:   p_tsi = pointer to a previously allocated sTsIndexer structure
399*           p_bfr = buffer containing transport data
400*           numBytes = number of bytes contained in p_bfr
401* OUTPUTS:  None.
402* RETURNS:  Number of packets processed.
403* FUNCTION: This function parses the transport data and stores the start code
404*           tables through the previously installed cb function.
405******************************************************************************/
406long tsindex_feed( sTsIndexer * const p_tsi, const unsigned char *p_bfr, long numBytes )
407{
408    unsigned short pid;
409    const unsigned char *p_curBfr;
410    long i = 0;
411
412    /* We are parsing transport packets */
413    p_tsi->PesParseMode = 0;
414
415    TS_DBGMSG(1,("feed %ld\n", numBytes));
416    while( i < numBytes )
417    {
418        /* Check if we have a partial packet cached */
419        if( p_tsi->TransPacketValidCount
420            || ((numBytes - i) < TS_PACKET_SIZE) )
421        {
422            /* Fill the rest of our transport cache */
423            while( i < numBytes )
424            {
425                p_tsi->TransPacket[p_tsi->TransPacketValidCount] = p_bfr[i];
426
427                p_tsi->TransPacketValidCount += 1;
428                i++;
429
430                if( p_tsi->TransPacketValidCount == TS_PACKET_SIZE )
431                    break;
432            }
433
434            /* We do not have enough data to cache the entire packet, so return */
435            if( p_tsi->TransPacketValidCount != TS_PACKET_SIZE )
436            {
437                return i;
438            }
439            else
440            {
441                p_curBfr = p_tsi->TransPacket;
442                p_tsi->TransPacketValidCount = 0;
443            }
444        }
445        else
446        {
447            p_curBfr = &(p_bfr[i]);
448            i += TS_PACKET_SIZE;
449        }
450
451        p_tsi->TransByteOffset = 0;
452        p_curBfr += TIMESTAMP_SIZE;
453
454        /* make sure this is a trasport packet */
455        if( tsindex_readByte(p_curBfr,0) != 0x47 )
456        {
457            TS_DBGMSG(3,("  bad packet %ld\n", p_tsi->TransRecordByteCount));
458            return -1;
459        }
460
461        /* Does this pid match the one we are indexing? */
462        pid = tsindex_readShort(p_curBfr,TS_PID_BYTE) & TS_PID_MASK;
463        TS_DBGMSG(1,("  pid 0x%x\n", pid));
464        if( pid == p_tsi->settings.pid )
465        {
466            /* we need to determine if we are currently parsing a PES packet or ES data */
467            if( tsindex_readByte(p_curBfr,TS_PAYLOAD_UNIT_START_BYTE) & TS_PAYLOAD_UNIT_START_MASK )
468            {
469                /* PR 16210 - if currently capturing start code payload, fire callback.
470                However, should we fire here, or when we actually detect the PES packet startcode? This
471                might need to change in the future. */
472                if (p_tsi->EsNumStartCodeBytes > 0) {
473                    tsindex_p_callback(p_tsi);
474                    p_tsi->EsNumStartCodeBytes = 0;
475                }
476
477                p_tsi->PesMode = 1;
478                p_tsi->PesHeaderByteCount = 0;
479                p_tsi->PesHeaderSize = 0;
480            }
481            else
482            {
483                p_tsi->PesMode = 0;
484            }
485
486            /* Now we need to find where our payload begins */
487            p_tsi->TransByteOffset = 4;
488
489            /* Check for an adaptation field */
490            if( ((tsindex_readByte(p_curBfr,TS_ADAPT_BYTE) & TS_ADAPT_MASK) == 0x20)
491                || ((tsindex_readByte(p_curBfr,TS_ADAPT_BYTE) & TS_ADAPT_MASK) == 0x30) )
492            {
493                if(p_tsi->settings.is_avc && tsindex_readByte(p_curBfr,TS_ADAPT_LENGTH_BYTE) && (tsindex_readByte(p_curBfr,TS_RAI_BYTE) & TS_RAI_MASK)){
494                    p_tsi->curEntry.startCodeBytes = (1<<5);
495                    p_tsi->sctType = (1<<24);
496                    tsindex_p_callback(p_tsi);
497                    p_tsi->sctType = 0;
498                }
499
500                /* We need to skip past the adaptation field */
501                p_tsi->TransByteOffset += tsindex_readByte(p_curBfr,TS_ADAPT_LENGTH_BYTE) + 1;
502            }
503
504            if( p_tsi->PesMode )
505            {
506                p_tsi->curEntry.recordByteCount = p_tsi->TransRecordByteCount;
507                p_tsi->curEntry.startCodeBytes = p_tsi->TransByteOffset;
508                TS_DBGMSG(1,("  processPes\n"));
509                tsindex_processPes( p_tsi, p_curBfr, p_tsi->TransByteOffset,
510                    TS_PACKET_SIZE - p_tsi->TransByteOffset - TIMESTAMP_SIZE);
511            }
512
513            if( p_tsi->TransByteOffset != TS_PACKET_SIZE )
514            {
515                TS_DBGMSG(1,("  processEs\n"));
516                tsindex_processEs( p_tsi, p_curBfr, p_tsi->TransByteOffset,
517                    TS_PACKET_SIZE - p_tsi->TransByteOffset - TIMESTAMP_SIZE);
518            }
519
520        }
521        /* Advance to next transport packet */
522        p_tsi->TransRecordByteCount += TS_PACKET_SIZE;
523    }
524
525    return i;
526}
527
528/******************************************************************************
529* INPUTS:   p_tsi = pointer to a previously allocated sTsIndexer structure
530*           p_bfr = buffer containing transport data
531*           numBytes = number of bytes contained in p_bfr
532* OUTPUTS:  None.
533* RETURNS:  Number of packets processed.
534* FUNCTION: This function parses pes data and stores the start code
535*           tables through the previously installed cb function.
536******************************************************************************/
537long tsindex_feedPes( sTsIndexer * const p_tsi, const unsigned char *p_bfr, long numBytes )
538{
539    long i = 0;
540    long count;
541
542    /* We are parsing PES packets */
543    p_tsi->PesParseMode = 1;
544
545    while( i < numBytes )
546    {
547        p_tsi->TransByteOffset = 0;
548
549        if( p_tsi->PesMode )
550        {
551            p_tsi->curEntry.recordByteCount = p_tsi->TransRecordByteCount - 4;
552            p_tsi->curEntry.startCodeBytes = p_tsi->TransByteOffset;
553            count = tsindex_processPes( p_tsi, p_bfr, i, numBytes-i );
554        }
555        else
556        {
557            count = tsindex_processEs( p_tsi, p_bfr, i, numBytes-i );
558        }
559        i += count;
560        p_tsi->TransRecordByteCount += count;
561    }
562
563    return i;
564}
565
566/******************************************************************************
567* INPUTS:   p_tsi = pointer to a previously allocated sTsIndexer structure
568*           p_bfr = buffer containing transport data
569*           numBytes = number of bytes contained in p_bfr
570* OUTPUTS:  None.
571* RETURNS:  Number of packets processed.
572* FUNCTION: This function parses pes data and stores the start code
573*           tables through the previously installed cb function.
574*           We treat VOB files just like transport (except with a bigger
575*           sector size and pack header).
576*
577*           THIS MODE IS CURRENTLY NOT WORKING DUE TO START CODE TABLE FORMAT.
578*           IT REQUIRES RE-WORK TO ENSURE THAT THE PACKET OFFSET IS ABLE TO
579*           STORE AN OFFSET OF 2048 BYTES.
580******************************************************************************/
581long tsindex_feedVob( sTsIndexer * const p_tsi, const unsigned char *p_bfr, long numBytes )
582{
583    long i = 0;
584    const unsigned char *p_curBfr;
585
586    /* We are parsing vob packets */
587    p_tsi->PesParseMode = 0;
588
589    while( i < numBytes )
590    {
591        /* Check if we have a partial packet cached */
592        if( p_tsi->TransPacketValidCount
593            || ((numBytes - i) < VOB_PACKET_SIZE) )
594        {
595            /* Fill the rest of our transport cache */
596            while( i < numBytes )
597            {
598                p_tsi->TransPacket[p_tsi->TransPacketValidCount] = p_bfr[i];
599
600                p_tsi->TransPacketValidCount += 1;
601                i++;
602
603                if( p_tsi->TransPacketValidCount == VOB_PACKET_SIZE )
604                    break;
605            }
606
607            /* We do not have enough data to cache the entire packet, so return */
608            if( p_tsi->TransPacketValidCount != VOB_PACKET_SIZE )
609            {
610                return i;
611            }
612            else
613            {
614                p_curBfr = p_tsi->TransPacket;
615                p_tsi->TransPacketValidCount = 0;
616            }
617        }
618        else
619        {
620            p_curBfr = &(p_bfr[i]);
621            i += VOB_PACKET_SIZE;
622        }
623
624        /* Check for the pack header */
625        if( tsindex_readLong( p_curBfr, 0 ) != 0x000001BA )
626        {
627            /* This is not a VOB packet!! */
628            return -1;
629        }
630
631        /* Check for the appropriate PES header ID */
632        if( tsindex_readLong( p_curBfr, 14 ) == (0x00000100 | (unsigned long)p_tsi->pesStreamId) )
633        {
634            p_tsi->PesMode = 1;
635            p_tsi->PesHeaderByteCount = 0;
636            p_tsi->PesHeaderSize = 0;
637
638            /* Now we need to find where our payload begins */
639            p_tsi->TransByteOffset = 14;
640
641            p_tsi->curEntry.recordByteCount = p_tsi->TransRecordByteCount;
642            p_tsi->curEntry.startCodeBytes = p_tsi->TransByteOffset;
643            tsindex_processPes( p_tsi, p_curBfr, p_tsi->TransByteOffset, VOB_PACKET_SIZE - p_tsi->TransByteOffset );
644
645            if( p_tsi->TransByteOffset != VOB_PACKET_SIZE )
646            {
647                tsindex_processEs( p_tsi, p_curBfr, p_tsi->TransByteOffset, VOB_PACKET_SIZE - p_tsi->TransByteOffset );
648            }
649        }
650
651        /* Advance to next vob packet */
652        p_tsi->TransRecordByteCount += VOB_PACKET_SIZE;
653    }
654
655    return i;
656}
657
658
659/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
660+ INPUTS:   p_tsi = pointer to a previously allocated sTsIndexer structure
661+           p_bfr = buffer containing PES header bytes
662+           offset  = offset into the buffer in bytes
663+           numBytes = number of bytes remaining in the cur trans packet
664+ OUTPUTS:  None.
665+ RETURNS:  Number of bytes processed
666+ FUNCTION: This function processes the PES header, stores the corresponding
667+           start code entry, then returns the number of bytes that was
668+           processed.  It also clears the PesMode lag in the p_tsi structure
669+           that inidicates if the PES header has been entirely processed (ie
670+           ES data can now be processed), or if the PES header continues into
671+           the next transport packet.
672+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
673long tsindex_processPes( sTsIndexer * const p_tsi, const unsigned char *p_bfr,
674                        const long offset, long numBytes )
675{
676    long i = 0;
677
678#ifdef SWAPPED_STREAM
679    /* check the offset is a multiple of four.  If it is not then we need more work here */
680    if (offset % 4)
681        TS_DBGMSG(3,("PES Header not 4 byte aligned\n"));
682#endif
683
684    for( i = 0; i < numBytes; i++ )
685    {
686        /* Cache some of the pes header bytes */
687        if( p_tsi->PesHeaderByteCount+i < NUM_PES_BYTES_TO_CACHE )
688        {
689            p_tsi->PesHeader[p_tsi->PesHeaderByteCount + i] = p_bfr[i + offset];
690
691            if( p_tsi->PesHeaderByteCount + i == 4 )
692            {
693                if( (0xFFFFFFF0 & tsindex_readLong( p_tsi->PesHeader,0 )) !=
694                    (0xFFFFFFF0 & (0x00000100 | (unsigned long)p_tsi->pesStreamId) ))
695                {
696                    /* This is not the type of pes packet we are searching for! */
697                    p_tsi->PesMode = 0;
698                    p_tsi->PesHeaderByteCount = 0;
699                    p_tsi->PesHeaderSize = 0;
700                    p_tsi->validPesPacket = 0;
701                    break;
702                }
703                else
704                {
705                    p_tsi->validPesPacket = 1;
706                    p_tsi->actualPesStreamId = 0xFF & tsindex_readLong( p_tsi->PesHeader,0 );
707                }
708            }
709            else if( p_tsi->PesHeaderByteCount+i == 6 )
710            {
711                /* Store the size of this PES packet */
712                p_tsi->curEntry.startCodeBytes |= ((unsigned long)p_tsi->actualPesStreamId<<24) | tsindex_readShort( p_tsi->PesHeader,TS_PES_LENGTH_BYTE) << 8;
713
714                tsindex_p_callback(p_tsi);
715            }
716            else if( p_tsi->PesHeaderByteCount+i == 9 )
717            {
718                /* Set the PES header length */
719                p_tsi->PesHeaderSize = tsindex_readByte(p_tsi->PesHeader,TS_PES_HEADER_LENGTH_BYTE) + TS_PES_HEADER_LENGTH_BYTE + 1;
720            }
721            else if( p_tsi->PesHeaderByteCount+i == 14 )
722            {
723                if(tsindex_readByte(p_tsi->PesHeader,TS_PES_PTS_DTS_FLAGS) & 0x80)
724                {
725                    uint32_t pts;
726
727                    p_tsi->PesPtsFlag = 1;
728
729                    /* Save PTS in RAVE-style SCT format. pts = PES PTS bits 32..1 >> 1, discard bit 0.
730                    The mask shows which bits contain the TS_PES_PTS_xx_xx bits. Then we bit shift up or down to get it into final MSB-32-bit-PTS position. */
731                    pts = ((unsigned long)tsindex_readByte(p_tsi->PesHeader,TS_PES_PTS_32_30)&0xE) << 28;
732                    pts |= ((unsigned long)tsindex_readShort( p_tsi->PesHeader,TS_PES_PTS_29_15)&0xFFFE) << 13;
733                    pts |= ((unsigned long)tsindex_readShort( p_tsi->PesHeader,TS_PES_PTS_14_0)&0xFFFE) >> 2; /* drop LSB 1 bit */
734                    p_tsi->curEntry.startCodeBytes = (0xFEul << 24);
735                    p_tsi->curEntry.recordByteCount = 0;
736                    p_tsi->curEntry.recordByteCountHi = pts;
737                    p_tsi->curEntry.flags = 0;
738                    tsindex_p_callback(p_tsi);
739                }
740                else
741                {
742                    p_tsi->PesPtsFlag = 0;
743                }
744            }
745        }
746        /*
747         * We can't fit any more header data in our cache, so just just wait
748         * until all pes header data is parsed.
749         */
750        else if( p_tsi->PesHeaderByteCount+i == NUM_PES_BYTES_TO_CACHE )
751        {
752            p_tsi->PesMode = 0;
753        }
754
755        if( p_tsi->PesHeaderSize != 0
756            && p_tsi->PesHeaderByteCount+i == p_tsi->PesHeaderSize )
757        {
758            /* Once we read the entire pes header, then return */
759            p_tsi->PesMode = 0;
760            break;
761        }
762    }
763    p_tsi->TransByteOffset += i;
764    p_tsi->PesHeaderByteCount += i;
765
766    return i;
767}
768
769/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
770+ INPUTS:   p_tsi = pointer to a previously allocated sTsIndexer structure
771+           p_bfr = buffer containing ES bytes
772+           offset  = offset into the buffer in bytes
773+           numBytes = number of bytes remaining in the cur trans packet
774+ OUTPUTS:  None.
775+ RETURNS:  Number of bytes processed
776+ FUNCTION: This function processes the ES bytes and stores the corresponding
777+           start code entries.
778+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
779long tsindex_processEs( sTsIndexer * const p_tsi, const unsigned char *p_bfr,
780                       const long offset, long numBytes )
781{
782    long i = 0;
783
784    for( i = 0; i < numBytes; i++ )
785    {
786        unsigned char data = tsindex_readByte(p_bfr,(i + offset));
787
788        switch( p_tsi->EsNumStartCodeBytes )
789        {
790        case 1:
791            /* Save the start code */
792            p_tsi->curEntry.startCodeBytes = (data << 24) | p_tsi->savePacketOffset;
793            p_tsi->curEntry.recordByteCount = p_tsi->saveStreamOffset;
794
795            if( data >= p_tsi->settings.start_code_lo &&
796                data <= p_tsi->settings.start_code_hi &&
797                p_tsi->settings.is_avc)
798            {
799                p_tsi->EsNumStartCodeBytes += 1;
800                p_tsi->EsNumZeroBytes = 0;
801                continue;
802            }
803
804            if( data == 0x00 )
805            {
806                p_tsi->EsStoreNextSlice = 1;
807                p_tsi->EsStoreNextNonSlice = 1; /* allow the capture of start codes (e.g. B5) between start codes 00 and 01 */
808            }
809            else if( data >= p_tsi->settings.start_code_lo &&
810                data <= p_tsi->settings.start_code_hi )
811            {
812                /* Check if we want to store a non-slice start code now */
813                if( p_tsi->EsStoreNextNonSlice)
814                {
815                    if( data == 0xB7 )
816                    {
817                        /* Sequence end codes don't have any data following them, so store immediately */
818                        p_tsi->EsNumStartCodeBytes = 0;
819                        p_tsi->EsNumZeroBytes = 0;
820
821#ifdef STORE_SEQUENCE_END_CODES
822                        /* Next time only store a slice start code */
823                        p_tsi->EsStoreNextSlice = 1;
824                        p_tsi->EsStoreNextNonSlice = 0;
825
826                        /* Save this start code entry */
827                        if( p_tsi->validPesPacket )
828                        {
829                            tsindex_p_callback(p_tsi);
830                        }
831#endif
832                        continue;
833                    }
834                    else
835                    {
836                        /* Next time only store a slice start code */
837                        p_tsi->EsStoreNextSlice = 1;
838                        p_tsi->EsStoreNextNonSlice = 0;
839                    }
840                }
841                else
842                {
843                    /* We don't care about this start code, so move on */
844                    p_tsi->EsNumStartCodeBytes = 0;
845                    p_tsi->EsNumZeroBytes = 0;
846                    continue;
847                }
848            }
849            else if (data >= 0xB9 /* && data <= 0xFF */)
850            {
851                p_tsi->EsNumStartCodeBytes = 0;
852
853                /* This is not elementary stream data (may be a new PES packet) */
854                p_tsi->PesHeaderByteCount = 4;
855
856                /* Initialize the pes header data */
857                p_tsi->PesHeader[0] = p_tsi->PesHeader[1] = 0;
858                p_tsi->PesHeader[2] = 0x01;
859                p_tsi->PesHeader[3] = data;
860                p_tsi->PesMode = 1;
861
862                /* Since we found a pes start code init remove the pes zero bytes from the count */
863                p_tsi->EsNumZeroBytes -= 2;
864
865                return i+1;
866            }
867            else if( p_tsi->EsStoreNextSlice)
868            {
869                /* Next time only store a non-slice start code */
870                p_tsi->EsStoreNextNonSlice = 1;
871                p_tsi->EsStoreNextSlice = 0;
872            }
873            else
874            {
875                /* We don't care about this start code, so move on */
876                p_tsi->EsNumStartCodeBytes = 0;
877                p_tsi->EsNumZeroBytes = 0;
878                continue;
879            }
880            p_tsi->EsNumStartCodeBytes += 1;
881
882            /* Since we found a start code init our zero byte count */
883            p_tsi->EsNumZeroBytes = 0;
884            continue;
885
886        case 2:
887            /* Save the msb of the 1st byte after start code */
888            p_tsi->curEntry.startCodeBytes |= data << 16;
889            p_tsi->EsNumStartCodeBytes += 1;
890            /* we can't continue here because we might be actually starting the next
891            start code */
892            break;
893
894        case 3:
895            /* Save the lsb of the 1st byte after start code */
896            p_tsi->curEntry.startCodeBytes |= data << 8;
897
898            if( p_tsi->EsNumZeroBytes == 2 || p_tsi->settings.entry_size == 6)
899            {
900                p_tsi->EsNumStartCodeBytes += 1;
901            }
902            else
903            {
904                /* This is not the start of a PES header, so we can store the start code */
905                p_tsi->EsNumStartCodeBytes = 0;
906                p_tsi->EsNumZeroBytes = 0;
907
908                /* Save this start code entry */
909                if( p_tsi->validPesPacket )
910                {
911                    tsindex_p_callback(p_tsi);
912                }
913            }
914            /* we can't continue here because we might be actually starting the next
915            start code */
916            break;
917
918#ifdef DETECT_EMBEDDED_PES_PACKETS
919        case 4:
920            /* Check if we have found a PES header immediately following a start code */
921            if( p_tsi->EsNumZeroBytes == 2 && data == 0x01 )
922            {
923                /* Resume where we left off after the PES header */
924                p_tsi->EsNumStartCodeBytes = 2;
925
926                /* This is not elementary stream data (may be a new PES packet) */
927                p_tsi->PesHeaderByteCount = 3;
928
929                /* Initialize the pes header data */
930                p_tsi->PesHeader[0] = p_tsi->PesHeader[1] = 0;
931                p_tsi->PesHeader[2] = 0x01;
932                p_tsi->PesMode = 1;
933
934                /* Since we found a pes start code init remove the pes zero bytes from the count */
935                p_tsi->EsNumZeroBytes = 0;
936
937                return i+1;
938            }
939            else
940            {
941                /* This is not the start of a PES header, so we can store the start code */
942                p_tsi->EsNumZeroBytes = 0;
943
944                /* Save this start code entry */
945                if( p_tsi->validPesPacket )
946                {
947                    tsindex_p_callback(p_tsi);
948                }
949            }
950            continue;
951#else
952        case 4:
953        case 5:
954        case 6:
955        case 7:
956        case 8:
957        case 9:
958            /* capture up to 6 bytes of additional ES data for 6 word format */
959            if (p_tsi->settings.entry_size == 6) {
960                int i = p_tsi->EsNumStartCodeBytes - 4;
961
962                /* Fill the payload */
963                if (i < 3)
964                    p_tsi->curEntry.recordByteCountHi |= data << ((2-i)*8);
965                else
966                    p_tsi->curEntry.flags |= data << ((2-(i-3))*8);
967
968                if (i == 5) {
969                    /* We filled the payload */
970                    tsindex_p_callback(p_tsi);
971                    p_tsi->EsNumStartCodeBytes = 0;
972                }
973                else {
974                    p_tsi->EsNumStartCodeBytes++;
975                }
976            }
977            break;
978#endif
979
980        default:
981            break;
982        }
983
984        if( data == 0x00 )
985        {
986            p_tsi->EsNumZeroBytes += 1;
987
988            /* The previous zero location is the actual start of the start code sequence.
989            Store this is a temp location because we might be finishing up the payload
990            of a previous startcode. It's unknown at this point. */
991            if( p_tsi->PesParseMode )
992            {
993                p_tsi->saveStreamOffset = p_tsi->EsRecordByteCount + p_tsi->EsStartCodeBytes;
994                p_tsi->savePacketOffset = 0;
995            }
996            else
997            {
998                p_tsi->saveStreamOffset = p_tsi->EsRecordByteCount;
999                p_tsi->savePacketOffset = p_tsi->EsStartCodeBytes;
1000            }
1001
1002            /* Save our location just in case this turns out to be a start code we need to save */
1003            p_tsi->EsRecordByteCount = p_tsi->TransRecordByteCount;
1004            p_tsi->EsStartCodeBytes = p_tsi->TransByteOffset + i;
1005        }
1006        else if( data == 0x01 && p_tsi->EsNumZeroBytes > 1 )
1007        {
1008            /* if currently capturing start code payload, fire callback */
1009            if (p_tsi->EsNumStartCodeBytes > 0) {
1010                tsindex_p_callback(p_tsi);
1011            }
1012
1013            /* We found a start code! */
1014            p_tsi->EsNumStartCodeBytes = 1;
1015        }
1016        else
1017        {
1018            p_tsi->EsNumZeroBytes = 0;
1019        }
1020    }
1021    p_tsi->TransByteOffset += i;
1022
1023    return i;
1024}
1025
1026/******************************************************************************
1027* INPUTS:   p_tsi = pointer to a previously allocated sTsIndexer structure
1028*           p_entry = pointer to array of start code entries
1029*           numEntries = number of bytes contained in p_bfr
1030* OUTPUTS:  None.
1031* RETURNS:  Number of entries processed.
1032* FUNCTION: This function parses the transport start code data and
1033*           adds the msbyte of the record offset if the recorded stream has
1034*           gone beyond 32 bits (4 GB).
1035******************************************************************************/
1036long tsindex_updateRecordByteCountHi( sTsIndexer * const p_tsi, sIndexEntry *p_entry, long numEntries )
1037{
1038    long i;
1039    long firstNonPtsSc = -1, lastNonPtsSc = -1;
1040
1041    /* Skip PTS start codes */
1042    for( i = 0; i < numEntries; i++ )
1043    {
1044        if( (p_entry[i].startCodeBytes >> 24) != 0xFE )
1045        {
1046            firstNonPtsSc = i;
1047            break;
1048        }
1049    }
1050
1051    /* All the start codes we checked were PTS start codes */
1052    if( firstNonPtsSc == -1 )
1053    {
1054        return numEntries;
1055    }
1056
1057    /* Skip PTS start codes */
1058    for( i = numEntries; i > 0; i-- )
1059    {
1060        if( (p_entry[i].startCodeBytes >> 24) != 0xFE )
1061        {
1062            lastNonPtsSc = i;
1063            break;
1064        }
1065    }
1066
1067    /* Wait for record byte count to wrap at least once before having to modify start code table data */
1068    if( (p_entry[firstNonPtsSc].recordByteCount > p_tsi->TransRecordByteCount)
1069        && (p_entry[lastNonPtsSc].recordByteCount > p_tsi->TransRecordByteCount)
1070        && (p_tsi->TransRecordByteCountHi == 0) )
1071    {
1072        return numEntries;
1073    }
1074
1075    for( i = 0; i < numEntries; i++ )
1076    {
1077        /* Skip PTS start codes */
1078        if( (p_entry[i].startCodeBytes >> 24) == 0xFE )
1079        {
1080            continue;
1081        }
1082
1083        /* Check for wrap */
1084        if( p_entry[i].recordByteCount < p_tsi->TransRecordByteCount )
1085        {
1086            p_tsi->TransRecordByteCountHi += 1;
1087        }
1088
1089        p_tsi->TransRecordByteCount = p_entry[i].recordByteCount;
1090        /* TODO: recordByteCountHi = should likely be recordByteCountHi |=. but this function is unused, so don't fix it now. */
1091        p_entry[i].recordByteCountHi = (p_tsi->TransRecordByteCountHi << 24);
1092    }
1093
1094    return numEntries;
1095}
1096
Note: See TracBrowser for help on using the repository browser.