source: svn/trunk/newcon3bcm2_21bu/BSEAV/lib/bcmplayer/src/bcmindexer.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: 74.2 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: bcmindexer.c $
11 * $brcm_Revision: 32 $
12 * $brcm_Date: 6/22/10 11:13a $
13 *
14 * Module Description: Converts startcode index to bcmplayer index
15 *
16 * Revision History:
17 *
18 * $brcm_Log: /BSEAV/lib/bcmplayer/src/bcmindexer.c $
19 *
20 * 32   6/22/10 11:13a erickson
21 * SW7405-4465: add BNAV_Indexer_Settings.ptsBasedFrameRate for PTS-based
22 * offline indexing
23 *
24 * 31   6/21/10 4:31p erickson
25 * SW7405-4249: added BNAV_Version_TimestampOnly option for indexing
26 * audio-only or scrambled streams
27 *
28 * 30   6/4/10 5:37p erickson
29 * SW7400-2788: provide a minimal safe increment so that timestamps can be
30 * unique and guaranteed increasing
31 *
32 * 29   6/2/10 12:51p erickson
33 * SW7400-2789: add BNAV_Indexer_Settings.allowLargeTimeGaps
34 *
35 * 28   5/13/10 9:51a erickson
36 * SW7405-4105: add full packet parsing support. enabled >10 ITB's per TS
37 * packet.
38 *
39 * 27   4/30/10 11:51a erickson
40 * SW7405-4105: fix parsing of AVC payload bytes [5] and [6]. add debug.
41 * remove support for non-RAVE SCT format.
42 *
43 * 26   3/16/10 2:17p erickson
44 * CDSTRMANA-294: support indexing of field-encoded MPEG streams
45 *
46 * 25   2/25/10 10:42a erickson
47 * SW7400-2685: fix bcmindexer's handling of adjacent I frames
48 *
49 * 24   2/12/10 2:47p erickson
50 * SW7400-2685: add BDBG_ERR for unknown picture_coding_type
51 *
52 * 23   11/11/09 4:39p erickson
53 * SWDEPRECATED-3668: make global into a const
54 *
55 * 22   4/17/09 7:06a erickson
56 * PR54150: check gettimeofday return code
57 *
58 * 21   2/25/09 5:04p erickson
59 * PR52471: make global data const
60 *
61 * 20   1/12/09 4:10p erickson
62 * PR49501: downgrade ERR to MSG
63 *
64 * 19   1/7/09 11:09p erickson
65 * PR49501: add append settings. removed BCM7030 support to make 40 bit
66 * offset support easier.
67 *
68 * 18   10/22/08 1:06p vishk
69 * PR 48074: Coverity Defect ID:12257 DEADCODE bcmindexer.c
70 * Product=97401linux
71 *
72 * 17   7/16/08 11:19a erickson
73 * PR44853: clean up -Wstrict-prototypes warning
74 *
75 * 16   4/2/08 9:32a erickson
76 * PR41171: fix misspelling
77 *
78 * 15   4/2/08 9:23a erickson
79 * PR41165: assign p_curBfr before using it
80 *
81 * 14   2/26/08 12:28p katrep
82 * PR38429: Added AVS record and playback support
83 *
84 * 13   2/5/08 3:52p gmohile
85 * PR 38979 : Add Random Access indicator in index file
86 *
87 * 12   1/3/08 6:21p erickson
88 * PR36068: switch B_HAS_RAVE to opt-out. all new chips have RAVE. if you
89 * are using a legacy chip with latest bcmplayer, please add your
90 * BCHP_CHIP.
91 *
92 * 11   12/27/07 3:27p erickson
93 * PR37035: if there's a gap in the recording, reset the timestamp base so
94 * that it is skipped
95 *
96 * 10   12/17/07 1:44p katrep
97 * PR37217: Added 7335 support
98 *
99 * 9   10/10/07 5:50p vishk
100 * PR 35272: SettopAPI-Coverity (CID 327): DEADCODE,
101 *
102 * 8   10/5/07 11:06a vishk
103 * PR 35272: SettopAPI-Coverity (CID 327): DEADCODE,
104 *
105 * 6   9/11/07 4:29p arbisman
106 * PR33338: Udate 7400 WinCE 5.0 branch
107 *
108 * 5   3/28/07 11:48p erickson
109 * PR27189: changed SEI indexing logic. previously, we including trailing
110 * SEI's with SPS's and PPS's. with this code, we are including leading
111 * SEI's with SPS's, PPS's and pictures. this is needed for trick modes
112 * on streams that use SEI recovery points.
113 *
114 * 4   2/7/07 11:07p katrep
115 * PR27183: Added debug code to vlidate SCT generated by HW.
116 *
117 * 3   2/2/07 3:06p erickson
118 * PR26328: added #ifndef B_IS_SOFTINDEXER
119 *
120 * 2   11/27/06 1:59p erickson
121 * PR25109: added 7403/7405 support
122 *
123 * Irvine_BSEAVSW_Devel/81   10/20/06 10:58a erickson
124 * PR21742: print error if framesize == 0
125 *
126 * Irvine_BSEAVSW_Devel/80   10/5/06 3:34p mward
127 * PR21671: 7118 B_HAS_RAVE
128 *
129 * Irvine_BSEAVSW_Devel/79   6/30/06 2:52p erickson
130 * PR21941: fix debug msg
131 *
132 * Irvine_BSEAVSW_Devel/78   6/23/06 8:46a erickson
133 * PR21941: downgrade open GOP WRN to MSG
134 *
135 * Irvine_BSEAVSW_Devel/77   5/11/06 3:31p mphillip
136 * PR20797: Replace currentTimestamp implementation to avoid an overflow
137 * resulting in bogus values on trimming
138 *
139 * Irvine_BSEAVSW_Devel/76   4/6/06 11:35a jrubio
140 * PR18463: Removed >>1 for PTS on RAVE.
141 *
142 * Irvine_BSEAVSW_Devel/75   3/31/06 4:24p erickson
143 * PR20569: parse PTS from SCT for RAVE platforms
144 *
145 * Irvine_BSEAVSW_Devel/74   3/6/06 1:20p erickson
146 * PR19853: added VC1 PES support
147 *
148 * Irvine_BSEAVSW_Devel/73   1/6/06 4:45p erickson
149 * PR17108: cleaned up DEBUG=n warnings
150 *
151 * Irvine_BSEAVSW_Devel/72   8/25/05 12:36p erickson
152 * PR16678: merged WinCE changes
153 *
154 * Irvine_BSE_Release/PROD_WinCE50/2   8/19/05 4:15p arbisman
155 * PR16678: Add support for WinCE
156 *
157 * Irvine_BSEAVSW_Devel/71   8/19/05 3:59p erickson
158 * PR16208: terminate the PPS and SPS after the SEI, which allows the SEI
159 * to be sent without indexing it separately
160 *
161 * Irvine_BSEAVSW_Devel/70   8/8/05 3:58p erickson
162 * PR16138: handle all PES start codes (not just E0), and avoid bad logic
163 * for swapping B's and P's
164 *
165 * Irvine_BSEAVSW_Devel/69   8/3/05 12:07p erickson
166 * PR16138: change definition of B frame in NAV table for AVC streams. It
167 * is now "non-I frame which is not a reference picture." See comment in
168 * code.
169 *
170 * Irvine_BSEAVSW_Devel/68   7/15/05 8:25p erickson
171 * PR16138: fixed AVC rfo and sps_id, added debug
172 *
173 * Irvine_BSEAVSW_Devel/67   7/13/05 2:10p erickson
174 * PR16138: added new NAV version for AVC support, PPS and SPS support
175 * added, refactored player to better support this with less code
176 * duplication
177 *
178 * Irvine_BSEAVSW_Devel/66   7/8/05 10:11a erickson
179 * PR16155: remove debug
180 *
181 * Irvine_BSEAVSW_Devel/65   7/8/05 9:57a erickson
182 * PR16155: changed b_vlc_decode calling convention
183 *
184 * Irvine_BSEAVSW_Devel/64   7/7/05 1:18p erickson
185 * PR16138: added support for non-IDR I frame for AVC, and capture (but
186 * not use of) SPS and PPS.
187 *
188 * Irvine_BSEAVSW_Devel/63   3/22/05 5:01p erickson
189 * PR14451: fixed 6word, non-avc
190 *
191 * Irvine_BSEAVSW_Devel/62   3/21/05 3:43p erickson
192 * PR14451: moved vlc decode algorithm to separate file
193 *
194 * Irvine_BSEAVSW_Devel/61   3/21/05 12:25p erickson
195 * PR14451: fixed FeedAVC for more than 1 SCT at a time
196 *
197 * Irvine_BSEAVSW_Devel/60   3/18/05 2:13p erickson
198 * PR14451: working impl of AVC trick modes
199 *
200 * Irvine_BSEAVSW_Devel/59   3/18/05 10:01a erickson
201 * PR14451: added first pass AVC indexing support
202 *
203 * Irvine_BSEAVSW_Devel/58   12/14/04 4:54p marcusk
204 * PR13560: Updated to default to frameratesimulation to 0.  Command line
205 * indexer updated to accept frame rate setting.
206 *
207 * Irvine_BSEAVSW_Devel/57   9/21/04 4:06p erickson
208 * PR12728: cleaned up pedantic warnings
209 *
210 * Irvine_BSEAVSW_Devel/56   5/10/04 11:33a erickson
211 * PR10065: fixed compiler warnings (most were unsigned/signed mismatches)
212 *
213 * Irvine_BSEAVSW_Devel/55   4/30/04 12:57p erickson
214 * PR10909: default to magnum kernelinterface (debug or release) but
215 * support legacy if specifically requested
216 *
217 * Irvine_BSEAVSW_Devel/54   4/13/04 4:59p erickson
218 * PR10292: added BNAV_Indexer_FeedReverse and refactored completeFrame to
219 * put common code in BNAV_Indexer_StampEntry
220 *
221 * Irvine_BSEAVSW_Devel/53   11/11/03 5:03p erickson
222 * PR8563: wasn't indexing for timestamps correctly. Now that I am, brcm
223 * trick modes are working.
224 *
225 * Irvine_BSEAVSW_Devel/52   11/10/03 2:29p erickson
226 * PR8563: added transport timestamp support to bcmplayer
227 *
228 * Irvine_BSEAVSW_Devel/51   9/17/03 12:11p erickson
229 * support both original and magnum debug interfaces
230 * replaced kernel interface calls with ansi calls
231 *
232 * Irvine_BSEAVSW_Devel/50   8/14/03 10:35a erickson
233 * removed printf
234 *
235 * Irvine_BSEAVSW_Devel/49   7/21/03 2:32p erickson
236 * added support for B7's (sequence end codes)
237 *
238 * Irvine_BSEAVSW_Devel/48   6/24/03 3:11p erickson
239 * don't have MSG's by default
240 *
241 * Irvine_BSEAVSW_Devel/47   6/24/03 11:03a erickson
242 * PR7218 - handled partially encrypted streams. Added maxFrameSize and
243 * mpegSizeCallback. Had to change the
244 * NAV table format (version 2) in order to handle I frames with reference
245 * offset of 0. Bcmplayer
246 * is backward compatible.
247 *
248 * Irvine_BSEAVSW_Devel/46   6/19/03 9:04a erickson
249 * added BNAV_Indexer_GetPosition (PR7211)
250 *
251 * Irvine_BSEAVSW_Devel/45   3/11/03 3:59p erickson
252 * fixed debug interface usage
253 *
254 * Irvine_BSEAVSW_Devel/44   2/14/03 2:40p erickson
255 * removed \n's from debug msg
256 *
257 * Irvine_BSEAVSW_Devel/43   2/14/03 1:57p erickson
258 * New naming convention
259 * Fixed looping from previous rework
260 * Removed bcmindexer _getParam/_setParam
261 * Did not change code shared between tsplayer and bcmplayer
262 * Refactored settings, playmode and other structures
263 *
264 * Irvine_BSEAVSW_Devel/42   2/10/03 5:42p erickson
265 * updated tests and utils for new bcmplayer
266 *
267 * Irvine_HDDemo_Devel/41   9/26/02 3:4p erickson
268 * Changed bcmindexer vchip from 3 bits to 16 bits packed into 12 bits.
269 * The index is NOT backward compatible, but the 3 bit version had only
270 * been released for 1 day.
271 *
272 * Irvine_HDDemo_Devel/40   9/10/02 10:38a erickson
273 * converted vchip from 16 bits in [7] to 3 bits in [5]
274 *
275 ***************************************************************************/
276#ifndef USE_LEGACY_KERNAL_INTERFACE
277/* Magnum debug interface */
278#include "bstd.h"
279#include "bkni.h"
280BDBG_MODULE(bcmindexer);
281#else
282/* Original debug interface */
283#define BRCM_DBG_MODULE_NAME "bcmindexer"
284#include "brcm_dbg.h"
285#define BDBG_ERR(X) BRCM_DBG_ERR(X)
286#define BDBG_WRN(X) BRCM_DBG_WRN(X)
287#define BDBG_MSG(X) BRCM_DBG_MSG(X)
288#define BDBG_DEBUG_BUILD 1
289#endif
290
291#if 0
292/* easy way to turn on debug */
293#include <stdio.h>
294#undef BDBG_MSG
295#define BDBG_MSG(X) do{printf X; printf("\n");}while(0)
296#undef BDBG_WRN
297#define BDBG_WRN(X) do{printf X; printf("\n");}while(0)
298#endif
299
300#define BDBG_MSG_TRACE(X) /* BDBG_MSG(X) */
301
302#include "bcmindexer.h"
303#include "bcmindexerpriv.h"
304#include "mpeg2types.h"
305#include "avstypes.h"
306#include "bvlc.h"
307#include <string.h>
308#include <stdlib.h>
309#ifdef LINUX
310#include <sys/time.h>
311#include <unistd.h>
312#elif defined __vxworks
313#include <time.h>
314#elif defined _WIN32_WCE
315#include <Windows.h>
316#include <mmsystem.h>
317#endif
318
319/* If we offset two words into an SCT6 entry, it looks just like an SCT4 entry,
320ignoring the extra payload bytes */
321#define CONVERT_TO_SCT4(P_SCT6_ENTRY) \
322    ((BSCT_Entry*)((char*)P_SCT6_ENTRY+(sizeof(BSCT_SixWord_Entry)-sizeof(BSCT_Entry))))
323
324/* enable this to add start code validation
325   debug messages at the compile time */
326/* #define VALIDATE_SC_NAV */
327#ifdef VALIDATE_SC_NAV
328#define VALIDATE_MPEG_SC(p_curBfr,sc) \
329        if(((p_curBfr->startCodeBytes&0xff) > 0xbc)||!(sc==SC_ANY_NON_PTS||sc==SC_PTS||sc==SC_PES||sc==SC_SEQUENCE \
330            ||sc==SC_PICTURE||sc==SC_FIRST_SLICE||sc==SC_EXTENSION||sc==SC_SEQ_END||sc==SC_GOP||sc==SC_PES_END \
331            ||sc==PC_I_FRAME||sc==PC_P_FRAME||sc==PC_B_FRAME||sc==PC_ANY_FRAME))\
332        {\
333          BDBG_WRN(("Invalid SCT Entry: %02x pkt offset 0x%02lx%08lx,sc offset 0x%02x",sc, \
334          (p_curBfr->recordByteCountHi>>24)&0xff,p_curBfr->recordByteCount,p_curBfr->startCodeBytes & 0xff));\
335        }
336
337#define VALIDATE_AVC_SC(p_curSct4,sc)                   \
338        if((p_curSct4->startCodeBytes&0xff)>0xbc)       \
339        {                                               \
340          BDBG_WRN(("Invalid SCT Entry: %02x pkt offset 0x%02lx%08lx,offset 0x%02x", sc, \
341          (p_curSct4->recordByteCountHi>>24) & 0xFF, p_curSct4->recordByteCount,p_curSct4->startCodeBytes & 0xff));\
342        }
343
344#define VALIDATE_AVS_SC(p_curBfr,sc) \
345        if(((p_curBfr->startCodeBytes&0xff) > 0xbc)||!(sc==SC_AVS_ANY_NON_PTS||sc==SC_AVS_PTS||sc==SC_AVS_PES||sc==SC_AVS_SEQUENCE \
346            ||sc==SC_AVS_PICTURE_I ||sc==SC_AVS_PICTURE_PB ||sc==SC_AVS_EXTENSION||sc==SC_AVS_SEQ_END||sc==SC_AVS_PES_END \
347            ||sc==PC_AVS_P_FRAME||sc==PC_AVS_B_FRAME || sc==SC_AVS_FIRST_SLICE  ))\
348        {\
349          BDBG_WRN(("Invalid AVS SCT Entry: %02x pkt offset 0x%02lx%08lx,sc offset 0x%02x",sc, \
350          (p_curBfr->recordByteCountHi>>24)&0xff,p_curBfr->recordByteCount,p_curBfr->startCodeBytes & 0xff));\
351        }
352
353#define VALIDATE_MPEG_NAV(frameType)\
354        if(!(frameType == eSCTypeIFrame || frameType == eSCTypePFrame ||\
355           frameType == eSCTypeBFrame || eSCTypeBFrame == eSCTypeRPFrame))\
356        {\
357        }
358#else
359
360#define VALIDATE_MPEG_SC(sc_offset,sc)
361#define VALIDATE_AVC_SC(sc_offset,sc)
362#define VALIDATE_AVS_SC(p_curBfr,sc)
363#define VALIDATE_MPEG_NAV(frameType)
364
365#endif
366
367
368/*---------------------------------------------------------------
369- PRIVATE FUNCTIONS
370---------------------------------------------------------------*/
371static unsigned long BNAV_Indexer_returnPts(const BSCT_Entry *p_sct );
372static int BNAV_Indexer_completeFrame( BNAV_Indexer_Handle handle );
373static void BNAV_Indexer_StampEntry(BNAV_Indexer_Handle handle, BNAV_Entry *entry);
374static unsigned long BNAV_Indexer_subtractByteCounts( unsigned long largerNum, unsigned long smallerNum );
375static unsigned long BNAV_Indexer_getScByteOffsetLo( BNAV_Indexer_Handle handle, const BSCT_Entry *p_entry );
376static unsigned long BNAV_Indexer_getScByteOffsetHi( BNAV_Indexer_Handle handle, const BSCT_Entry *p_entry );
377static long BNAV_Indexer_FeedAVC(BNAV_Indexer_Handle handle, const void *p_bfr, long numEntries);
378static long BNAV_Indexer_FeedAVS(BNAV_Indexer_Handle handle, void *p_bfr, long numEntries);
379static int BNAV_Indexer_Flush(BNAV_Indexer_Handle handle);
380static int BNAV_Indexer_completeTimestampFrame(BNAV_Indexer_Handle handle);
381
382/**
383* currentTimestamp returns the # of milliseconds from some fixed point in the past.
384* I currently have a LINUX version. The generic version is only 1 second accurate,
385* which might be sufficient if the requirement is to make +/- 30 second jumps.
386**/
387static unsigned int currentTimestamp(void) {
388#if defined LINUX
389    struct timeval tv;
390    if (gettimeofday(&tv, NULL)) {
391        return 0;
392    }
393    else {
394        return tv.tv_sec*1000+(tv.tv_usec/1000);
395    }
396#elif defined __vxworks
397    return time(NULL) * 1000;
398#elif defined _WIN32_WCE
399    return GetTickCount();
400#endif
401}
402
403void BNAV_Indexer_GetDefaultSettings(BNAV_Indexer_Settings *settings)
404{
405    memset(settings, 0, sizeof(*settings));
406    settings->simulatedFrameRate = 0;
407    settings->sctVersion = BSCT_Version40bitOffset;
408    settings->videoFormat = BNAV_Indexer_VideoFormat_MPEG2;
409    settings->navVersion = BNAV_VersionLatest;
410    settings->maxFrameSize = 5 * 1024 * 1024; /* We've seen 500K HD I frames. This is 10x larger. */
411}
412
413/******************************************************************************
414* INPUTS:   cb = pointer to a function that stores table entries (same format as fwrite)
415*           fp = general pointer that is passed in as param 3 into cb function
416*           pid = pid of the transport stream used for table generation
417* OUTPUTS:  None.
418* RETURNS:  pointer to sBcmIndexer structure
419* FUNCTION: This function allocates and initializes an indexer structure.
420******************************************************************************/
421int BNAV_Indexer_Open(BNAV_Indexer_Handle *handle, const BNAV_Indexer_Settings *settings)
422{
423    *handle = (BNAV_Indexer_Handle)malloc( sizeof( struct BNAV_Indexer_HandleImpl) );
424    if (BNAV_Indexer_Reset(*handle, settings)) {
425        free(*handle);
426        return -1;
427    }
428    return 0;
429}
430
431int BNAV_Indexer_Reset(BNAV_Indexer_Handle handle, const BNAV_Indexer_Settings *settings)
432{
433    int result = 0;
434
435    if (!settings->writeCallback ||
436        !settings->filePointer)
437    {
438        BDBG_ERR(("Missing required settings"));
439        return -1;
440    }
441
442    if (settings->videoFormat == BNAV_Indexer_VideoFormat_AVC &&
443        settings->navVersion != BNAV_Version_AVC)
444    {
445        BDBG_ERR(("You need to select an AVC BNAV_Version for bcmindexer."));
446        return -1;
447    }
448    else if (settings->videoFormat != BNAV_Indexer_VideoFormat_AVC &&
449        settings->navVersion == BNAV_Version_AVC)
450    {
451        BDBG_ERR(("You need to select an MPEG2 BNAV_Version for bcmindexer."));
452        return -1;
453    }
454    else if (settings->videoFormat != BNAV_Indexer_VideoFormat_AVS &&
455        settings->navVersion == BNAV_Version_AVS)
456    {
457        BDBG_ERR(("You need to select an MPEG2 BNAV_Version for bcmindexer."));
458        return -1;
459    }
460    else if (settings->navVersion >= BNAV_VersionUnknown) {
461        BDBG_ERR(("Unsupported BNAV_Version"));
462        return -1;
463    }
464
465    memset(handle, 0, sizeof(*handle));
466
467    handle->settings = *settings;
468
469    if (!settings->simulatedFrameRate && !settings->ptsBasedFrameRate) {
470        /* real, not simulated */
471        handle->lasttime = handle->starttime = currentTimestamp();
472    }
473
474    BNAV_set_frameType(&(handle->curEntry), eSCTypeUnknown);
475    BNAV_set_frameType(&(handle->avcEntry), eSCTypeUnknown);
476
477    BNAV_set_frameOffsetLo(&(handle->curEntry), handle->settings.append.offsetLo);
478    BNAV_set_frameOffsetHi(&(handle->curEntry), handle->settings.append.offsetHi);
479    BNAV_set_frameOffsetLo(&(handle->avcEntry), handle->settings.append.offsetLo);
480    BNAV_set_frameOffsetHi(&(handle->avcEntry), handle->settings.append.offsetHi);
481
482    handle->isHits = 1;  /* Assume HITS until we're proven wrong */
483    handle->avc.current_sps = handle->avc.current_pps = -1;
484
485    return result;
486}
487
488/******************************************************************************
489* INPUTS:   handle = pointer to a previously allocated sBcmIndexer structure
490* OUTPUTS:  None.
491* RETURNS:  None.
492* FUNCTION: This function frees any memory used by an indexer structure.
493******************************************************************************/
494void BNAV_Indexer_Close(BNAV_Indexer_Handle handle)
495{
496    free((void *)handle);
497}
498
499static void BNAV_Indexer_P_AddAppend(BNAV_Indexer_Handle handle, unsigned long *offsetHi, unsigned long *offset)
500{
501    if (handle->settings.append.offsetHi || handle->settings.append.offsetLo) {
502        off_t value = ((off_t)*offsetHi << 32) + *offset;
503
504        /* add the append amount */
505        value += ((off_t)handle->settings.append.offsetHi << 32) + handle->settings.append.offsetLo;
506
507        *offset = value & 0xFFFFFFFF;
508        *offsetHi = value >> 32;
509    }
510}
511
512long BNAV_Indexer_Feed(BNAV_Indexer_Handle handle, void *p_bfr, long numEntries)
513{
514    long i;
515    const BSCT_Entry *p_curBfr;
516    int inc;
517    BNAV_Entry *navEntry = &handle->curEntry;
518
519    if (handle->settings.videoFormat == BNAV_Indexer_VideoFormat_AVC) {
520        return BNAV_Indexer_FeedAVC(handle, p_bfr, numEntries);
521    }
522    else if(handle->settings.videoFormat == BNAV_Indexer_VideoFormat_AVS){
523        return BNAV_Indexer_FeedAVS(handle, p_bfr, numEntries);
524    }
525
526    switch (handle->settings.sctVersion) {
527    case BSCT_Version32bitOffset:
528        return BERR_TRACE(BERR_NOT_SUPPORTED);
529    case BSCT_Version40bitOffset:
530        /* convert 32 bit byte count to 40 bits for venom2 */
531        p_curBfr = p_bfr;
532        inc = sizeof(BSCT_Entry);
533        break;
534    case BSCT_Version6wordEntry:
535        /* Offseting into BSCT_SixWordEntry gives the same
536        as BSCT_Entry. We don't care about the first two words. */
537        p_curBfr = CONVERT_TO_SCT4(p_bfr);
538        inc = sizeof(BSCT_SixWord_Entry);
539        break;
540    default:
541        return -1;
542    }
543
544    for(i=0; i<numEntries; ++i)
545    {
546        int sc = returnStartCode(p_curBfr->startCodeBytes); /* parse once */
547        unsigned long offset = BNAV_Indexer_getScByteOffsetLo(handle, p_curBfr);
548        unsigned long offsetHi = BNAV_Indexer_getScByteOffsetHi(handle, p_curBfr);
549
550        BNAV_Indexer_P_AddAppend(handle, &offsetHi, &offset);
551
552        /* detect invalid start code and offsets */
553        VALIDATE_MPEG_SC(p_curBfr,sc);
554
555        BDBG_MSG_TRACE(("SCT Entry: %02x 0x%02lx%08lx", sc, offsetHi, offset));
556
557        if (handle->settings.navVersion == BNAV_Version_TimestampOnly) {
558            switch (sc) {
559            /* BNAV_Version_TimestampOnly does not require PTS, but it will index it if found */
560            case SC_PTS:
561                handle->next_pts = BNAV_Indexer_returnPts(p_curBfr);
562                break;
563            default:
564                /* BNAV_Version_TimestampOnly requires at least one non-PTS startcode so it can get
565                the file offset. Without the file offset, the timestamp has no use. */
566                {
567                    long currenttime = currentTimestamp();
568                    unsigned framesize = BNAV_Indexer_subtractByteCounts( offset, handle->picStart);
569
570                    /* don't write out NAV's more than 1 per 30 msec or that are too small. */
571                    if (currenttime >= handle->lasttime + 30 && framesize > 1000) {
572                        BNAV_set_frameSize(navEntry, framesize);
573                        BNAV_Indexer_completeTimestampFrame( handle );
574
575                        /* record the start of the next frame */
576                        BNAV_set_framePts(navEntry, handle->next_pts);
577                        BNAV_set_frameOffsetLo(navEntry, offset);
578                        BNAV_set_frameOffsetHi(navEntry, offsetHi);
579                        handle->picStart = offset;
580                    }
581                }
582                break;
583            }
584            continue;
585        }
586
587        if (handle->seqHdrFlag) {
588            if (sc != SC_PES && sc != SC_PTS && sc != SC_EXTENSION) {
589                handle->seqHdrFlag = 0;
590                handle->seqHdrSize = BNAV_Indexer_subtractByteCounts(offset, handle->seqHdrStartOffset);
591            }
592        }
593
594        if (sc == SC_PICTURE && handle->fieldEncodedCount == 1) {
595            /* we've only processed one field of a field encoded picture. skip this one. */
596            goto skip;
597        }
598
599        switch(sc)
600        {
601        case SC_FIRST_SLICE:
602            /* I-slice check here */
603            if (returnIntraSliceBit(p_curBfr->startCodeBytes) && handle->isHits) {
604                BNAV_set_frameType(navEntry, eSCTypeRPFrame);
605                handle->isISlice = 1;
606            }
607            break;
608
609        case SC_PES:
610            break;
611
612        case SC_PTS:
613            handle->next_pts = BNAV_Indexer_returnPts(p_curBfr);
614            break;
615
616        case SC_SEQUENCE:
617            handle->seqHdrStartOffset = offset;
618            handle->seqHdrFlag = 1; /* set on next qualifying sct */
619
620            /* complete any pending frame */
621            handle->picEnd = handle->seqHdrStartOffset;
622            handle->fieldEncodedCount = 0;
623            BNAV_Indexer_completeFrame( handle );
624            break;
625
626        case SC_SEQ_END:   /* TODO: Change me to any non-slice */
627            /* complete any pending frame */
628            handle->picEnd = offset;
629            handle->fieldEncodedCount = 0;
630            BNAV_Indexer_completeFrame( handle );
631            break;
632
633        case SC_EXTENSION:
634            {
635            unsigned char payload0;
636            payload0 = (p_curBfr->startCodeBytes >> 16) & 0xFF;
637            if ((payload0 & 0xF0) == 0x80) { /* extension_start_code_identifier == picture coding extension ID */
638                unsigned char payload2 = (p_curBfr->recordByteCountHi >> 16) & 0xFF;
639                if ((payload2 & 0x3) == 0x1 || (payload2 & 0x3) == 0x2) {
640                    handle->fieldEncodedCount++; /* field */
641                    BDBG_MSG(("field encoded %d", handle->fieldEncodedCount));
642                }
643                else {
644                    handle->fieldEncodedCount = 0; /* frame */
645                }
646            }
647            }
648
649            break;
650
651        case SC_PICTURE:
652            {
653            unsigned pc;
654
655            /* complete any pending frame */
656            handle->picEnd = offset;
657            handle->fieldEncodedCount = 0;
658            BNAV_Indexer_completeFrame( handle );
659
660            /* start a new frame */
661            handle->picStart = offset;
662
663            BNAV_set_frameOffsetLo(navEntry, offset);
664            BNAV_set_frameOffsetHi(navEntry, offsetHi);
665
666            pc = returnPictureCode(p_curBfr->startCodeBytes);
667
668            switch(pc)
669            {
670            case PC_I_FRAME:
671                handle->isISlice = 1;
672                handle->isHits = 0;
673                BNAV_set_frameType(navEntry, eSCTypeIFrame);
674                if (handle->prev_pc == PC_I_FRAME) {
675                    handle->prev_I_rfo = 0;
676                }
677                break;
678            case PC_P_FRAME:
679                handle->prev_I_rfo = 0;
680                /* First P after first I allows open GOP B's to be saved */
681                if (handle->hitFirstISlice) {
682                    handle->allowOpenGopBs = 1;
683                }
684                BNAV_set_frameType(navEntry, eSCTypePFrame);
685                break;
686            case PC_B_FRAME:
687                BNAV_set_frameType(navEntry, eSCTypeBFrame);
688                break;
689            default:
690                BDBG_ERR(("unknown picture_coding_type 0x%x", pc));
691                break;
692            }
693            handle->prev_pc = pc;
694
695            /* make sequence header offset relative to current frame rather than */
696            /* relative to reference frame to allow removal of b-frames */
697            BNAV_set_seqHdrSize(navEntry, (unsigned short)handle->seqHdrSize);
698            BNAV_set_seqHdrStartOffset(navEntry,
699                        BNAV_Indexer_subtractByteCounts(handle->picStart, handle->seqHdrStartOffset));
700
701            /* Sets the refFrameOffset after adding the prev_I_rfo to the rfo.
702            prev_I_rfo will be non-zero ONLY for open gop B's, which are B's that come
703            after an I but before a P. */
704            BNAV_set_refFrameOffset(navEntry, handle->rfo + handle->prev_I_rfo);
705
706            if (handle->settings.navVersion >= BNAV_VersionOpenGopBs) {
707                if (pc == PC_I_FRAME) {
708                    handle->prev_I_rfo = handle->rfo;
709                }
710            }
711
712            if (handle->hitFirstISlice) {
713                handle->rfo++;
714            }
715
716            BNAV_set_framePts(navEntry, handle->next_pts);
717            }
718            break;
719        default:
720            break;
721
722        }
723
724skip:
725        p_curBfr = (const BSCT_Entry*)((char*)p_curBfr + inc);
726    }
727
728    return i;
729}
730
731long BNAV_Indexer_FeedReverse(BNAV_Indexer_Handle handle, const BSCT_Entry *p_bfr, long numEntries)
732{
733    int i,j;
734
735    if (handle->settings.sctVersion == BSCT_Version32bitOffset) {
736        return BERR_TRACE(BERR_NOT_SUPPORTED);
737    }
738
739    for(i=numEntries-1; i>=0; --i)
740    {
741        const BSCT_Entry *curSct = &p_bfr[i];
742        BNAV_Entry *navEntry;
743
744        int sc = returnStartCode(curSct->startCodeBytes); /* parse once */
745
746        BDBG_MSG(("SCT Entry: %02x %d %08x %08x",
747            sc, returnPictureCode(curSct->startCodeBytes), curSct->recordByteCountHi, curSct->recordByteCount));
748
749        /* Set navEntry to the current BNAV_Entry */
750        if (handle->reverse.total_entries)
751            navEntry = &handle->reverse.entry[handle->reverse.total_entries-1];
752        else
753            navEntry = NULL;
754
755        switch(sc)
756        {
757#if 0
758/* No HITS support for OTF PVR. Is this a requirement? */
759        case SC_FIRST_SLICE:
760            /* I-slice check here */
761            if (returnIntraSliceBit(curSct->startCodeBytes) && handle->isHits) {
762                BNAV_set_frameType(navEntry, eSCTypeRPFrame);
763                handle->isISlice = 1;
764            }
765            break;
766        case SC_PES:
767        case SC_SEQ_END:
768            break;
769#endif
770        case SC_PTS:
771            {
772            unsigned long pts = BNAV_Indexer_returnPts(curSct);
773
774            /* Set PTS for all entries that don't have one. */
775            for (j=handle->reverse.total_entries-1;j>=0;j--) {
776                BNAV_Entry *entry = &handle->reverse.entry[j];
777
778                if (BNAV_get_framePts(entry))
779                    break;
780                BNAV_set_framePts(entry, pts);
781            }
782            }
783            break;
784
785        case SC_SEQUENCE:
786            handle->seqHdrStartOffset = BNAV_Indexer_getScByteOffsetLo( handle, curSct );
787            handle->seqHdrSize = handle->picEnd - handle->seqHdrStartOffset;
788
789            /* Go through every entry and set seqhdr offset if not set already */
790            for (j=handle->reverse.total_entries-1;j>=0;j--) {
791                BNAV_Entry *entry = &handle->reverse.entry[j];
792
793                if (BNAV_get_seqHdrStartOffset(entry))
794                    break;
795
796                BNAV_set_seqHdrSize(entry, (unsigned short)handle->seqHdrSize);
797                BNAV_set_seqHdrStartOffset(entry,
798                    BNAV_Indexer_subtractByteCounts(
799                        BNAV_get_frameOffsetLo(entry), handle->seqHdrStartOffset));
800            }
801
802            BNAV_Indexer_Flush(handle);
803            break;
804
805        case SC_PICTURE:
806            {
807            unsigned frameSize, pc;
808            if (!handle->picEnd) {
809                /* If we don't know where this frame ends, we have to skip it. */
810                break;
811            }
812
813            /* Select a new BNAV_Entry */
814            if (handle->reverse.total_entries == MAX_GOP_SIZE) {
815                BDBG_ERR(("MAX_GOP_SIZE exceeded. Bad data resulting."));
816                return -1;
817            }
818            navEntry = &handle->reverse.entry[handle->reverse.total_entries++];
819
820            handle->picStart = BNAV_Indexer_getScByteOffsetLo( handle, curSct );
821            frameSize = BNAV_Indexer_subtractByteCounts(handle->picEnd, handle->picStart);
822            if (frameSize > handle->settings.maxFrameSize) {
823                BDBG_WRN(("Giant frame (%d bytes) detected and rejected: %d", frameSize, handle->totalEntriesWritten));
824                /* Throw away this entry */
825                handle->reverse.total_entries--;
826                continue;
827            }
828
829            BNAV_set_frameOffsetLo(navEntry, handle->picStart);
830            BNAV_set_frameOffsetHi(navEntry, 0); /* BNAV_Indexer_getScByteOffsetHi(handle, curSct)); */
831
832            BNAV_set_frameSize(navEntry, frameSize);
833            BNAV_Indexer_StampEntry(handle, navEntry);
834
835            /* Set this to 0 so that we'll set it when we hit a seqhdr */
836            BNAV_set_seqHdrStartOffset(navEntry, 0);
837            BNAV_set_refFrameOffset(navEntry, 0);
838
839            pc = returnPictureCode(curSct->startCodeBytes);
840
841            switch (pc)
842            {
843            case PC_I_FRAME:
844                BNAV_set_frameType(navEntry, eSCTypeIFrame);
845                break;
846            case PC_P_FRAME:
847                BNAV_set_frameType(navEntry, eSCTypePFrame);
848                break;
849            case PC_B_FRAME:
850                BNAV_set_frameType(navEntry, eSCTypeBFrame);
851                break;
852            default:
853                BDBG_ERR(("unknown picture_coding_type 0x%x", pc));
854                break;
855            }
856
857
858            /* When we hit an I frame, we can set the refoffset for the GOP */
859            if (pc == PC_I_FRAME) {
860                int refoff = 0; /* Offset from I frame */
861                int newgop = 1; /* Set at every I frame */
862                int foundFirstP = 0; /* This is the marker for open GOP B's */
863                for (j=handle->reverse.total_entries-1;j>=0;j--) {
864                    BNAV_Entry *entry = &handle->reverse.entry[j];
865                    int done = 0;
866
867                    switch (BNAV_get_frameType(entry)) {
868                    case eSCTypeBFrame:
869                        /* If this is an open GOP B for the previous frame, skip it. */
870                        if (newgop && !foundFirstP) {
871                            refoff++;
872                            continue;
873                        }
874                        break;
875                    case eSCTypePFrame:
876                        /* If we have a new GOP but we've already found a P, then we're
877                        done setting the open GOP B's for the current reference frame.
878                        We're done. */
879                        /* coverity[dead_error_condition] */
880                        if (newgop && foundFirstP) {
881                            /* coverity[dead_error_begin] */
882                            done = 1;
883                            break;
884                        }
885
886                        /* Once we find a P, we're into the middle of the GOP so don't
887                        skip open GOP B's. */
888                        newgop = 0;
889                        foundFirstP = 1;
890                        break;
891                    case eSCTypeIFrame:
892                        newgop = 1;
893                        break;
894                    default:
895                        BDBG_ERR(("Only GOP-based streams supported."));
896                        return -1;
897                    }
898
899                    /* coverity[dead_error_condition] */
900                    if (done)
901                        /* coverity[dead_error_line] */
902                        break;
903
904                    BNAV_set_refFrameOffset(entry, refoff);
905                    refoff++;
906                }
907
908                /* And now we can flush */
909                BNAV_Indexer_Flush(handle);
910            }
911            }
912            break;
913
914        default:
915            break;
916        }
917
918        if (sc != SC_PES && sc != SC_PTS && sc != SC_EXTENSION && sc != SC_FIRST_SLICE)
919        {
920            handle->picEnd = BNAV_Indexer_getScByteOffsetLo( handle, curSct);
921            BDBG_MSG(("Set picEnd %lx, %d", handle->picEnd,sc));
922        }
923    }
924
925    return numEntries;
926}
927
928#define BNAV_LARGE_TIME_GAP 3000 /* 3000 msec = 3 seconds */
929
930/**
931Set timestamp and vchip stamps for an entry based on current bcmindexer and system state.
932**/
933static void BNAV_Indexer_StampEntry(BNAV_Indexer_Handle handle, BNAV_Entry *entry)
934{
935    if (handle->settings.simulatedFrameRate) {
936        /* calc a timestamp based on a simulated frame rate. actual system time is irrevelevant. */
937        BNAV_set_timestamp(entry, handle->starttime++ * (1000/handle->settings.simulatedFrameRate));
938    }
939    else if (handle->settings.ptsBasedFrameRate) {
940        unsigned currenttime;
941        int frameType = BNAV_get_frameType(entry);
942
943        /* ignore B frames. this algo converts from decode-order PTS to guaranteed-increasing timestamp. the easiest way is to
944        ignore where decode order varies from display order, and that's by counting over B frames. */
945
946        if (frameType != eSCTypeBFrame && (handle->next_pts < handle->ptsBasedFrameRate.lastPts || handle->next_pts > handle->ptsBasedFrameRate.lastPts + 10*45000)) {
947            /* get across the pts discontinuity. don't change the rate and don't accumulate frameCount. just advance the lastPts.
948            allow for infrequently coded PTS's, but bound it to 10 seconds. */
949            handle->ptsBasedFrameRate.lastPts = handle->next_pts;
950            handle->ptsBasedFrameRate.frameCount = 1;
951        }
952        else if (frameType != eSCTypeBFrame && handle->next_pts > handle->ptsBasedFrameRate.lastPts) {
953            unsigned old_rate = handle->ptsBasedFrameRate.rate;
954
955            /* calc rate between PTS's */
956            if (++handle->ptsBasedFrameRate.frameCount) {
957                unsigned ptsDiff = handle->next_pts - handle->ptsBasedFrameRate.lastPts;
958#if 0
959                /* set the new rate immediately */
960                handle->ptsBasedFrameRate.rate = ptsDiff / handle->ptsBasedFrameRate.frameCount;
961#else
962                int targetRate = ptsDiff / handle->ptsBasedFrameRate.frameCount;
963                int rateDiff = targetRate - (int)handle->ptsBasedFrameRate.rate;
964                /* don't just assign the rate. approach it. this provides some smoothing effect. */
965                if (rateDiff > 4) rateDiff /= 4;
966                handle->ptsBasedFrameRate.rate += rateDiff;
967#endif
968            }
969
970            BSTD_UNUSED(old_rate); /* if BDBG_MSG_TRACE is undefined */
971            BDBG_MSG_TRACE(("set rate: from PTS %08x -> %08x, from rate %d -> %d, %d frames",
972                handle->ptsBasedFrameRate.lastPts, handle->next_pts,
973                old_rate, handle->ptsBasedFrameRate.rate,
974                handle->ptsBasedFrameRate.frameCount));
975
976            /* "/ 45" converts from 45KHz PTS units to 1000 msec timestamp units */
977            handle->lasttime += (handle->ptsBasedFrameRate.frameCount * handle->ptsBasedFrameRate.rate) / 45;
978
979            /* reset to measure between next PTS's */
980            handle->ptsBasedFrameRate.lastPts = handle->next_pts;
981            handle->ptsBasedFrameRate.frameCount = 0;
982        }
983        else {
984            /* no new pts or B frame means we keep the rate but just count pictures */
985            handle->ptsBasedFrameRate.frameCount++;
986
987        }
988
989        /* set a minimum rate of 15 msec/frame in case something gets out of whack */
990        if (handle->ptsBasedFrameRate.rate < 15 * 45) {
991            handle->ptsBasedFrameRate.rate = 15 * 45;
992        }
993
994        currenttime = handle->lasttime + (handle->ptsBasedFrameRate.frameCount * handle->ptsBasedFrameRate.rate) / 45;
995
996        BNAV_set_timestamp(entry, currenttime);
997    }
998    else {
999        unsigned currenttime = currentTimestamp();
1000
1001        /* provide a minimal safe increment so that timestamps can be unique and guaranteed increasing. */
1002        if (currenttime <= (unsigned)handle->lasttime) {
1003            currenttime = handle->lasttime + 15; /* 15 msec increment is less than 60 fps (16.6 msec), so we shouldn't get ahead of real timestamps */
1004        }
1005
1006        /* Any large jump in timestamps can only be caused by the source disappearing because of loss of signal, etc.
1007        The timestamps should skip over this gap. */
1008        if (!handle->settings.allowLargeTimeGaps && currenttime - handle->lasttime > BNAV_LARGE_TIME_GAP) {
1009            handle->starttime += (currenttime - handle->lasttime) - 30; /* turn any large gap into a 30 millisecond gap by adjusting the starttime */
1010        }
1011        BNAV_set_timestamp(entry, currenttime - handle->starttime + handle->settings.append.timestamp);
1012        handle->lasttime = currenttime;
1013    }
1014    BNAV_set_packed_vchip(entry, handle->vchip);
1015    BNAV_set_version(entry, handle->settings.navVersion);
1016}
1017
1018/* For FeedReverse only. Write out BNAV_Entry's which have a seqhdr and refoffset. */
1019static int BNAV_Indexer_Flush(BNAV_Indexer_Handle handle)
1020{
1021    int i;
1022    BDBG_MSG(("flush total %d", handle->reverse.total_entries));
1023    for (i=0;i<handle->reverse.total_entries; i++) {
1024        BNAV_Entry *entry = &handle->reverse.entry[i];
1025
1026        BDBG_MSG(("  %ld, %d, %d",
1027            BNAV_get_seqHdrStartOffset(entry),
1028            BNAV_get_refFrameOffset(entry),
1029            BNAV_get_frameType(entry)
1030            ));
1031
1032        if (BNAV_get_seqHdrStartOffset(entry) && BNAV_get_refFrameOffset(entry))
1033        {
1034           /* write using callback */
1035            int numBytes = (*handle->settings.writeCallback)(entry, 1,
1036                sizeof( BNAV_Entry ), handle->settings.filePointer);
1037            if (numBytes != sizeof( BNAV_Entry )) {
1038                BDBG_ERR(("Unable to write index entry."));
1039                return -1;
1040            }
1041            handle->totalEntriesWritten++;
1042            handle->lastEntryWritten = *entry;
1043        }
1044        else {
1045            /* When we hit the first entry we can't send, break out */
1046            break;
1047        }
1048    }
1049
1050    /* Shift forward the entry array based on how many were sent */
1051    handle->reverse.total_entries -= i;
1052    memmove(handle->reverse.entry, &handle->reverse.entry[i],
1053        handle->reverse.total_entries * sizeof(BNAV_Entry));
1054
1055    return 0;
1056}
1057
1058static int BNAV_P_CheckEntry(BNAV_Indexer_Handle handle, BNAV_Entry *navEntry)
1059{
1060    unsigned long frameSize = BNAV_get_frameSize(navEntry);
1061    int frameType = BNAV_get_frameType(navEntry);
1062
1063    if (frameSize > handle->settings.maxFrameSize) {
1064        BDBG_WRN(("Giant frame (%ld bytes) detected and rejected: %d", frameSize, handle->totalEntriesWritten));
1065        /* discard everything until next I frame */
1066        handle->hitFirstISlice = 0;
1067        handle->rfo = 0;
1068        handle->isISlice = 0;
1069        handle->prev_I_rfo = 0;
1070        handle->prev_pc = 0;
1071        handle->allowOpenGopBs = 0; /* including open GOP B's after that first I */
1072        goto fail;
1073    }
1074    else if (frameSize == 0) {
1075        BDBG_ERR(("Invalid frame size 0 rejected, probably corrupt index at %d", handle->totalEntriesWritten));
1076        goto fail;
1077    }
1078    else if (BNAV_get_seqHdrSize(navEntry) == 0) {
1079        BDBG_MSG(("Discarding picture with no sequence header"));
1080        goto fail;
1081    }
1082
1083    /* Skip dangling open GOP B's */
1084    if (frameType == eSCTypeBFrame && handle->hitFirstISlice && !handle->allowOpenGopBs &&
1085        handle->settings.navVersion != BNAV_Version_AVC &&
1086        handle->settings.navVersion != BNAV_Version_VC1_PES &&
1087        handle->settings.navVersion != BNAV_Version_AVS)
1088    {
1089        BDBG_MSG(("Discarding dangling open GOP B: %d", handle->totalEntriesWritten));
1090        handle->rfo--;
1091        goto fail;
1092    }
1093
1094    /* success */
1095    return 0;
1096
1097fail:
1098    BNAV_set_frameType(navEntry, eSCTypeUnknown);
1099    return -1;
1100}
1101
1102
1103/* Write a MPEG2 or AVC entry back to the write callback. */
1104int BNAV_Indexer_completeFrameAux(BNAV_Indexer_Handle handle, void *data, int size)
1105{
1106    BNAV_Entry *navEntry = (BNAV_Entry *)data;
1107    unsigned long frameSize = BNAV_Indexer_subtractByteCounts( handle->picEnd, BNAV_get_frameOffsetLo(navEntry));
1108    int frameType = BNAV_get_frameType(navEntry);
1109
1110    BNAV_set_frameSize(navEntry,frameSize);
1111
1112    /* perform sanity check before writing */
1113    if (BNAV_P_CheckEntry(handle, navEntry))
1114    {
1115        return -1;
1116    }
1117
1118
1119    if (handle->isISlice)
1120        handle->hitFirstISlice = 1;
1121
1122    if (frameType != eSCTypeUnknown && handle->hitFirstISlice)
1123    {
1124        int numBytes;
1125        BNAV_Indexer_StampEntry(handle, navEntry);
1126
1127        BDBG_MSG(("Output: %08x %08x %08x %08x %08x %08x (%s)", navEntry->words[0], navEntry->words[1],
1128            navEntry->words[2], navEntry->words[3], navEntry->words[4], navEntry->words[5],
1129            BNAV_frameTypeStr[frameType]));
1130
1131        /* write using callback */
1132        numBytes = (*handle->settings.writeCallback)(navEntry, 1, size, handle->settings.filePointer);
1133        if (numBytes != size) {
1134            BDBG_ERR(("Unable to write index entry."));
1135            return -1;
1136        }
1137        handle->totalEntriesWritten++;
1138        handle->lastEntryWritten = *navEntry;
1139    }
1140    /**
1141    * Clear the frametype, but don't clear the rest of the information. If
1142    * in the future the rest of the information must be cleared, watchout so that
1143    * BNAV_Indexer_GetPosition isn't broken.
1144    **/
1145    BNAV_set_frameType(navEntry, eSCTypeUnknown);
1146
1147    if(handle->isISlice)
1148    {
1149        handle->rfo = 1;
1150        handle->isISlice = 0;
1151    }
1152    handle->picEnd = 0;
1153
1154    return 0;
1155}
1156
1157/* Write completed MPEG2 entry to write callback. */
1158static int BNAV_Indexer_completeFrame(BNAV_Indexer_Handle handle)
1159{
1160    return BNAV_Indexer_completeFrameAux(handle, &handle->curEntry, sizeof(handle->curEntry));
1161}
1162/* Write completed AVC entry to write callback. */
1163static int BNAV_Indexer_completeAVCFrame(BNAV_Indexer_Handle handle)
1164{
1165    BNAV_AVC_Entry *avcEntry = &handle->avcEntry;
1166
1167    /* We're going to change the definition of P and B frame for AVC. For MPEG2, a B picture has two
1168    properties: it uses bidirectional prediction (forward and backward in display order, always backward in decode order)
1169    and it is not predicted against. The player only uses the second property. It can drop a B frame.
1170    For AVC, a B picture is has the first property but not the second. At this point, it's unclear if the player
1171    can use the B directional property for any trick mode (especially if not stored at a slice level).
1172    Therefore, for the NAV table AVC indexes, the definition of "B frame" will be "non-I frame which is not
1173    a referenced picture." This means B frames will have the second property - they are discardable. */
1174    if (BNAV_get_frameType(avcEntry) == eSCTypeBFrame) {
1175        if (handle->avc.is_reference_picture) {
1176            BDBG_MSG(("We have a reference B frame"));
1177            BNAV_set_frameType(avcEntry, eSCTypePFrame);
1178        }
1179    }
1180    else if (BNAV_get_frameType(avcEntry) == eSCTypePFrame) {
1181        if (!handle->avc.is_reference_picture) {
1182            BDBG_MSG(("We have a non-reference P frame"));
1183            BNAV_set_frameType(avcEntry, eSCTypeBFrame);
1184        }
1185    }
1186
1187    return BNAV_Indexer_completeFrameAux(handle, &handle->avcEntry, sizeof(handle->avcEntry));
1188}
1189
1190static int BNAV_Indexer_completeTimestampFrame(BNAV_Indexer_Handle handle)
1191{
1192    BNAV_Entry *navEntry = &handle->curEntry;
1193    unsigned size = sizeof(handle->curEntry);
1194    int numBytes;
1195
1196    BNAV_Indexer_StampEntry(handle, navEntry);
1197
1198    BDBG_MSG(("Output: %08x %08x %08x %08x %08x %08x", navEntry->words[0], navEntry->words[1],
1199        navEntry->words[2], navEntry->words[3], navEntry->words[4], navEntry->words[5]));
1200
1201    /* write using callback */
1202    numBytes = (*handle->settings.writeCallback)(navEntry, 1, size, handle->settings.filePointer);
1203    if (numBytes != (int)size) {
1204        BDBG_ERR(("Unable to write index entry."));
1205        return -1;
1206    }
1207    handle->totalEntriesWritten++;
1208    handle->lastEntryWritten = *navEntry;
1209
1210    return 0;
1211}
1212
1213/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1214+ INPUTS:   p_sct = pointer to sct entry
1215+ OUTPUTS:  None.
1216+ RETURNS:  pts value (bits [32:1]
1217+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
1218unsigned long BNAV_Indexer_returnPts(const BSCT_Entry *p_sct )
1219{
1220    return p_sct->recordByteCountHi;
1221}
1222
1223/******************************************************************************
1224* INPUTS:   p_entry = pointer to a start code entry
1225* OUTPUTS:  None.
1226* RETURNS:  Lower 32 bits of the start code byte offset.
1227* FUNCTION: This function returns the lower 32 bits of of the number obtained
1228*           by adding the byte offset of the packet to the offset within the
1229*           packet of the start code.
1230******************************************************************************/
1231unsigned long BNAV_Indexer_getScByteOffsetLo(BNAV_Indexer_Handle handle, const BSCT_Entry *p_entry)
1232{
1233    unsigned long byteOffset;
1234
1235    byteOffset = p_entry->recordByteCount + (p_entry->startCodeBytes & 0xff);
1236    if (handle->settings.transportTimestampEnabled)
1237        byteOffset += 4;
1238
1239    return byteOffset;
1240}
1241
1242/******************************************************************************
1243* INPUTS:   p_entry = pointer to a start code entry
1244* OUTPUTS:  None.
1245* RETURNS:  most significant 8 bites of the 40 bit offset, shifted into lower 8 bits
1246* FUNCTION: This function takes into account the start code offset and possible timestamp and increments the Hi once
1247*
1248******************************************************************************/
1249unsigned long BNAV_Indexer_getScByteOffsetHi(BNAV_Indexer_Handle handle, const BSCT_Entry *p_entry )
1250{
1251    unsigned long byteOffset;
1252
1253    /* Offset into transport packet may cause 32 bit overflow. */
1254    byteOffset = p_entry->recordByteCount + (p_entry->startCodeBytes & 0xff);
1255    if (handle->settings.transportTimestampEnabled)
1256        byteOffset += 4;
1257    if (byteOffset < p_entry->recordByteCount)
1258    {
1259        return (p_entry->recordByteCountHi>>24) + 1;
1260    }
1261    else
1262    {
1263        return p_entry->recordByteCountHi>>24;
1264    }
1265}
1266
1267/******************************************************************************
1268* INPUTS:   largerNum - Number to subtract from.
1269*           smallerNum - Number to be subtracted.
1270* OUTPUTS:  None.
1271* RETURNS:  Difference between 2 numbers.
1272* FUNCTION: This function subtracts largerNum from smallerNum.  It assumes that
1273*           largerNum is larger and if not, it must have wrapped.
1274*           This function is used for calculating the difference between 64-bit
1275*           byte counts using only 32-bit numbers and assuming that the
1276*           difference between the two number can be contained in a 32-bit
1277*           unsigned integer.
1278******************************************************************************/
1279unsigned long BNAV_Indexer_subtractByteCounts( unsigned long largerNum, unsigned long smallerNum )
1280{
1281    if (largerNum >= smallerNum)
1282    {
1283        return largerNum - smallerNum;
1284    }
1285    else
1286    {
1287        return (0 - smallerNum) + largerNum;
1288    }
1289}
1290
1291const char * const BNAV_frameTypeStr[] = {
1292    "Seq",  /* eSCTypeSeqHdr    Sequence header */
1293    "I",    /* eSCTypeIFrame    I-frame */
1294    "P",    /* eSCTypePFrame    P-frame */
1295    "B",    /* eSCTypeBFrame    B-frame */
1296    "GOP",  /* eSCTypeGOPHdr    GOP header */
1297    "RP",   /* eSCTypeRPFrame   Reference picture frame */
1298    "Unk",  /* eSCTypeUnknown   Unknown or "don't care" frame type */
1299    0
1300};
1301
1302int BNAV_Indexer_IsHits(BNAV_Indexer_Handle handle) {
1303    return handle->isHits;
1304}
1305
1306int BNAV_Indexer_SetVChipState(BNAV_Indexer_Handle handle, unsigned short vchipState)
1307{
1308    return BNAV_pack_vchip(vchipState, &handle->vchip);
1309}
1310
1311unsigned short BNAV_Indexer_GetVChipState(BNAV_Indexer_Handle handle)
1312{
1313    return BNAV_unpack_vchip(handle->vchip);
1314}
1315
1316unsigned short BNAV_unpack_vchip(unsigned short packed_vchip)
1317{
1318    /* unpack from 12 bits */
1319    packed_vchip = ((packed_vchip << 2) & 0x3f00) | (packed_vchip & 0x003f);
1320    /* reset the 1 bits & return */
1321    return packed_vchip | 0x4040;
1322}
1323
1324int BNAV_pack_vchip(unsigned short unpacked_vchip, unsigned short *packed_vchip)
1325{
1326    /* test the 1 bit in each byte */
1327    if ((unpacked_vchip & 0x4040) != 0x4040) {
1328        BDBG_ERR(("Invalid vchip value: 0x%04x", unpacked_vchip));
1329        return -1;
1330    }
1331    /* pack into 12 bits */
1332    *packed_vchip = ((unpacked_vchip & 0x3f00)>>2) | (unpacked_vchip & 0x003f);
1333    return 0;
1334}
1335
1336int BNAV_Indexer_GetPosition(BNAV_Indexer_Handle handle, BNAV_Indexer_Position *position)
1337{
1338    if (!handle->totalEntriesWritten)
1339        return -1;
1340    else {
1341        BNAV_Entry *p_entry = &handle->lastEntryWritten;
1342        position->index = handle->totalEntriesWritten-1;
1343        position->pts = BNAV_get_framePts(p_entry);
1344        position->offsetHi = BNAV_get_frameOffsetHi(p_entry);
1345        position->offsetLo = BNAV_get_frameOffsetLo(p_entry);
1346        position->timestamp = BNAV_get_timestamp(p_entry);
1347        position->vchipState = BNAV_unpack_vchip(BNAV_get_packed_vchip(p_entry));
1348        return 0;
1349    }
1350}
1351
1352static int b_check_for_start_code(unsigned char data, int sccount)
1353{
1354    switch (data) {
1355    case 0:
1356        if (sccount >= 1)
1357            sccount = 2;
1358        else
1359            sccount = 1;
1360        break;
1361    case 1:
1362        if (sccount == 2) {
1363            /* we've got a start code! */
1364            sccount = 3;
1365        }
1366        else {
1367            sccount = 0;
1368        }
1369        break;
1370    default:
1371        sccount = 0;
1372        break;
1373    }
1374    return sccount;
1375}
1376
1377/*
1378BNAV_Indexer_P_ProcessFullPacketForFeedAvc takes a TS packet and generates SCT entries, just like the SCD hardware.
1379It must generate 3 SCT types: RAI, start code, PTS.
1380*/
1381static void BNAV_Indexer_P_ProcessFullPacketForFeedAvc(BNAV_Indexer_Handle handle)
1382{
1383    unsigned offset = 0;
1384    uint8_t *pkt = handle->fullPacket;
1385    uint8_t *payload = NULL;
1386    BSCT_SixWord_Entry sct;
1387    unsigned sccount = 0;
1388    unsigned startCodeOffset = 0;
1389    unsigned sctCount = 0;
1390
1391    BDBG_MSG_TRACE(("BNAV_Indexer_P_ProcessFullPacketForFeedAvc"));
1392#if 0
1393    {
1394        unsigned i;
1395        for (i=0;i<BCMINDEXER_TS_PACKET_SIZE;i++)
1396            BKNI_Printf("%02x", pkt[i]);
1397        BKNI_Printf("\n");
1398    }
1399#endif
1400
1401    BKNI_Memset(&sct, 0, sizeof(sct));
1402
1403    /* read adaptation field, then skip TS header */
1404    if (pkt[3] & 0x20) {
1405        /* check for RAI */
1406        sct.word0 = 0x01 << 24; /* TPIT */
1407        sct.startCodeBytes = 0x20; /* RAI set */
1408        BDBG_MSG_TRACE(("  sending RAI SCT"));
1409        if (++sctCount > 10) {
1410            BNAV_Indexer_FeedAVC(handle, &sct, 1);
1411        }
1412        BKNI_Memset(&sct, 0, sizeof(sct));
1413
1414        /* skip over adaptation field length */
1415        offset += pkt[4] + 1; /* then add the adaptation_field_length and 1 for the length field itself */
1416    }
1417
1418    /* Find start codes and build SCT packets.
1419    The loop test is "<=" so that we can process any remainder. */
1420    for (;offset<=BCMINDEXER_TS_PACKET_SIZE;offset++) {
1421        if (sccount == 3 || offset == BCMINDEXER_TS_PACKET_SIZE) {
1422            /* pkt[offset] is a start code */
1423            if (payload) {
1424                unsigned payloadAvailable = BCMINDEXER_TS_PACKET_SIZE - (payload - pkt);
1425
1426                /* now we can finish out previous SCT. note that payload[] may extend past the next start code. this is how
1427                the SCD HW works as well. */
1428                if (payloadAvailable > 0) {
1429                    sct.startCodeBytes |= payload[0] << 16;
1430                }
1431                if (payloadAvailable > 1) {
1432                    sct.startCodeBytes |= payload[1] << 8;
1433                }
1434                if (payloadAvailable > 2) {
1435                    sct.recordByteCountHi |= payload[2] << 16;
1436                }
1437                if (payloadAvailable > 3) {
1438                    sct.recordByteCountHi |= payload[3] << 8;
1439                }
1440                if (payloadAvailable > 4) {
1441                    sct.recordByteCountHi |= payload[4];
1442                }
1443                if (payloadAvailable > 5) {
1444                    sct.flags |= payload[5] << 16;
1445                }
1446                if (payloadAvailable > 6) {
1447                    sct.flags |= payload[6] << 8;
1448                }
1449                if (payloadAvailable > 7) {
1450                    sct.flags |= payload[7];
1451                }
1452
1453                /* set offset */
1454                sct.startCodeBytes |= startCodeOffset; /* byte offset from the start of the packet to the start code */
1455                sct.recordByteCount = handle->lastPacketOffset.offset; /* lower 32 bits of packet offset */
1456                sct.recordByteCountHi |= handle->lastPacketOffset.offsetHi << 24; /* upper 8 bits of packet offset */
1457
1458                BDBG_MSG_TRACE(("  sending SC SCT"));
1459                if (++sctCount > 10) {
1460                    BNAV_Indexer_FeedAVC(handle, &sct, 1);
1461                }
1462
1463                /* PTS is a special case */
1464                if (sct.startCodeBytes >> 24 == 0xE0 && payloadAvailable > 4 /* TODO: however many bytes are required from PES header */) {
1465                    BKNI_Memset(&sct, 0, sizeof(sct));
1466                    sct.startCodeBytes = 0xFE << 24;
1467                    sct.recordByteCountHi = 0xdeadbeef; /* TODO: parse PTS from PES header. I'm not doing this now because the chances
1468                    are very high it will occur within the first 10 ITB's for a packet */
1469                    BDBG_MSG_TRACE(("  sending PTS SCT"));
1470                    if (++sctCount > 10) {
1471                        BNAV_Indexer_FeedAVC(handle, &sct, 1);
1472                    }
1473                }
1474                BKNI_Memset(&sct, 0, sizeof(sct));
1475                payload = NULL;
1476            }
1477            if (offset == BCMINDEXER_TS_PACKET_SIZE) {
1478                /* this was the remainder. there is no next startcode. */
1479                break;
1480            }
1481
1482            /* store start code and start of payload */
1483            startCodeOffset = offset;
1484            sct.startCodeBytes = pkt[offset] << 24;
1485            payload = &pkt[offset+1];
1486            sccount = 0;
1487        }
1488
1489        sccount = b_check_for_start_code(pkt[offset], sccount);
1490    }
1491    BDBG_ASSERT(!payload); /* no pending SC */
1492}
1493
1494static long
1495BNAV_Indexer_FeedAVC(BNAV_Indexer_Handle handle, const void *p_bfr, long numEntries)
1496{
1497    long i;
1498    const BSCT_SixWord_Entry *p_curBfr;
1499    BNAV_AVC_Entry *avcEntry = &handle->avcEntry;
1500
1501    if (handle->settings.sctVersion != BSCT_Version6wordEntry) {
1502        BDBG_ERR(("Must use 6 word SCT's for AVC content"));
1503        return -1;
1504    }
1505    /* no AVC hits */
1506    handle->isHits = 0;
1507
1508    p_curBfr = (const BSCT_SixWord_Entry *)p_bfr;
1509
1510    for(i=0; i<numEntries; i++, p_curBfr++)
1511    {
1512        unsigned char sc = returnStartCode(p_curBfr->startCodeBytes); /* parse once */
1513        unsigned long offset, offsetHi;
1514        unsigned nal_unit_type;
1515        unsigned nal_ref_idc;
1516#define TOTAL_PAYLOAD 8
1517        unsigned char payload[TOTAL_PAYLOAD];
1518        unsigned index = 0, bit = 7;
1519        BSCT_Entry *p_curSct4 = CONVERT_TO_SCT4(p_curBfr);
1520
1521        BDBG_MSG_TRACE(("SCT %08x %08x %08x %08x %08x %08x",
1522            ((uint32_t*)p_curBfr)[0],
1523            ((uint32_t*)p_curBfr)[1],
1524            ((uint32_t*)p_curBfr)[2],
1525            ((uint32_t*)p_curBfr)[3],
1526            ((uint32_t*)p_curBfr)[4],
1527            ((uint32_t*)p_curBfr)[5]));
1528
1529        /* Check for TPIT Entry to extract RAI. discard all other TPIT entries. */
1530        if ((p_curBfr->word0>>24) == 1)
1531        {
1532            if ((p_curBfr->startCodeBytes & 0x20)>>5)
1533            {
1534                handle->random_access_indicator = true;
1535            }
1536            continue;
1537        }
1538
1539        /* Check for "full packet" entry. See bcmindexerpriv.h for comment. */
1540        if((p_curBfr->word0>>24) == 0x80){
1541            unsigned fullPacketOffset;
1542            switch (handle->fullPacketCount) {
1543            case 0:
1544                fullPacketOffset = 0;
1545                BKNI_Memcpy(&handle->fullPacket[fullPacketOffset], &((uint32_t*)p_curBfr)[2], sizeof(uint32_t) * 4);
1546                break;
1547            default: /* 1..8 */
1548                fullPacketOffset = 4 + 5*(handle->fullPacketCount-1);
1549                fullPacketOffset *= sizeof(uint32_t);
1550                BKNI_Memcpy(&handle->fullPacket[fullPacketOffset], &((uint32_t*)p_curBfr)[1], sizeof(uint32_t) * 5);
1551                break;
1552            case 9:
1553                fullPacketOffset = 4 + 5*(handle->fullPacketCount-1);
1554                fullPacketOffset *= sizeof(uint32_t);
1555                BKNI_Memcpy(&handle->fullPacket[fullPacketOffset], &((uint32_t*)p_curBfr)[1], sizeof(uint32_t) * 3);
1556                break;
1557            }
1558            if (++handle->fullPacketCount == 10) {
1559                unsigned i;
1560#if BSTD_CPU_ENDIAN == BSTD_ENDIAN_LITTLE
1561                /* byteswap */
1562                for (i=0;i<BCMINDEXER_TS_PACKET_SIZE;i+=4) {
1563                    uint8_t temp;
1564                    temp = handle->fullPacket[i+0];
1565                    handle->fullPacket[i+0] = handle->fullPacket[i+3];
1566                    handle->fullPacket[i+3] = temp;
1567
1568                    temp = handle->fullPacket[i+1];
1569                    handle->fullPacket[i+1] = handle->fullPacket[i+2];
1570                    handle->fullPacket[i+2] = temp;
1571                }
1572#endif
1573
1574                /* process the full packet. this will result in recursion into this function. */
1575                BNAV_Indexer_P_ProcessFullPacketForFeedAvc(handle);
1576                handle->fullPacketCount = 0;
1577            }
1578
1579            /* this SCT has been consumed */
1580            continue;
1581        }
1582        else {
1583            /* discard anything in the fullPacket buffer */
1584            handle->fullPacketCount = 0;
1585        }
1586
1587        /* Grab the PTS */
1588        if (sc == 0xfe) {
1589            handle->next_pts = BNAV_Indexer_returnPts(p_curSct4);
1590            BDBG_MSG_TRACE(("PTS %08lx", handle->next_pts));
1591            continue;
1592        }
1593        if (sc & 0x80) {
1594            /* if forbidden_zero_bit is set, this is not an AVC start code */
1595            continue;
1596        }
1597
1598        offset = BNAV_Indexer_getScByteOffsetLo( handle, p_curSct4 );
1599        offsetHi = BNAV_Indexer_getScByteOffsetHi(handle, p_curSct4);
1600
1601        handle->lastPacketOffset.offset = p_curSct4->recordByteCount;
1602        handle->lastPacketOffset.offsetHi = p_curSct4->recordByteCountHi >> 24;
1603
1604        BNAV_Indexer_P_AddAppend(handle, &offsetHi, &offset);
1605
1606        VALIDATE_AVC_SC(p_curSct4,sc);
1607
1608        BDBG_MSG(("sc %02x at %#lx", sc, offset));
1609        nal_ref_idc = (sc >> 5) & 0x3;
1610        nal_unit_type = sc & 0x1F;
1611
1612        /* extract 8 bytes of payload from BSCT_SixWord_Entry fields. see RDB for documentation on this. */
1613        payload[0] = (p_curBfr->startCodeBytes >> 16) & 0xFF;
1614        payload[1] = (p_curBfr->startCodeBytes >> 8) & 0xFF;
1615        payload[2] = (p_curBfr->recordByteCountHi >> 16) & 0xFF;
1616        payload[3] = (p_curBfr->recordByteCountHi >> 8) & 0xFF;
1617        payload[4] = p_curBfr->recordByteCountHi & 0xFF;
1618        payload[5] = (p_curBfr->flags >> 16) & 0xFF;
1619        payload[6] = (p_curBfr->flags >> 8) & 0xFF;
1620        payload[7] = p_curBfr->flags & 0xFF;
1621
1622        BDBG_MSG(("payload %02x%02x%02x%02x%02x%02x%02x%02x",
1623            payload[0],payload[1],payload[2],payload[3],payload[4],payload[5],payload[6],payload[7]));
1624
1625        /* complete pending PPS or SPS because we've hit the next NAL */
1626        if (handle->avc.current_pps >= 0) {
1627            /* complete the PPS */
1628            int id = handle->avc.current_pps;
1629            handle->avc.pps[id].size = BNAV_Indexer_subtractByteCounts(
1630                offset, handle->avc.pps[id].offset);
1631            handle->avc.current_pps = -1;
1632        }
1633        else if (handle->avc.current_sps >= 0) {
1634            /* complete the SPS */
1635            int id = handle->avc.current_sps;
1636            handle->avc.sps[id].size = BNAV_Indexer_subtractByteCounts(
1637                offset, handle->avc.sps[id].offset);
1638            handle->avc.current_sps = -1;
1639        }
1640
1641        /* We must call BNAV_Indexer_completeAVCFrame UNLESS we have IDR/non-IDR slice
1642        with first_mb_in_slice != 0. So handle all the "other" cases in one spot. */
1643        if (nal_unit_type != 1 && nal_unit_type != 5) {
1644            handle->picEnd = offset;
1645            if (BNAV_get_frameType(avcEntry) == eSCTypeIFrame)
1646                handle->prev_I_rfo = handle->rfo;
1647            BNAV_Indexer_completeAVCFrame( handle );
1648        }
1649
1650        /* if SEI and preceding was not an SEI, remember this offset for start point of next PPS, SPS or picture */
1651        if (nal_unit_type == 6 && !handle->avc.current_sei_valid) {
1652            handle->avc.current_sei_valid = true;
1653            handle->avc.current_sei = offset;
1654        }
1655
1656        switch (nal_unit_type) {
1657        case 1: /* non-IDR slice */
1658        case 5: /* IDR slice */
1659            {
1660            unsigned first_mb_in_slice, slice_type, pic_parameter_set_id;
1661            unsigned sps_id;
1662
1663            /* vlc decode the payload */
1664            first_mb_in_slice = b_vlc_decode(payload, TOTAL_PAYLOAD, index, bit, &index, &bit);
1665            slice_type = b_vlc_decode(payload, TOTAL_PAYLOAD, index, bit, &index, &bit);
1666            pic_parameter_set_id = b_vlc_decode(payload, TOTAL_PAYLOAD, index, bit, &index, &bit);
1667
1668            /* check the pps. anything above this is an invalid AVC stream. */
1669            if (pic_parameter_set_id >= TOTAL_PPS_ID) {
1670                BDBG_ERR(("pic_parameter_set_id %d", pic_parameter_set_id));
1671                return -1;
1672            }
1673            /* check the sps right away. if we use a PPS without receiving it's SPS first, we should discard. */
1674            sps_id = handle->avc.pps[pic_parameter_set_id].sps_id;
1675            if (sps_id >= TOTAL_SPS_ID) {
1676                BDBG_ERR(("seq_parameter_set_id %d from pps %d", sps_id, pic_parameter_set_id));
1677                return -1;
1678            }
1679
1680            BDBG_MSG(("%s slice: mb=%-4d type=%-2d pps=%-3d offset=%#lx",
1681                (nal_unit_type==1)?"non-IDR":"IDR", first_mb_in_slice, slice_type, pic_parameter_set_id, offset));
1682
1683            if (first_mb_in_slice == 0) {
1684                /* we have the beginning of a new frame. first, complete the previous frame. */
1685                handle->picEnd = offset;
1686                if (BNAV_get_frameType(avcEntry) == eSCTypeIFrame)
1687                    handle->prev_I_rfo = handle->rfo;
1688                BNAV_Indexer_completeAVCFrame( handle );
1689
1690                /* start the next frame */
1691                handle->picStart = handle->avc.current_sei_valid?handle->avc.current_sei:offset; /* start with preceding SEI's if present */
1692
1693                BNAV_set_frameOffsetLo(avcEntry, handle->picStart);
1694                BNAV_set_frameOffsetHi(avcEntry, offsetHi);
1695
1696                /* default to I frame until P or B slices indicate differently */
1697                BNAV_set_frameType(avcEntry, eSCTypeIFrame);
1698                handle->isISlice = 1;
1699                handle->avc.is_reference_picture = 0;
1700
1701                /* Set PPS and SPS */
1702                BNAV_set_seqHdrStartOffset(avcEntry,
1703                    BNAV_Indexer_subtractByteCounts(handle->picStart, handle->avc.pps[pic_parameter_set_id].offset));
1704                BNAV_set_seqHdrSize(avcEntry,
1705                    handle->avc.pps[pic_parameter_set_id].size);
1706                BNAV_set_SPS_Offset(avcEntry,
1707                    BNAV_Indexer_subtractByteCounts(handle->picStart, handle->avc.sps[sps_id].offset));
1708                BNAV_set_SPS_Size(avcEntry,
1709                    handle->avc.sps[sps_id].size);
1710
1711                BDBG_MSG(("sps %d: %#lx, %ld", sps_id, BNAV_get_SPS_Offset(avcEntry), BNAV_get_SPS_Size(avcEntry)));
1712
1713                /* check for P slice, which means it's not a B frame */
1714                if (slice_type == 0 || slice_type == 5) {
1715                    handle->prev_I_rfo = 0;
1716                    /* First P after first I allows open GOP B's to be saved */
1717                    if (handle->hitFirstISlice)
1718                        handle->allowOpenGopBs = 1;
1719                }
1720
1721                /* Sets the refFrameOffset after adding the prev_I_rfo to the rfo.
1722                prev_I_rfo will be non-zero ONLY for open gop B's, which are B's that come
1723                after an I but before a P. */
1724                BDBG_MSG(("BNAV_set_refFrameOffset %d, %d", handle->rfo, handle->prev_I_rfo));
1725                BNAV_set_refFrameOffset(avcEntry, handle->rfo + handle->prev_I_rfo);
1726
1727                if (handle->hitFirstISlice) {
1728                    handle->rfo++;
1729                }
1730
1731                BNAV_set_framePts(avcEntry, handle->next_pts);
1732
1733                BNAV_set_RandomAccessIndicator(avcEntry, handle->random_access_indicator);
1734                handle->random_access_indicator = false;
1735            }
1736
1737            if (nal_unit_type == 5 && (slice_type !=2 && slice_type != 7)) {
1738                BDBG_ERR(("IDR frame with non-I slices"));
1739                return -1;
1740            }
1741
1742            /* test if the slice is a referenced by another slice */
1743            if (nal_ref_idc) {
1744                handle->avc.is_reference_picture = 1;
1745            }
1746
1747            /* test every slice to determine frame type */
1748            switch (slice_type) {
1749            case 2:
1750            case 7:
1751                /* we've already defaulted to I frame */
1752                break;
1753            case 0:
1754            case 5:
1755                /* if we ever get one P slice, then it's either a P or B frame, cannot be I */
1756                if (BNAV_get_frameType(avcEntry) == eSCTypeIFrame) {
1757                    handle->isISlice = 0;
1758                    BNAV_set_frameType(avcEntry, eSCTypePFrame);
1759                }
1760                break;
1761            case 1:
1762            case 6:
1763                /* if we ever get one B slice, it's a B frame */
1764                handle->isISlice = 0;
1765                BNAV_set_frameType(avcEntry, eSCTypeBFrame);
1766                break;
1767            default:
1768                BDBG_ERR(("unsupported slice_type %d", slice_type));
1769                break;
1770            }
1771            }
1772            break;
1773        case 7: /* sequence parameter set */
1774            {
1775            unsigned profile_idc, constraint_flags, level_idc, seq_parameter_set_id;
1776
1777            /* parse and vlc decode the payload */
1778            profile_idc = payload[0];
1779            constraint_flags = payload[1];
1780            level_idc = payload[2];
1781            index = 3;
1782            seq_parameter_set_id = b_vlc_decode(payload, TOTAL_PAYLOAD, index, bit, &index, &bit);
1783            if (seq_parameter_set_id >= TOTAL_SPS_ID) {
1784                BDBG_ERR(("corrupt seq_parameter_set_id %u", seq_parameter_set_id));
1785                return -1;
1786            }
1787            handle->avc.sps[seq_parameter_set_id].offset = handle->avc.current_sei_valid?handle->avc.current_sei:offset; /* start with preceding SEI's if present */
1788            handle->avc.current_sps = seq_parameter_set_id;
1789
1790            BDBG_MSG(("SeqParamSet: profile_idc=%u flags=0x%x level_idc=%d SPS=%d offset=%#lx",
1791                profile_idc, constraint_flags, level_idc, seq_parameter_set_id, offset));
1792            }
1793            break;
1794        case 8: /* picture parameter set */
1795            {
1796            unsigned pic_parameter_set_id, seq_parameter_set_id;
1797
1798            /* vlc decode payload */
1799            pic_parameter_set_id = b_vlc_decode(payload, TOTAL_PAYLOAD, index, bit, &index, &bit);
1800            if (pic_parameter_set_id >= TOTAL_PPS_ID) {
1801                BDBG_ERR(("corrupt pic_parameter_set_id %u", pic_parameter_set_id));
1802                return -1;
1803            }
1804            seq_parameter_set_id = b_vlc_decode(payload, TOTAL_PAYLOAD, index, bit, &index, &bit);
1805            if (seq_parameter_set_id >= TOTAL_SPS_ID) {
1806                BDBG_ERR(("corrupt seq_parameter_set_id %u", seq_parameter_set_id));
1807                return -1;
1808            }
1809
1810            handle->avc.pps[pic_parameter_set_id].offset = handle->avc.current_sei_valid?handle->avc.current_sei:offset; /* start with preceding SEI's if present */
1811            handle->avc.pps[pic_parameter_set_id].sps_id = seq_parameter_set_id;
1812            handle->avc.current_pps = pic_parameter_set_id;
1813
1814            BDBG_MSG(("PicParamSet: PPS=%d, SPS=%d offset=%#lx",
1815                pic_parameter_set_id, seq_parameter_set_id, offset));
1816            }
1817            break;
1818
1819#if 0
1820/* This code is optional because we are detecting the picture type by examining each slice. */
1821        case 9: /* access unit delimiter */
1822            {
1823#if BDBG_DEBUG_BUILD
1824            static const char *primary_pic_type_str[] = {
1825                "I",
1826                "I,P",
1827                "I,P,B",
1828                "SI",
1829                "SI,SP",
1830                "I,SI",
1831                "I,SI,P,SP",
1832                "I,SI,P,SP,B"
1833            };
1834#endif
1835            int primary_pic_type;
1836            primary_pic_type = (payload[0] >> 5) & 0x3;
1837
1838            BDBG_MSG(("AUD %d (%s)", primary_pic_type, primary_pic_type_str[primary_pic_type]));
1839            }
1840            break;
1841#endif
1842        }
1843
1844        /* after any non-SEI, the current_sei is no longer valid */
1845        if (nal_unit_type != 6) {
1846            handle->avc.current_sei_valid = false;
1847        }
1848    }
1849
1850    return i;
1851}
1852
1853static long
1854BNAV_Indexer_FeedAVS(BNAV_Indexer_Handle handle, void *p_bfr, long numEntries)
1855{
1856    long i;
1857    const BSCT_Entry *p_curBfr=NULL;
1858    const BSCT_SixWord_Entry *p_cur6WordBfr=NULL;
1859    BNAV_Entry *navEntry = &handle->curEntry;
1860
1861    if (handle->settings.sctVersion != BSCT_Version6wordEntry)
1862    {
1863        BDBG_ERR(("Must use 6 word SCT's for AVC content"));
1864        return -1;
1865    }
1866    p_cur6WordBfr = (const BSCT_SixWord_Entry *)p_bfr;
1867
1868    for (i=0; i<numEntries; i++,p_cur6WordBfr++)
1869    {
1870        int sc;
1871        unsigned long offset, offsetHi;
1872
1873        p_curBfr = CONVERT_TO_SCT4(p_cur6WordBfr);
1874
1875        /* Check for TPIT Entry to extract RAI. discard all other TPIT entries. */
1876        if ((p_cur6WordBfr->word0>>24) == 1)
1877        {
1878            if ((p_curBfr->startCodeBytes & 0x20)>>5)
1879            {
1880                handle->random_access_indicator = true;
1881            }
1882            continue;
1883        }
1884
1885        sc = returnStartCode(p_curBfr->startCodeBytes); /* parse once */
1886        offset = BNAV_Indexer_getScByteOffsetLo(handle, p_curBfr);
1887        offsetHi = BNAV_Indexer_getScByteOffsetHi(handle, p_curBfr);
1888
1889        BNAV_Indexer_P_AddAppend(handle, &offsetHi, &offset);
1890
1891        /* detect invalid start code and offsets */
1892        VALIDATE_AVS_SC(p_curBfr,sc);
1893
1894        BDBG_MSG(("AVS SCT Entry: %02x 0x%02x%08x", sc,
1895                  (p_curBfr->recordByteCountHi>>24) & 0xFF, p_curBfr->recordByteCount));
1896        if (handle->seqHdrFlag)
1897        {
1898            if (sc != SC_AVS_PES && sc != SC_AVS_PTS && sc != SC_AVS_EXTENSION && sc != SC_AVS_USER_DATA)
1899            {
1900                handle->seqHdrFlag = 0;
1901                handle->seqHdrSize = BNAV_Indexer_subtractByteCounts(offset, handle->seqHdrStartOffset);
1902            }
1903        }
1904
1905        switch (sc)
1906        {
1907        case SC_AVS_FIRST_SLICE:
1908            break;
1909
1910        case SC_AVS_PES:
1911            break;
1912
1913        case SC_AVS_PTS:
1914            handle->next_pts = BNAV_Indexer_returnPts(p_curBfr);
1915            break;
1916
1917        case SC_AVS_SEQUENCE:
1918            handle->seqHdrStartOffset = offset;
1919            handle->seqHdrFlag = 1; /* set on next qualifying sct */
1920
1921            /* new complete any pending frame */
1922            handle->picEnd = handle->seqHdrStartOffset;
1923            BNAV_Indexer_completeFrame( handle );
1924            break;
1925
1926        case SC_AVS_SEQ_END:   /* TODO: Change me to any non-slice */
1927            /* complete any pending frame */
1928            handle->picEnd = offset;
1929            BNAV_Indexer_completeFrame( handle );
1930            break;
1931
1932        case SC_AVS_PICTURE_I:
1933        case SC_AVS_PICTURE_PB:
1934            /* complete any pending frame */
1935            handle->picEnd = offset;
1936            BNAV_Indexer_completeFrame( handle );
1937
1938            /* start a new frame */
1939            handle->picStart = offset;
1940
1941            BNAV_set_frameOffsetLo(navEntry, offset);
1942            BNAV_set_frameOffsetHi(navEntry, offsetHi);
1943
1944            if (sc == SC_AVS_PICTURE_I)
1945            {
1946                handle->isISlice = 1;   /* indicated I picture */
1947                handle->isHits = 0;     /* for AVS this should always be 0 */
1948                BNAV_set_frameType(navEntry, eSCTypeIFrame);
1949            }
1950            else
1951            {
1952                switch (returnAvsPictureCode(p_curBfr->recordByteCountHi))
1953                {
1954                case PC_AVS_P_FRAME:
1955                    handle->prev_I_rfo = 0;
1956                    /* First P after first I allows open GOP B's to be saved */
1957                    /* if (handle->hitFirstISlice)
1958                        handle->allowOpenGopBs = 1; */
1959                    BNAV_set_frameType(navEntry, eSCTypePFrame);
1960                    break;
1961                case PC_B_FRAME:
1962                    BNAV_set_frameType(navEntry, eSCTypeBFrame);
1963                    break;
1964                }
1965            }
1966
1967            /* make sequence header offset relative to current frame rather than */
1968            /* relative to reference frame to allow removal of b-frames */
1969            BNAV_set_seqHdrSize(navEntry, (unsigned short)handle->seqHdrSize);
1970            BNAV_set_seqHdrStartOffset(navEntry,
1971                                       BNAV_Indexer_subtractByteCounts(handle->picStart, handle->seqHdrStartOffset));
1972
1973            /* Sets the refFrameOffset after adding the prev_I_rfo to the rfo.
1974            prev_I_rfo will be non-zero ONLY for open gop B's, which are B's that come
1975            after an I but before a P. */
1976            BNAV_set_refFrameOffset(navEntry, handle->rfo + handle->prev_I_rfo);
1977
1978            if (handle->settings.navVersion >= BNAV_VersionOpenGopBs)
1979            {
1980                if (sc == SC_AVS_PICTURE_I)
1981                    handle->prev_I_rfo = handle->rfo;
1982            }
1983
1984            if (handle->hitFirstISlice) {
1985                handle->rfo++;
1986            }
1987
1988            BNAV_set_framePts(navEntry, handle->next_pts);
1989            break;
1990        default:
1991            break;
1992
1993        }
1994
1995    }
1996
1997    return i;
1998}
1999
2000int BNAV_Indexer_FeedPES(BNAV_Indexer_Handle handle, uint8_t *p_bfr, unsigned size)
2001{
2002    if (handle->settings.navVersion == BNAV_Version_VC1_PES) {
2003        return BNAV_P_FeedPES_VC1(handle, p_bfr, size);
2004    }
2005
2006    BDBG_ERR(("FeedPES is only supported for BNAV_Version_VC1_PES"));
2007    return -1;
2008}
Note: See TracBrowser for help on using the repository browser.