source: svn/trunk/newcon3bcm2_21bu/BSEAV/lib/bcmplayer/src/bcmplayer.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: 141.8 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: bcmplayer.c $
11 * $brcm_Revision: 54 $
12 * $brcm_Date: 6/21/10 4:31p $
13 *
14 * Module Description: Transport Stream Index Player
15 *
16 * Revision History:
17 *
18 * Created: 02/09/2001 by Marcus Kellerman
19 *
20 * $brcm_Log: /BSEAV/lib/bcmplayer/src/bcmplayer.c $
21 *
22 * 54   6/21/10 4:31p erickson
23 * SW7405-4249: added BNAV_Version_TimestampOnly option for indexing
24 * audio-only or scrambled streams
25 *
26 * 53   6/3/10 3:53p erickson
27 * SW7400-2788: clean up BNAV_Player_FindIFrameFromIndex to avoid extra
28 * logic
29 *
30 * 52   5/18/10 11:53a erickson
31 * SW7405-4193: back out previous change
32 *
33 * 50   4/5/10 3:58p erickson
34 * SW7405-4131: add bounds check when trying to skip resending the I frame
35 *
36 * 49   3/30/10 11:40a gmohile
37 * SW7405-4079 : Check if nav file supports GOP trick modes before
38 * trickplay
39 *
40 * 48   3/29/10 3:06p erickson
41 * CDSTRMANA-294: re-add 0xb5 extension to dummy picture for field-encoded
42 * MPEG2 brcm trick modes.
43 *
44 * 47   3/17/10 10:21a erickson
45 * CDSTRMANA-294: add MSG for DISPLAY_PAST_BUFFER
46 *
47 * 46   1/8/10 11:02a erickson
48 * SW7405-3041: fix overflow possibility
49 *
50 * 45   11/10/09 3:12p erickson
51 * SW7400-2596: ensure that the first or last I frame is displayed when
52 * doing an I frame trick mode with no looping
53 *
54 * 44   11/4/09 1:15p erickson
55 * SW7400-2591: SkipP for AVC is not allowed
56 *
57 * 43   9/29/09 1:27p erickson
58 * SW7405-3041: rework timestamp and file offset interpolation algos so
59 * that overflow is not possible
60 *
61 * 42   9/4/09 3:47p erickson
62 * SW7405-2974: fix off-by-one error in backward
63 * BNAV_Player_FindIndexFromPts search
64 *
65 * 41   8/28/09 8:11p mphillip
66 * SWDEPRECATED-3998: If index file has a non-zero lower bound, don't try
67 * to read from before the start of file
68 *
69 * 40   7/30/09 12:12p jtna
70 * PR54129: suppress error message in index lookup that are normal due to
71 * race condition with trim
72 *
73 * 39   7/23/09 11:46a ahulse
74 * PR56928: fix compiler warning
75 *
76 * 38   7/22/09 1:56p ahulse
77 * PR56928: Allow user to set loose checking of index file in normal
78 * playback
79 *
80 * 37   7/13/09 10:47a ahulse
81 * PR56762: Report if B frame or not
82 *
83 * 36   6/25/09 11:00a erickson
84 * PR56358: BNAV_Player_FindIndexFromPts should not update its cached read
85 * ptr if the search fails
86 *
87 * 35   6/6/09 12:21p ahulse
88 * PR55770: For field encoded streams return 1st field in frame not 2nd
89 *
90 * 34   6/4/09 4:03p erickson
91 * PR54129: change DEFAULT_NORMAL_PLAY_BUFFER_SIZE to multiple of 188 and
92 * 4096
93 *
94 * 33   2/25/09 4:48p erickson
95 * PR52471: added const keyword
96 *
97 * 32   1/27/09 9:05a erickson
98 * PR51468: make global symbols static
99 *
100 * 31   4/9/08 4:07p erickson
101 * PR41567: don't allow bcmplayer to run without a non-zero video pid
102 *
103 * 30   4/2/08 9:33a erickson
104 * PR41171: add typecast to fix warning. fix misspelling.
105 *
106 * 29   3/27/08 2:28p ahulse
107 * PR27566: Handle interpolated frames in host trick mode, stop searching
108 * when close match
109 *
110 * 28   3/20/08 1:15p ahulse
111 * PR40792: Fix loopback freeze in BCM trickmode
112 *
113 * 27   2/11/08 2:32p gmohile
114 * PR 38980 : Use RAI as starting point for AVC DQT
115 *
116 * 26   1/3/08 6:21p erickson
117 * PR36068: switch B_HAS_RAVE to opt-out. all new chips have RAVE. if you
118 * are using a legacy chip with latest bcmplayer, please add your
119 * BCHP_CHIP.
120 *
121 * 25   12/28/07 12:07p erickson
122 * PR37038: any failure in BNAV_Player_GetNextPlayEntry needs to cause the
123 * function to fail. this is needed for continuous record where the
124 * beginning could be trimmed. also fixed infinite loop off-by-one bug in
125 * BNAV_Player_FindIndexFromPts.
126 *
127 * 24   12/17/07 1:44p katrep
128 * PR37217: Added 7335 support
129 *
130 * 23   12/6/07 10:24a ahulse
131 * PR36547: On file trim, ensure we jump to next I frame
132 *
133 * 22   10/25/07 1:41p ahulse
134 * PR36192: Account for file trimming when in continuous record mode,
135 * AdjustCurrentIndex
136 *
137 * 21   10/22/07 5:23p vishk
138 * PR 35237: SettopAPI-Coverity (CID 512): UNUSED_VALUE,
139 *
140 * 20   10/12/07 12:23p vishk
141 * PR 35237: SettopAPI-Coverity (CID 512): UNUSED_VALUE,
142 *
143 * 19   10/10/07 10:52a btosi
144 * PR30310: renamed TT_MODE_GENERIC_EOS to TT_MODE_INLINE_FLUSH
145 *
146 * 18   10/9/07 3:45p btosi
147 * PR30310: modified BNAV_Player_AdvanceIndex() to use the new commands
148 * TT_MODE_GENERIC_EOS and TT_MODE_PIC_OUTPUT_COUNT
149 *
150 * 17   10/4/07 6:58p vishk
151 * PR 35280: SettopAPI-Coverity (CID 326): DEADCODE,
152 *
153 * 15   7/18/07 12:00p erickson
154 * PR30310: implement skipGOP feature for eBpPlayDecoderGOPTrick
155 *
156 * 14   7/16/07 5:12p erickson
157 * PR30310: don't allow eBpPlayDecoderGOPTrick with playModeModifier == 0
158 *
159 * 13   7/16/07 4:46p erickson
160 * PR30310: fixed support for field-encoded AVC streams for DQT
161 *
162 * 12   6/20/07 1:13p erickson
163 * PR30310: convert to BNAV_Player_GenerateStartCodePacket and use for
164 * EOS, SeqEnd as part of DQT impl.
165 *
166 * 11   6/12/07 10:46a erickson
167 * PR30310: fix eBpPlayDecoderGOPTrick loop around at BOF
168 *
169 * 10   5/22/07 12:46p erickson
170 * PR24374: improve BDBG_MSG for typical debug
171 *
172 * 9   4/30/07 1:32p erickson
173 * PR30310: added eBpPlayDecoderGOPTrick
174 *
175 * 8   2/9/07 2:03p ahulse
176 * PR27136: Increase max fifo entries to accomadate a GOP size up to 60
177 *
178 * 7   2/9/07 11:57a katrep
179 * PR26647: Rave has improved flush.Taken out the empty BPT packet
180 * insertion workaround added in ver 5.
181 *
182 * 6   2/7/07 11:12a ahulse
183 * PR27362: Downgrade near match PTS warning to a message
184 *
185 * 5   1/24/07 1:22p erickson
186 * PR27274: send a harmless PROCESS BTP through the system so any pending
187 * PROCESS is nullified. this is a workaround which appears 100%
188 * effective. it should be removed when the root cause is understood.
189 *
190 * 4   11/30/06 6:36p erickson
191 * PR26095: add eBpPlayNormalByFrames for IP settop support
192 *
193 * 3   11/30/06 12:03p erickson
194 * PR26095: removed unused NEW_PLAY_MODE with normalForward state
195 * variable. This was a modification of brcm trick modes with advance
196 * count 1. It would confuse the feature about to go in.
197 *
198 * 2   11/27/06 1:59p erickson
199 * PR25109: added 7403/7405 support
200 *
201 * Irvine_BSEAVSW_Devel/163   10/5/06 3:34p mward
202 * PR21671: 7118 B_HAS_RAVE
203 *
204 * Irvine_BSEAVSW_Devel/162   9/12/06 5:59p ahulse
205 * PR22600, PR22661: Increased PTS_CACHE_SIZE, reworked search algorithm
206 * to avoid lengthy searches, interpolate PTS's if needed
207 *
208 * Irvine_BSEAVSW_Devel/161   8/14/06 2:00p ahulse
209 * PR23214: use sizeof dummy_picture to calculate correct offsets
210 *
211 * Irvine_BSEAVSW_Devel/160   8/14/06 1:26p ahulse
212 * PR23214: Remove picture coding extension when sending dummy picture
213 *
214 * Irvine_BSEAVSW_Devel/158   6/30/06 2:52p erickson
215 * PR21941: fix warning
216 *
217 * Irvine_BSEAVSW_Devel/157   5/11/06 3:29p mphillip
218 * PR20797: Add boundary shortcuts to IndexFromTimestamp to avoid lengthy
219 * linear searches
220 *
221 * Irvine_BSEAVSW_Devel/156   5/4/06 4:47p erickson
222 * PR21422: added improved debug for bad streams, bad PTS's
223 *
224 * Irvine_BSEAVSW_Devel/155   4/4/06 2:36p ahulse
225 * PR20249: Clear needsDisplayPicture flag if we can't find entry in
226 * index. Otherwise loops forever.
227 *
228 * Irvine_BSEAVSW_Devel/154   3/28/06 3:42p mphillip
229 * PR19786: Handle version detection on trimmed files (mainline)
230 *
231 * Irvine_BSEAVSW_Devel/153   3/24/06 10:29a erickson
232 * PR20220: added additional condition (I frame trick mode) to InsertEOS
233 * test.
234 *
235 * Irvine_BSEAVSW_Devel/152   3/21/06 6:09p ahulse
236 * PR18725: Put back in insertion of EOS before I frames
237 *
238 * Irvine_BSEAVSW_Devel/151   3/21/06 11:48a erickson
239 * PR19848: use BTP's for host trick modes on 740x
240 *
241 * Irvine_BSEAVSW_Devel/150   3/17/06 2:00p erickson
242 * PR19848: don't use BTP's for host trick modes on 740x yet because of
243 * decoder hang
244 *
245 * Irvine_BSEAVSW_Devel/149   3/16/06 12:52p erickson
246 * PR19848: added 740x BTP support
247 *
248 * Irvine_BSEAVSW_Devel/148   3/8/06 4:51p erickson
249 * PR19853: fix off by one for VC1
250 *
251 * Irvine_BSEAVSW_Devel/147   3/6/06 1:20p erickson
252 * PR19853: added VC1 PES support
253 *
254 * Irvine_BSEAVSW_Devel/146   2/24/06 11:21a dlwin
255 * PR 19611: Remove specific code for 7411D0, treat 7411D0 as a 7411C0.
256 *
257 * Irvine_BSEAVSW_Devel/145   2/15/06 4:54p ahulse
258 * PR19373: No longer zero out data in packet, rely on BTP info for data
259 * trim.
260 *
261 * Irvine_BSEAVSW_Devel/144   2/1/06 5:30p ahulse
262 * PR17951: change bounds checking in
263 * BNAV_Player_FindIndexFromOffset/Timestamp to be >= instead of >
264 *
265 * Irvine_BSEAVSW_Devel/143   1/26/06 12:29p rjlewis
266 * PR18408: must declare storage at top with old C compilers.
267 *
268 * Irvine_BSEAVSW_Devel/142   1/18/06 5:35p ahulse
269 * PR18408, PR18725:: Insert a valid PTS when adding SequenceHeader. Don't
270 * send EOS before I frame in forward AVC trickmodes
271 *
272 * Irvine_BSEAVSW_Devel/140   1/8/06 10:36a dlwin
273 * PR 18408: Corrected for incorrect PTS values.  Checkin for Adrian, due
274 * to user priivilege problems.
275 *
276 * Irvine_BSEAVSW_Devel/139   11/30/05 3:07p vsilyaev
277 * PR 18183: Improved error reporting
278 *
279 * Irvine_BSEAVSW_Devel/138   9/14/05 2:24p erickson
280 * PR17148: converted to BCHP_7411_REV
281 *
282 * Irvine_BSEAVSW_Devel/137   9/6/05 11:06a erickson
283 * PR16794: BTP needs to include whole first packet only for legacy
284 * platforms now
285 *
286 * Irvine_BSEAVSW_Devel/136   9/2/05 11:52a erickson
287 * PR15861: use BTP's for host trick modes on 7038
288 *
289 * Irvine_BSEAVSW_Devel/135   8/30/05 2:17p erickson
290 * PR16208: for field encoded streams, don't send adjacent I pictures
291 *
292 * Irvine_BSEAVSW_Devel/134   8/26/05 3:48p erickson
293 * PR16794: Use BTP's on 7411 host trick modes to trim last packet, but
294 * not first packet, for a picture. This allows PES headers to get
295 * through. Also, for PR 16803 I changed the logic on inserting EOS NAL
296 * headers. They are now inserted before every I picture instead of after
297 * every picture.
298 *
299 * Irvine_BSEAVSW_Devel/133   8/25/05 1:34p erickson
300 * PR16208: make AVC EOS insertion permanent, and fix MPEG2 TS header for
301 * EOS packet
302 *
303 * Irvine_BSEAVSW_Devel/132   8/19/05 3:54p erickson
304 * PR16208: added EOS NAL unit after each frame during AVC trick modes
305 *
306 * Irvine_BSEAVSW_Devel/130   8/3/05 12:07p erickson
307 * PR16138: improve comments, restore skip_count on BUILD_REFERENCE for
308 * 7411
309 *
310 * Irvine_BSEAVSW_Devel/129   7/18/05 11:35a erickson
311 * PR16205: form correct PROCESS BTP's for 7411c and d
312 *
313 * Irvine_BSEAVSW_Devel/128   7/15/05 10:07p erickson
314 * PR16138: added AVC support for SPS and PPS, refactored to allow more
315 * shared code, implemented BTP's for 7411 host trick modes, reworked
316 * GenerateDummyPicture in endian-neutral way
317 *
318 * Irvine_BSEAVSW_Devel/127   7/13/05 3:05p erickson
319 * PR16207: added 7411D support
320 *
321 * Irvine_BSEAVSW_Devel/126   7/13/05 2:10p erickson
322 * PR16138: added new NAV version for AVC support, PPS and SPS support
323 * added, refactored player to better support this with less code
324 * duplication
325 *
326 * Irvine_BSEAVSW_Devel/125   7/8/05 8:49a erickson
327 * PR15861: added check for sending seqhdr for BTP-based host trick modes
328 *
329 * Irvine_BSEAVSW_Devel/124   7/6/05 4:18p erickson
330 * PR16094: modified 7411C impl to use NULL packet before data when
331 * data_end_packet is 1 or 3. This allows both data_start_byte and
332 * data_end_byte to be used by hardware.
333 *
334 * Irvine_BSEAVSW_Devel/123   7/6/05 2:21p erickson
335 * PR16102: increase PTS_CACHE_SIZE to support SD AVC in HD sized buffers.
336 * Also improved debug messages.
337 *
338 * Irvine_BSEAVSW_Devel/122   7/1/05 5:55p erickson
339 * PR15443: fixed non-7411c build
340 *
341 * Irvine_BSEAVSW_Devel/121   7/1/05 4:33p erickson
342 * PR15443: fixed i386 compilation warnings
343 *
344 * Irvine_BSEAVSW_Devel/120   7/1/05 10:52a erickson
345 * PR15443: Setting PTS based on each frame that is decoded. Firmware is
346 * now reading PTS and this is required in order to get out correct
347 * current PTS from decoder.
348 *
349 * Irvine_BSEAVSW_Devel/119   6/13/05 12:21p erickson
350 * PR15849: set zeroByteCountBegin after adjusting for possible seqhdr
351 *
352 * Irvine_BSEAVSW_Devel/118   6/8/05 1:37p erickson
353 * PR15126: converted BNAV_Player_FindIndexFromPts to use a cache of
354 * recently sent pictures and their PTS values. No longer perform an
355 * index search.
356 *
357 * Irvine_BSEAVSW_Devel/117   4/26/05 2:07p erickson
358 * PR15052: removed PICTURE_START/END_PACKET/BYTE because they are unused.
359 * Made usage of DISCARD_TAILEND consistent. Use SKIP_COUNT=0 for
360 * BUILD_REFERNECE because it was incorrect and unused anyway.
361 *
362 * Irvine_BSEAVSW_Devel/116   3/9/05 12:29p erickson
363 * PR13202: fixed zeroByteCountEnd logic for 7411C
364 *
365 * Irvine_BSEAVSW_Devel/115   3/8/05 3:43p erickson
366 * PR13202: refactored common 7411C code into SendData, and added seqhdr
367 * support
368 *
369 * Irvine_BSEAVSW_Devel/114   3/8/05 11:07a erickson
370 * PR13202: commented out BCM7411C_BTP_FORMAT
371 *
372 * Irvine_BSEAVSW_Devel/113   3/7/05 9:39a erickson
373 * PR13202: inc DATA_END_PACKET if value is 1 or 3, then add a dummy
374 * packet
375 *
376 * Irvine_BSEAVSW_Devel/112   3/4/05 4:17p erickson
377 * PR13202: modified 7411C_BTP_FORMAT based on new requirements from 7411
378 *
379 * Irvine_BSEAVSW_Devel/111   3/3/05 12:52p erickson
380 * PR8348: refactored BNAV_Player_AddFrameToFifo to support two things:
381 * 1) interruption of the BuildReferenceFrame process - this allows a
382 * smaller size FIFO to be used
383 * for a large GOP. If the FIFO fills up, the function returns and resumes
384 * its work later.
385 * 2) subdivision of the GOP into multiple reference frames - this allows
386 * large GOP streams to be
387 * processed without a huge bandwidth spike on the trailing frames in the
388 * GOP.
389 * The main change was to change BNAV_Player_AddFrameToFifo so that it
390 * doesn't recurse in order to
391 * build a reference frame. There's now a separate function for that, and
392 * so there isn't all the
393 * extra conditionals to handle this. This makes handling these new
394 * features manageable.
395 * The remaining BNAV_Player_AddFrameToFifo function is only used to build
396 * displayed frames, and it
397 * can't be interrupted because the various optimizations are more
398 * complex.
399 * There are two new #define options for controlling this new behavior:
400 * MAX_REFERENCE_FRAME_OFFSET
401 * MAX_NUM_FIFO_ENTRIES-8 is used for max size (probably need another
402 * #define here)
403 *
404 * Irvine_BSEAVSW_Devel/110   2/28/05 9:37a erickson
405 * PR13202: added NEW_BTP_FORMAT support, defaulted off
406 *
407 * Irvine_BSEAVSW_Devel/109   2/18/05 12:38p erickson
408 * PR14180: handle endianness of dummy picture BTP's
409 *
410 * Irvine_BSEAVSW_Devel/108   2/3/05 3:19p erickson
411 * PR14017: must factor in timestampOffset when calculating BTP params
412 * using packetSize
413 *
414 * Irvine_BSEAVSW_Devel/107   2/3/05 1:36p erickson
415 * PR14017: fix for 192 byte packets
416 *
417 * Irvine_BSEAVSW_Devel/106   11/30/04 4:07p erickson
418 * PR13303: commented out debug code
419 *
420 * Irvine_BSEAVSW_Devel/105   11/30/04 4:05p erickson
421 * PR13303: added useReferenceFrame setting, defaulting to true, which
422 * allows reduced memory/reduced performance mode
423 *
424 * Irvine_BSEAVSW_Devel/104   8/19/04 1:48p erickson
425 * PR11582: brcm trick modes with mode_modified ==1 are invalid. fail it.
426 *
427 * Irvine_BSEAVSW_Devel/103   5/10/04 11:33a erickson
428 * PR10065: fixed compiler warnings (most were unsigned/signed mismatches)
429 *
430 * Irvine_BSEAVSW_Devel/102   4/30/04 12:57p erickson
431 * PR10909: default to magnum kernelinterface (debug or release) but
432 * support legacy if specifically requested
433 *
434 * Irvine_BSEAVSW_Devel/101   4/14/04 5:03p erickson
435 * PR10065: if BNAV_Player_AddNormalPlay fails, don't leave bad fifo entry
436 * in the fifo
437 *
438 * Irvine_BSEAVSW_Devel/100   4/13/04 4:57p erickson
439 * PR10292: allow sanity check to be skipped, also cleaned up some
440 * compiler warnings and debug messages
441 *
442 * Irvine_BSEAVSW_Devel/99   3/18/04 3:38p erickson
443 * PR10111: Null out bounds callback if SetBounds is called. Also NULL'd
444 * handle when open fails and verified direction parameter is always 1/-1
445 * in a search algorithm.
446 *
447 * Irvine_BSEAVSW_Devel/98   1/23/04 12:20p bandrews
448 * PR8956: Bad frame caused by missing sequence header just before short I
449 * frame.
450 *
451 * Irvine_BSEAVSW_Devel/97   12/8/03 11:32a erickson
452 * PR8879: added BNAV_Player_GetPositionInformation. doesn't impact
453 * existing api.
454 *
455 * Irvine_BSEAVSW_Devel/96   11/10/03 2:33p erickson
456 * PR8563: added transport timestamp support to bcmplayer
457 *
458 * Irvine_BSEAVSW_Devel/95   11/10/03 2:29p erickson
459 * PR8563: added transport timestamp support to bcmplayer
460 *
461 * Irvine_BSEAVSW_Devel/94   10/8/03 4:25p erickson
462 * need to rely on brcm_t.h for uint64_t. No more platform-specific
463 * typedefs.
464 *
465 * Irvine_BSEAVSW_Devel/93   9/17/03 12:11p erickson
466 * support both original and magnum debug interfaces
467 * replaced kernel interface calls with ansi calls
468 *
469 * Irvine_BSEAVSW_Devel/92   9/8/03 5:01p erickson
470 * added sanity check
471 * this makes sure we're not trying to play completely corrupted, wrong-
472 * endianness indexes
473 *
474 * Irvine_BSEAVSW_Devel/91   8/26/03 5:02p erickson
475 * normal play should still feed in 188 byte chunks because of other
476 * dependencies throughout the system
477 * correct skip count for build reference. the firmware isn't checking it
478 * anyway, but we wanted it to
479 * mimic the skip count for decode.
480 *
481 * Irvine_BSEAVSW_Devel/90   8/25/03 12:30p erickson
482 * Version 0 indexes need to fail. For a short time there were version 0
483 * indexes being produced and not getting labelled. False detects are
484 * bad, and I don't want to leave the auto-detect code in there long-
485 * term. So it's best to just fail them. You really shouldn't run version
486 * 0 anyway because it's very inefficient.
487 * I also fixed the skip count for BUILD_REFERENCE.
488 *
489 * Irvine_BSEAVSW_Devel/89   8/25/03 11:26a erickson
490 * DISPLAY_PAST_BUFFER doesn't work with old index formats
491 *
492 * Irvine_BSEAVSW_Devel/88   8/22/03 9:22a erickson
493 * fixed normal play
494 *
495 * Irvine_BSEAVSW_Devel/87   8/8/03 10:25a erickson
496 * fixed variable declaration in middle of source
497 *
498 * Irvine_BSEAVSW_Devel/86   7/23/03 9:22a erickson
499 * now setting or clearing the discontinuity_indicator in BTP packets (PR
500 * 6380)
501 *
502 * Irvine_BSEAVSW_Devel/85   6/24/03 11:03a erickson
503 * PR7218 - handled partially encrypted streams. Added maxFrameSize and
504 * mpegSizeCallback. Had to change the
505 * NAV table format (version 2) in order to handle I frames with reference
506 * offset of 0. Bcmplayer
507 * is backward compatible.
508 *
509 * Irvine_BSEAVSW_Devel/84   5/27/03 11:10a erickson
510 * zeroByteCountBegin/End must be set to 0 for BTP packets
511 * zeroByteCountBegin/End of 188 should be 0
512 *
513 * Irvine_BSEAVSW_Devel/83   5/19/03 5:47p erickson
514 * Fixed logic for zeroByteCountEnd.
515 *
516 * Irvine_BSEAVSW_Devel/82   5/19/03 1:16p marcusk
517 * Specify how many bytes must be zeroed when performing trick modes and
518 * frames are not aligned to transport packet boundaries.
519 *
520 * Irvine_BSEAVSW_Devel/81   4/25/03 1:48p erickson
521 * used brcm_t.h for uint64_t
522 *
523 * Irvine_BSEAVSW_Devel/80   4/23/03 2:11p erickson
524 * enabled DISPLAY_PAST_BUFFER and DUMMY_PICTURE optimizations for 7xxx
525 * platforms.
526 *
527 * Irvine_BSEAVSW_Devel/79   4/23/03 10:07a erickson
528 * win32 uint64_t definition, resolved warnings
529 *
530 * Irvine_BSEAVSW_Devel/78   4/22/03 5:16p erickson
531 * New optimizations working, but not released yet
532 *
533 * Irvine_BSEAVSW_Devel/77   4/9/03 1:12p erickson
534 * no video pid is allowed, but don't allow broadcom trick modes
535 *
536 * Irvine_BSEAVSW_Devel/76   4/4/03 1:41p erickson
537 * converted bcmplayer to use uint64_t directly
538 *
539 * Irvine_BSEAVSW_Devel/75   3/31/03 2:42p erickson
540 * added DUMMY_PICTURE_OPTIMIZATION, but left it commented out.
541 *
542 * Irvine_BSEAVSW_Devel/74   3/11/03 4:00p erickson
543 * fixed debug interface usage
544 *
545 * Irvine_BSEAVSW_Devel/73   2/28/03 5:21p erickson
546 * Normal play wraps now backup to the seqhdr and ts-packet
547 * When doing trick modes after setCurrentIndex, we have to validate the
548 * frame type and
549 * can't completely skip the next advance.
550 *
551 * Irvine_BSEAVSW_Devel/71   2/14/03 2:57p erickson
552 * fixed DISPLAY_PAST_BUFFER_OPTIMIZATION
553 *
554 * Irvine_BSEAVSW_Devel/70   2/14/03 1:57p erickson
555 * New naming convention
556 * Fixed looping from previous rework
557 * Removed bcmindexer _getParam/_setParam
558 * Did not change code shared between tsplayer and bcmplayer
559 * Refactored settings, playmode and other structures
560 *
561 * Irvine_BSEAVSW_Devel/69   2/12/03 11:42a erickson
562 * commented out PRINT_PACKETTYPES_SENT
563 * defaulted the debugMode
564 * initialized the lastOffset variable
565 *
566 * Irvine_BSEAVSW_Devel/68   2/11/03 11:46a erickson
567 * loopMode wasn't allowed to be changed for normal play
568 * normal playback now loops
569 *
570 * Irvine_BSEAVSW_Devel/67   2/10/03 5:23p erickson
571 * win32 compilation warnings
572 *
573 * Irvine_BSEAVSW_Devel/66   2/10/03 5:15p erickson
574 * bcmplayer rework:
575 * 1) version 2.02
576 * 2) removed getParam/setParam API
577 * 3) added various get/set functions and specific algorithmic functions.
578 * No more typecasting
579 * or strange parameter passing needed. Each function has a specified
580 * execution time.
581 * 4) added run-time debug modes
582 * 5) normal play is no longer frame based. this enables 60 frames/sec
583 * content.
584 *
585 * Irvine_BSEAVSW_Devel/65   10/30/02 10:16a erickson
586 * Made floating point support optional, defaulting off. Define HAVE_FLOAT
587 * to turn it back on.
588 *
589 * Irvine_HDDemo_Devel/64   9/26/02 3:4p erickson
590 * Changed bcmindexer vchip from 3 bits to 16 bits packed into 12 bits.
591 * The index is NOT backward compatible, but the 3 bit version had only
592 * been released for 1 day.
593 *
594 * Irvine_HDDemo_Devel/63   9/25/02 9:36a erickson
595 * ExtraB optimization disabled by default because venom2 doesn't support
596 * it.
597 * When changing eBpPlayMode, if it remains in normal play, do nothing.
598 * This fixes a bug when unpausing normal play.
599 *
600 * Irvine_HDDemo_Devel/62   9/20/02 11:58a erickson
601 * Enabled EXTRA_B optimization. This works for minititan but not venom2
602 * currently.
603 * Removed old STUB_LAST_IP code because it will never be used.
604 * Removed generate_NULL code because it isn't needed.
605 * Added eBpIsHits and bcmplayer_isHits()
606 * Enabled eBpPlayIP for HITS as well as GOP-based streams
607 * Modified bcmplayer_findPictureIndex to detect mismatched searches in
608 * HITS and GOP-based streams and to prevent long and unproductive
609 * searches.
610 *
611 * Irvine_HDDemo_Devel/61   9/9/02 11:52a erickson
612 * added vchip support
613 *
614 * Irvine_HDDemo_Devel/60   8/15/02 2:1p swindell
615 * Fix VxWorks bcmkernel.h capitalization mismatch.
616 *
617 * Irvine_HDDemo_Devel/59   8/14/02 10:22a erickson
618 * disabled the EXTRA_B_OPTIMIZATION until firmware supports it
619 * reorganized some #defines
620 *
621 * Irvine_HDDemo_Devel/58   8/12/02 10:24a erickson
622 * Fixed some compilation typecast warnings when using C++ compiler
623 * Fixed rewind algorithm so if there's no skip frames in DISPLAY_REV, it
624 * will resend the reference frame.
625 * A few changes to the stub-frame code, which still doesn't work.
626 * Fixed IndexFromPTS algorithm for adjacent I/P frames.
627 *
628 * Irvine_HDDemo_Devel\57   7/8/02 10:57a erickson
629 * during 1x rewind, combine adjacent B's into single DISPLAY sequence.
630 * 18% throughput savings.
631 * Also found I was sending an extra I during rewind, so that's another 7
632 * %.
633 * Total optimization from original algorithm: 50%
634 *
635 * Irvine_HDDemo_Devel\55   7/2/02 4:59p erickson
636 * Updated to version 0201. This required bcmindexer version >= 0201.
637 * Accelerates broadcom trick modes for GOP-based streams by 25% by using
638 * a single I frame as the reference frame and then sending only what's
639 * necessary.
640 *
641 * Irvine_HDDemo_Devel\54   6/19/02 4:1p erickson
642 * complete rework of IndexFromPts algorithm. Works MUCH better.
643 * Removed prevFrameEnd state variable.
644 * Changed logic for sending sequence header on normal playback.
645 * Made some macros to cleanup code.
646 *
647 * Irvine_HDDemo_Devel\52   6/17/02 10:9a erickson
648 * fixed compiler warnings
649 *
650 * Irvine_HDDemo_Devel\51   5/17/02 9:47a marcusk
651 * Added "" around BDBG_MODULE to support new debug routines.
652 *
653 * Irvine_HDDemo_Devel\50   4/17/02 1:24p erickson
654 * Removed skip opengop b code (which never worked)
655 * Added IndexFromTimestamp
656 * Added readIndex()
657 * Converted printf's to BDBG_MSG
658 * Removed getPrevPlayEntry, which was the result of a misunderstanding of
659 * customer requirements.
660 *
661 * Irvine_HDDemo_Devel\49   4/16/02 2:54p erickson
662 * Removed unused variable
663 *
664 * Irvine_HDDemo_Devel\48   4/16/02 2:53p erickson
665 * Implemented 2nd cache for IndexFromPts
666 * Fixed IndexFromPts jitter problem
667 * Convert get_frameOffset64 to macro
668 * Added printCachePerformance
669 *
670 * \main\Irvine_HDDemo_Devel\45   3/15/02 6:35p erickson
671 * Added #include <math.h> for abs() on WIN32
672 *
673 * \main\Irvine_HDDemo_Devel\44   3/15/02 6:31p erickson
674 * Added skipNextAdvance so that trick modes would start on the I frame.
675 * Removed some debug code.
676 *
677 * \main\Irvine_HDDemo_Devel\43   3/8/02 5:13p erickson
678 * Removed #ifdef for SKIP_OPENGOP
679 * Added some debug statements
680 * Combined addForward and addFrame, and fixed a logic error
681 * Added some code for new I Frame ref offset, but left it commented out.
682 *
683 * \main\Irvine_HDDemo_Devel\42   3/5/02 9:38a marcusk
684 * Fixed VisualC++ compiler warnings.
685 *
686 * \main\Irvine_HDDemo_Devel\41   3/4/02 8:48p erickson
687 * Implemented SkipB and SkipP Removed \n from debug statements Turned on
688 * Skip Open GOP and USE_NEW_DISPLAY_MODES Fixed Skip Open GOP for trick
689 * modes
690 *
691 * \main\Irvine_HDDemo_Devel\41   3/4/02 8:40p erickson
692 * Removed unused members from structure Removed some redundant state
693 * checking outside of setParam Fixed the skip open gop code to work for
694 * play and trick modes Implemented SkipP and SkipB Removed \n from all
695 * debug messages.
696 *
697 * \main\Irvine_HDDemo_Devel\40   2/27/02 12:35p erickson
698 * Added PRINT_PACKETTYPES_SENT and PRINT_PACKETTYPES_ADDED debugging
699 * modes. Added method to get fifo size. Removed PTS search threshold in
700 * favor of first-fit algorithm. When setting PlayMode, I normalize the
701 * mode, then check if there's really a change. When setting the PTS or
702 * SCT, I seek to an I-frame, unless it's hits. No longer sending NULL
703 * packet when flushing the fifo. It's not needed and doesn't belong
704 * there. When playing normal, the startIndex shouldn't be incremented
705 * until the first frame is sent, otherwise we lose the initial I frame.
706 * Added SKIP_OPENGOP code, but left it commented out until later. Fixed
707 * getLastSctIndex to return the correct index.
708 *
709 ***************************************************************************/
710#ifndef USE_LEGACY_KERNAL_INTERFACE
711/* Magnum debug interface */
712#include "bstd.h"
713#include "bchp.h"
714BDBG_MODULE(bcmplayer);
715#else
716/* Original debug interface */
717#define BRCM_DBG_MODULE_NAME "bcmplayer"
718#include "brcm_dbg.h"
719#include "brcm_t.h" /* uint64_t */
720#define BCHP_VER_C0 (0x00020000)
721
722/* emulate magnum */
723#define BDBG_ERR(X) BRCM_DBG_ERR(X)
724#define BDBG_WRN(X) BRCM_DBG_WRN(X)
725#define BDBG_MSG(X) BRCM_DBG_MSG(X)
726#define BDBG_ASSERT(COND) \
727    do {if (!(COND)) BDBG_ERR(("BDBG_ASSERT failed on %d", __LINE__)); } while (0)
728#define BSTD_UNUSED(X)
729#endif
730
731#include "bcmindexer.h"
732#include "bcmindexerpriv.h"
733#include "bcmplayer.h"
734#include "mpeg2types.h"
735#include <stdio.h>
736#include <string.h>
737#include <stdlib.h>
738
739#define i_abs(X) ((X)<0?-(X):(X))
740
741#define DEFAULT_CACHE_SIZE          100
742#define BTP_PACKET_DATA_SIZE        10
743#define MAX_NUM_FIFO_ENTRIES        250  /* set this to 4 x MAX GOP length if get "bcmplayer ERROR: fifo full!" errors */
744#define MAX_REFERENCE_FRAME_OFFSET  30
745#define DEFAULT_NORMAL_PLAY_BUFFER_SIZE (188*2*1024) /* enough to handle 720p, but should be tuned */
746
747#define BDBG_MSG_PTSCACHE(X) /* BDBG_MSG(X) */
748
749/*
750   Set LOOSE_INDEX_CHECKING if you want bcmplayer to ignore certain errors found in the nav file.
751   Disabled by default, as it is better to identify the source of the errors than ignore them.
752*/
753/* #define LOOSE_INDEX_CHECKING       1 */
754
755/*
756PR 15861 - BTP's are used for host trick modes on 7038 (minititan+) and 7411 decoders.
757They are not supported on legacy platforms (minititan).
758*/
759#if BCHP_CHIP == 7320 || BCHP_CHIP == 7315 || BCHP_CHIP == 7110 || BCHP_CHIP == 7115
760/* No RAVE. */
761#else
762#define B_HAS_RAVE 1
763#endif
764#if BCHP_CHIP == 7038 || B_HAS_RAVE
765#define USE_BTPS_FOR_HOST_TRICK_MODES
766#endif
767
768/**
769* There are numerous places where functions are called, and if they return
770* NULL, an error message is generated and the function returns immediately with
771* -1. This macro does that.
772**/
773#define CHECKREAD(READ) \
774    if (!(READ)) { \
775        BDBG_ERR(("%s failed on line %d", #READ, __LINE__)); \
776        return -1; \
777    }
778#define CHECKREAD_SILENT(READ) \
779    if (!(READ)) { \
780        return -1; \
781    }
782
783typedef enum
784{
785    eBpInsertNone = 0, /* No inserted packet. This is used for data that must be read from file. */
786    eBpInsertBTP, /* Broadcom Transport Packet, used for Broadcom trick modes and delimited data */
787    eBpInsertDummy, /* one packet picture, used for advancing the decoder pipeline but not being displayed */
788    eBpInsertNULL, /* NULL packet (pid 0x1fff) */
789    eBpInsertStartCode, /* insert packet with single start code */
790    TotalPacketTypes
791} eBpInsertPacketType;
792
793typedef struct BNAV_sPktFifoEntry
794{
795    eBpInsertPacketType insertpackettype;
796    unsigned long pktdata[BTP_PACKET_DATA_SIZE]; /* BTP payload */
797    uint64_t startByte;
798    uint64_t endByte;
799    unsigned long zeroByteCountBegin;
800    unsigned long zeroByteCountEnd;
801    unsigned startcode;
802    struct BNAV_sPktFifoEntry *next;
803} BNAV_PktFifoEntry;
804
805struct BNAV_Player_HandleImpl
806{
807    /* callbacks */
808    BP_READ_CB          readCb;
809    BP_TELL_CB          tellCb;
810    BP_SEEK_CB          seekCb;
811    BP_BOUNDS_CB        boundsCb;
812    void                *filePointer;
813
814    /* nav cache */
815    unsigned char       *navCache;
816    long                navCacheIndexStart;
817    long                navCacheIndexEnd;
818
819    /* nav cache metrics */
820    long                navCacheMisses;
821    long                navCacheReads;
822    long                navCacheFails;
823
824    /* nav cache parameters */
825    int                 navCacheSize; /* size in entries */
826    int                 navCacheBytes; /* size in bytes */
827    int                 navCacheOverlap; /* hardcoded to 1/4 of navCacheSize for now */
828
829    /* file format parameters */
830    long                navFileIndexEntryStart;
831    long                navFileIndexEntrySize;  /* size of each record in NAV table.
832                            Currently either sizeof(BNAV_Entry) or sizeof(BNAV_AVC_Entry) */
833
834    /* state */
835    eBpPlayModeParam    playMode;
836    eBpDirectionParam   playDir;
837    eBpLoopModeParam    loopMode;
838    long                currentIndex;
839    int                 skipCount; /* used for eBpPlaySkipB and eBpPlaySkipP */
840
841    int                 advanceCount;  /* Number of frames to advance each
842                                          picture (1=Normal) */
843    unsigned short      pid;            /* Current video PID */
844    char                gotEntry;       /* indicates that getNextEntry got an entry. */
845    long                firstIndex;
846    long                lastIndex;
847
848    BNAV_PktFifoEntry   pktfifo[MAX_NUM_FIFO_ENTRIES];
849    long                firstFifoEntry;
850    long                lastFifoEntry;
851    BNAV_PktFifoEntry   *pktfifo_tail;
852    int                 curRefFrame;
853    int                 skipNextAdvance;
854    int                 iFrameRepeatCount;
855    uint64_t            lastSeqHdrOffset64;
856    int                 disableExtraBOptimization; /* see note in playertypes.h */
857    BNAV_DecoderFeatures    decoderFeatures;
858    BNAV_Version        navVersion;
859    int                 useReferenceFrame;
860
861    /* used for normal playback */
862    uint64_t currentOffset;
863    unsigned long normalPlayBufferSize;
864    BNAV_Player_DebugMode debugMode;
865
866    int                 pastPred, futurePred;
867
868    int timestampOffset;    /* 0 or 4 */
869    unsigned packetSize;    /* 188 or 192 */
870
871    /* Data needed to interrupt and resume BNAV_Player_BuildReferenceFrame_Process */
872    struct {
873        int inProcess; /* if true, haven't finished reference frame */
874        int needDisplayPicture;/* if true, haven't sent display frame that necessitated the reference frame */
875        long curOffset;
876        unsigned long lastFrameSize;
877        long entry;
878    } buildRef;
879
880    /* array used to cache last displayed frames so that we can do efficient pts->index searches,
881    even during fast trick modes. The value of PTS_CACHE_SIZE should be enough to hold all the pictures
882    in even large playback and video FIFO's.
883    300 appears sufficient for MPEG2, but 600 is required for AVC. We need to handle SD decode in HD sized
884    playback and decode fifos. */
885#define PTS_CACHE_SIZE 1200
886    struct {
887        uint32_t pts;
888        long index;
889    } ptscache[PTS_CACHE_SIZE];
890    int ptscache_wptr;      /* index where next ptscache entry will be written  */
891    int ptscache_rptr;      /* index where we read ptscache entry from      */
892    int doBackwardPtsSearch;    /* If set search backwards instead of forwards      */
893
894    /* used for eBpPlayDecoderGOPTrick */
895    struct {
896        int currentStart, currentEnd;
897        int pictureTag;
898        int gopSkip; /* how many gops to skip between advances */
899    } gopTrick;
900};
901
902/*---------------------------------------------------------------
903- PRIVATE FUNCTIONS
904---------------------------------------------------------------*/
905static BNAV_Entry *BNAV_Player_ReadEntry(BNAV_Player_Handle handle, long index);
906
907static void BNAV_Player_SetCacheSize(BNAV_Player_Handle handle, int cacheSize);
908static int BNAV_Player_AddNormalPlay(BNAV_Player_Handle handle);
909static int BNAV_Player_AddNormalPlayByFrames(BNAV_Player_Handle handle);
910static int BNAV_Player_AddFrame(BNAV_Player_Handle handle, long entry);
911static int BNAV_Player_AddFrameToFifo(BNAV_Player_Handle handle, long entry);
912static int BNAV_Player_AdvanceIndex(BNAV_Player_Handle handle);
913static BNAV_PktFifoEntry  *BNAV_Player_AddFifoEntry(BNAV_Player_Handle handle);
914static int BNAV_Player_AddSequenceHeader(BNAV_Player_Handle handle, BNAV_Entry *pStartEntry,
915    int btpMode, int display, int skip);
916static int BNAV_Player_AddData(BNAV_Player_Handle handle, uint64_t offset, unsigned long size, unsigned long pts,
917    int btpMode, int display, int skip);
918static int BNAV_Player_AddFrameData(BNAV_Player_Handle handle, BNAV_Entry *pStartEntry);
919static long BNAV_Player_P_FindPictureIndex(BNAV_Player_Handle handle, long startIndex, eSCType picCode, eBpDirectionParam dir);
920
921/* generate commands */
922static void BNAV_Player_GenerateBTP(BNAV_Player_Handle handle, unsigned long *params, unsigned char *pkt, int discarding_tailend);
923static void BNAV_Player_GenerateDummyPicture(BNAV_Player_Handle handle, unsigned char *pkt);
924static void BNAV_Player_GenerateNullPacket(BNAV_Player_Handle handle, unsigned char *pkt);
925static void BNAV_Player_GenerateStartCodePacket(BNAV_Player_Handle handle, unsigned char *pkt, uint8_t startcode);
926
927static int BNAV_Player_GetFifoSize(const BNAV_Player_Handle handle);
928static int BNAV_Player_BuildReferenceFrame_Process(BNAV_Player_Handle handle);
929
930static int BNAV_Player_AddDummyFrame(BNAV_Player_Handle handle, BNAV_Entry *pStartEntry);
931static int BNAV_Player_p_SanityCheck(BNAV_Player_Handle handle);
932
933/* 64 bit support */
934#define getLo64(X) (unsigned long)((X)&0xFFFFFFFF)
935#define getHi64(X) (unsigned long)((X)>>32)
936#define create64(HI,LO) ((((uint64_t)(HI))<<32)|(unsigned long)(LO))
937#define BNAV_Player_get_frameOffset64(PENTRY) \
938    create64(BNAV_get_frameOffsetHi(PENTRY),BNAV_get_frameOffsetLo(PENTRY))
939
940/*! Function Definitions */
941
942/**
943* Auto-detects the NAV table version. If successful, the version is set in bcmplayer's
944* state, and optionally returned through the version parameter (if not NULL).
945*
946* If BNAV_Player_detectNavTableVersion() is not called before
947* the first call to BNAV_Player_getNextPlayEntry(), it will be called
948* automatically.
949*
950* The reason it is not called by BNAV_Player_Allocate() and BNAV_Player_reset()
951* is that the user may want to use a NULL boundsCb and assert the firstIndex and
952* lastIndex. This must be done before auto-detecting the version.
953*
954* Return values:
955* -1 on failure
956* 0 on success
957**/
958static int BNAV_Player_DetectNavTableVersion(BNAV_Player_Handle handle, int isPes);
959
960/* Important: when building general-purpose binaries, always default to the
961* lowest common denominator feature set. */
962static const BNAV_DecoderFeatures g_defaultDecoderFeatures = {1,1,0,0};
963
964void BNAV_Player_GetDefaultSettings(BNAV_Player_Settings *settings)
965{
966    memset(settings, 0, sizeof(*settings));
967    settings->lastIndex = 0x7FFFFFFF; /* this allows autodetect to work, but
968        you might get lots of error messages from readEntry(). */
969    memcpy(&settings->decoderFeatures, &g_defaultDecoderFeatures, sizeof(g_defaultDecoderFeatures));
970    settings->cacheSize = DEFAULT_CACHE_SIZE;
971    settings->normalPlayBufferSize = DEFAULT_NORMAL_PLAY_BUFFER_SIZE;
972    settings->debugMode = BNAV_Player_DebugFramesAndAllPacketsSent;
973    settings->navVersion = BNAV_VersionUnknown;
974    settings->boundsCb = BNAV_Player_DefaultGetBounds;
975    settings->useReferenceFrame = 1; /* true */
976}
977
978int BNAV_Player_Open(BNAV_Player_Handle *handle, const BNAV_Player_Settings *settings)
979{
980    *handle = (BNAV_Player_Handle)malloc(sizeof(struct BNAV_Player_HandleImpl));
981    memset(*handle, 0, sizeof(**handle));
982
983    /* At this point, we are opened. If reset fails, a close must be performed. */
984    if (BNAV_Player_Reset(*handle, settings)) {
985        /* Free everything */
986        BNAV_Player_Close(*handle);
987
988        /* NULLing this is not required, but it may help prevent some application failures */
989        *handle = NULL;
990
991        return -1;
992    }
993
994    return 0;
995}
996
997int BNAV_Player_Reset(BNAV_Player_Handle handle, const BNAV_Player_Settings *settings)
998{
999    int result = 0;
1000    int i;
1001
1002    if (!settings->readCb ||
1003        !settings->seekCb ||
1004        !settings->tellCb ||
1005        !settings->filePointer ||
1006        !settings->cacheSize)
1007    {
1008        BDBG_ERR(("Missing required BNAV_Player_Settings"));
1009        return -1;
1010    }
1011
1012    if (!settings->videoPid) {
1013        BDBG_ERR(("Video PID required"));
1014        return -1;
1015    }
1016
1017    handle->readCb  = settings->readCb;
1018    handle->seekCb  = settings->seekCb;
1019    handle->tellCb  = settings->tellCb;
1020    handle->boundsCb    = settings->boundsCb;
1021    handle->filePointer = settings->filePointer;
1022
1023    switch (settings->navVersion) {
1024    case BNAV_Version_VC1_PES:
1025    case BNAV_Version_AVC: handle->navFileIndexEntrySize = sizeof(BNAV_AVC_Entry); break;
1026    default: handle->navFileIndexEntrySize = sizeof(BNAV_Entry); break;
1027    }
1028    handle->navFileIndexEntryStart = 0;
1029    handle->playMode            = eBpPlayNormal;
1030    handle->playDir             = eBpForward;
1031    handle->advanceCount        = 1;
1032    handle->loopMode            = eBpSinglePlay;
1033    handle->currentIndex        = 0;
1034    handle->pid                 = settings->videoPid;
1035    handle->firstFifoEntry      = 0;
1036    handle->lastFifoEntry       = -1;
1037    handle->curRefFrame         = -1; /* 0 is a valid refframe */
1038    handle->skipNextAdvance     = 0;
1039    handle->currentOffset       = 0;
1040    handle->normalPlayBufferSize    = settings->normalPlayBufferSize;
1041    handle->debugMode           = settings->debugMode;
1042    handle->navVersion          = settings->navVersion;
1043    handle->useReferenceFrame   = settings->useReferenceFrame;
1044    memcpy(&handle->decoderFeatures, &settings->decoderFeatures, sizeof(settings->decoderFeatures));
1045    handle->firstIndex          = settings->firstIndex;
1046    handle->lastIndex           = settings->lastIndex;
1047
1048    handle->ptscache_wptr       = 2;
1049    handle->ptscache_rptr       = 0;
1050    handle->doBackwardPtsSearch = 1;
1051    handle->gopTrick.currentStart = -1;
1052    handle->gopTrick.pictureTag = 0;
1053
1054    for (i=0;i<PTS_CACHE_SIZE;i++)
1055        handle->ptscache[i].index = -1;
1056
1057    if (settings->transportTimestampEnabled) {
1058        handle->timestampOffset = 4;
1059        handle->packetSize = 192;
1060    }
1061    else {
1062        handle->timestampOffset = 0;
1063        handle->packetSize = 188;
1064    }
1065
1066    /* videoPid is required for Broadcom trick modes. */
1067    if (!settings->videoPid)
1068        handle->decoderFeatures.supportsBroadcomTrickModes = 0;
1069
1070    handle->disableExtraBOptimization = 0;
1071
1072    /* this only reallocates the cache if cacheSize or size changes. */
1073    BNAV_Player_SetCacheSize(handle, settings->cacheSize);
1074
1075    if (handle->navVersion == BNAV_VersionUnknown) {
1076        result = BNAV_Player_DetectNavTableVersion(handle, settings->isPes);
1077        if (result) {
1078            BDBG_ERR(("Unable to detect BNAV_Version"));
1079            return -1;
1080        }
1081
1082        /* reset cache for changes */
1083        switch (handle->navVersion) {
1084        case BNAV_Version_VC1_PES:
1085        case BNAV_Version_AVC: handle->navFileIndexEntrySize = sizeof(BNAV_AVC_Entry); break;
1086        default: handle->navFileIndexEntrySize = sizeof(BNAV_Entry); break;
1087        }
1088        BNAV_Player_SetCacheSize(handle, settings->cacheSize);
1089    }
1090    if (handle->navVersion >= BNAV_VersionUnknown) {
1091        BDBG_ERR(("Unknown BNAV_Version: %d", handle->navVersion));
1092        BDBG_ERR(("Hint: Indexes should be in host endianness. If the index is byteswapped, the first symption is a bad version."));
1093        return -1;
1094    }
1095    if (handle->navVersion == 0) {
1096        /* There were a couple months where version 1 indexes were being produced
1097        but we weren't labelling the indexes as such. And a false detect is really
1098        bad. If you need to use version 0 indexes and you know that they really
1099        are correct, feel free to delete this check, but by default it should fail. */
1100        BDBG_ERR(("Unable to support version 0 indexes reliably."));
1101        BDBG_ERR(("Hint: Indexes should be in host endianness. If the index is byteswapped, the first symption is a bad version."));
1102        return -1;
1103    }
1104    if (handle->navVersion == BNAV_Version_VC1_PES) {
1105        /* PES data, no packets */
1106        handle->timestampOffset = 0;
1107        handle->packetSize = 0;
1108    }
1109
1110/* no sanity check for otf */
1111    if (!settings->skipSanityCheck && BNAV_Player_p_SanityCheck(handle)) {
1112        BDBG_ERR(("Internal check of bcm index failed. This is an invalid index. "
1113        "Is it the correct endianness? "
1114        "Please use the printindex utility to verify its integrity."));
1115        return -1;
1116    }
1117
1118    return result;
1119}
1120
1121void BNAV_Player_Close(BNAV_Player_Handle handle)
1122{
1123    if (handle->navCache)
1124        free(handle->navCache);
1125    free(handle);
1126}
1127
1128int BNAV_Player_UpdateBounds(BNAV_Player_Handle handle) {
1129    if (handle->boundsCb)
1130        return (*handle->boundsCb)(handle, handle->filePointer, &handle->firstIndex, &handle->lastIndex);
1131    else
1132        return 0;
1133}
1134
1135/**
1136* This is the only place where the seekCb, tellCb and readCb callbacks are used.
1137* The boundsCb calback is used by BNAV_Player_UpdateBounds().
1138**/
1139BNAV_Entry *BNAV_Player_ReadEntry(BNAV_Player_Handle handle, long index)
1140{
1141    /* We don't want to update the bounds unless we have to (causes seeks that could be slow in some OS's) */
1142    /* If the entries have not been set then set them */
1143    /* We always update the bounds if continuous record (where first moves as buffer wraps) */
1144    if (handle->firstIndex == handle->lastIndex || handle->firstIndex != 0)
1145        BNAV_Player_UpdateBounds(handle);
1146    /* If not in valid range then update the range values (we might be recording and the end has moved) */
1147    if (index < handle->firstIndex || index > handle->lastIndex)
1148        BNAV_Player_UpdateBounds(handle);
1149    /* Test again, if we're still not in range then we're past the end of the file -- done! */
1150    if (index < handle->firstIndex || index > handle->lastIndex) {
1151        BDBG_MSG(("BNAV_Player_ReadEntry failed, index %d, firstIndex %d, lastIndex %d",
1152            index, handle->firstIndex, handle->lastIndex));
1153        return NULL;
1154    }
1155
1156    /* Check if this naventry is in our cache */
1157    if ((handle->navCacheIndexStart == -1)
1158        || !((index >= handle->navCacheIndexStart) && (index < handle->navCacheIndexEnd)))
1159    {
1160        unsigned long saveStart = handle->navCacheIndexStart;
1161        unsigned long saveEnd = handle->navCacheIndexEnd;
1162        unsigned long pos;
1163        long t;
1164
1165        if (index < handle->navCacheIndexStart)
1166        {
1167            /* We are reading indexes backwards so cache backwards */
1168            handle->navCacheIndexStart = index - handle->navCacheSize + handle->navCacheOverlap + 1;
1169        }
1170        else
1171        {
1172            handle->navCacheIndexStart = index - handle->navCacheOverlap;
1173        }
1174
1175        /* need to handle -1 case */
1176        if (handle->navCacheIndexStart < 0)
1177        {
1178            handle->navCacheIndexStart = 0;
1179        }
1180        /* need to handle being outside of trimmed bounds as well*/
1181        if (handle->navCacheIndexStart < handle->firstIndex)
1182        {
1183            handle->navCacheIndexStart = handle->firstIndex;
1184        }
1185
1186        pos = handle->navFileIndexEntryStart + (handle->navCacheIndexStart*handle->navFileIndexEntrySize);
1187        if ((*handle->seekCb)(handle->filePointer, pos, SEEK_SET))
1188            t = -1;
1189        else {
1190            t = (*handle->tellCb)(handle->filePointer);
1191            if (t != -1)
1192                t = (t - handle->navFileIndexEntryStart) / handle->navFileIndexEntrySize;
1193        }
1194        /* We may not get exactly what we asked for, but it may work. */
1195        if (t != -1 && t <= index && t < index + handle->navCacheSize)
1196            handle->navCacheIndexStart = t;
1197        else {
1198            BDBG_WRN(("Seek was invalidated: %ld, %ld", t, index));
1199            handle->navCacheIndexStart = saveStart;
1200            handle->navCacheIndexEnd = saveEnd;
1201            handle->navCacheFails++;
1202            return 0;
1203        }
1204
1205        handle->navCacheIndexEnd = handle->navCacheIndexStart;
1206
1207        /* The end is equal to the start plus whatever we are able to read */
1208        handle->navCacheIndexEnd += (*handle->readCb)(handle->navCache, 1, handle->navFileIndexEntrySize * handle->navCacheSize, handle->filePointer) / handle->navFileIndexEntrySize;
1209
1210        if (index >= handle->navCacheIndexEnd || handle->navCacheIndexEnd == handle->navCacheIndexStart) {
1211            /* The index bounds should prevent this, therefore it is an ERR. */
1212            BDBG_ERR(("Unable to read index: %ld in %ld..%ld",
1213                index, handle->navCacheIndexStart, handle->navCacheIndexEnd));
1214            handle->navCacheFails++;
1215            return 0;
1216        }
1217        handle->navCacheMisses++;
1218    }
1219
1220    handle->navCacheReads++;
1221    return (BNAV_Entry *) &(handle->navCache[(index-handle->navCacheIndexStart) * handle->navFileIndexEntrySize]);
1222}
1223
1224void BNAV_Player_GetStatus(const BNAV_Player_Handle handle, BNAV_Player_Status *status) {
1225    status->fifoSize = BNAV_Player_GetFifoSize(handle);
1226    status->currentIndex = handle->currentIndex;
1227}
1228
1229int BNAV_Player_GetPosition(BNAV_Player_Handle handle, BNAV_Player_Position *position) {
1230    return BNAV_Player_GetPositionInformation(handle, handle->currentIndex, position);
1231}
1232
1233int BNAV_Player_GetPositionInformation(BNAV_Player_Handle handle, long index, BNAV_Player_Position *position) {
1234    BNAV_Entry *pEntry = BNAV_Player_ReadEntry(handle, index);
1235    if (!pEntry)
1236        return -1;
1237
1238    position->index = index;
1239    position->pts = BNAV_get_framePts(pEntry);
1240    position->offsetHi = BNAV_get_frameOffsetHi(pEntry);
1241    position->offsetLo = BNAV_get_frameOffsetLo(pEntry);
1242    position->timestamp = BNAV_get_timestamp(pEntry);
1243    position->vchipState = BNAV_unpack_vchip(BNAV_get_packed_vchip(pEntry));
1244
1245    return 0;
1246}
1247
1248int BNAV_Player_GetNextPlayEntry(BNAV_Player_Handle handle, BNAV_Player_PlayEntry *navEntry, unsigned char *pkt)
1249{
1250    long        startIndex;
1251    BNAV_PktFifoEntry *fifoEntry;
1252
1253    if (BNAV_Player_UpdateBounds(handle))
1254        return BNAV_GENERIC_IDX_FAIL;
1255
1256    if (handle->currentIndex < handle->firstIndex ) {
1257        /* Index file has been trimmed ! */
1258        BDBG_MSG(("currentIndex %lx, first %lx , last %lx , current offset %llx, firstFifoEntry %d, lastFifoEntry %d",
1259            handle->currentIndex, handle->firstIndex, handle->lastIndex, handle->currentOffset, handle->firstFifoEntry,
1260            handle->lastFifoEntry));
1261
1262        if( handle->playMode == eBpPlayNormal) {
1263            /* Tell caller, index has gone away from under us so they can take action */
1264            return BNAV_GENERIC_IDX_FAIL;
1265        }
1266    }
1267
1268    /* If the fifo is empty, allow the algorithm to fill it. If we have even one
1269    entry, allow the app to get it before processing more.
1270    Throughout this loop, any function may fail because of trimming away the beginning/end of file. If this happens, this function should fail. */
1271    while (handle->firstFifoEntry > handle->lastFifoEntry)
1272    {
1273        /* reset the fifo */
1274        handle->firstFifoEntry = 0;
1275        handle->lastFifoEntry = -1;
1276
1277        /* If our BNAV_Player_BuildReferenceFrame_Process was interrupted,
1278        continue it */
1279        if (handle->buildRef.inProcess) {
1280            if (BNAV_Player_BuildReferenceFrame_Process(handle))
1281                return BNAV_GENERIC_IDX_FAIL;
1282            continue;
1283        }
1284
1285        if (handle->playMode == eBpPlayNormal) {
1286            if (BNAV_Player_AddNormalPlay(handle))
1287                return BNAV_GENERIC_IDX_FAIL;
1288        }
1289        else if (handle->playMode == eBpPlayNormalByFrames) {
1290            if (BNAV_Player_AddNormalPlayByFrames(handle))
1291                return BNAV_GENERIC_IDX_FAIL;
1292        }
1293        else {
1294            /* needsDisplayPicture will be set if the last call to BNAV_Player_AddFrameToFifo
1295            results in a BuildReferenceFrame. In that case, another trip round is
1296            required to build the actual display picture, so we don't need to advance
1297            again. */
1298            if (!handle->buildRef.needDisplayPicture) {
1299                if (BNAV_Player_AdvanceIndex(handle))
1300                    return BNAV_ADVANCE_IDX_FAIL;
1301            }
1302
1303            /* now add it to the fifo */
1304            startIndex = handle->currentIndex;
1305            if (handle->playMode == eBpPlayBrcm) {
1306                if (BNAV_Player_AddFrameToFifo(handle, startIndex))
1307                    return BNAV_GENERIC_IDX_FAIL;
1308            }
1309            else {
1310                /* I, IP, SkipB, SkipP - just add the current frame to the fifo */
1311                if (BNAV_Player_AddFrame(handle, startIndex))
1312                    return BNAV_GENERIC_IDX_FAIL;
1313            }
1314        }
1315    }
1316
1317    handle->gotEntry = 1;
1318    navEntry->zeroByteCountBegin = 0;
1319    navEntry->zeroByteCountEnd = 0;
1320    fifoEntry = &handle->pktfifo[handle->firstFifoEntry];
1321
1322    switch (fifoEntry->insertpackettype) {
1323    case eBpInsertStartCode:
1324        navEntry->isInsertedPacket = 1;
1325        BNAV_Player_GenerateStartCodePacket(handle, pkt, fifoEntry->startcode);
1326        break;
1327
1328    case eBpInsertDummy:
1329        navEntry->isInsertedPacket = 1;
1330        BNAV_Player_GenerateDummyPicture(handle, pkt);
1331        break;
1332
1333    case eBpInsertNULL:
1334        navEntry->isInsertedPacket = 1;
1335        BNAV_Player_GenerateNullPacket(handle, pkt);
1336        break;
1337
1338    case eBpInsertBTP:
1339        /* Handle packet insertions */
1340        navEntry->isInsertedPacket = fifoEntry->insertpackettype;   /* For now... */
1341        BNAV_Player_GenerateBTP(handle, fifoEntry->pktdata, pkt,
1342            /* Test if we're discarding the tailend */
1343            (fifoEntry->pktdata[0] == TT_MODE_PROCESS && fifoEntry->pktdata[8] < 188));
1344        break;
1345
1346    case eBpInsertNone:
1347        /* Specify frame data to send */
1348        navEntry->isInsertedPacket = 0;   /* For now... */
1349
1350        navEntry->startOffsetHi = getHi64(fifoEntry->startByte);
1351        navEntry->startOffset = getLo64(fifoEntry->startByte);
1352        navEntry->zeroByteCountBegin = fifoEntry->zeroByteCountBegin;
1353        navEntry->zeroByteCountEnd = fifoEntry->zeroByteCountEnd;
1354        navEntry->byteCount = 1 + getLo64(
1355            fifoEntry->endByte -
1356            fifoEntry->startByte);
1357        break;
1358
1359    default:
1360        BDBG_ERR(("Invalid HITS packet insertion type!"));
1361        return BNAV_GENERIC_IDX_FAIL;
1362    }
1363
1364    /* tell host if this is the last piece of data in the fifo */
1365    if (handle->firstFifoEntry >= handle->lastFifoEntry)
1366        navEntry->isLastEntry = 1;
1367    else
1368        navEntry->isLastEntry = 0;
1369
1370    /* Get next entry */
1371    handle->firstFifoEntry++;
1372
1373    return 0;
1374}
1375
1376void BNAV_Player_FlushFifo(BNAV_Player_Handle handle)
1377{
1378    handle->firstFifoEntry = 0;
1379    handle->lastFifoEntry = -1;
1380    BDBG_MSG(("flush fifo"));
1381}
1382
1383int BNAV_Player_GetFifoSize(const BNAV_Player_Handle handle)
1384{
1385    return (handle->lastFifoEntry+1) - handle->firstFifoEntry;
1386}
1387
1388static int BNAV_Player_AddCurrentToPTSCache(BNAV_Player_Handle handle)
1389{
1390    BNAV_Entry *pEntry;
1391    pEntry = BNAV_Player_ReadEntry(handle, handle->currentIndex);
1392    if (!pEntry)
1393        return -1;
1394    handle->ptscache[handle->ptscache_wptr].pts = BNAV_get_framePts(pEntry);
1395    handle->ptscache[handle->ptscache_wptr].index = handle->currentIndex;
1396    BDBG_MSG_PTSCACHE(("add %ld, %#lx wptr=%d", handle->currentIndex, BNAV_get_framePts(pEntry), handle->ptscache_wptr ));
1397    if (++handle->ptscache_wptr == PTS_CACHE_SIZE)
1398        handle->ptscache_wptr = 0;
1399    return 0;
1400}
1401
1402/**
1403* In normal play, we read ALL data according to a specified size.
1404* However, keep the current index state variable up-to-date.
1405**/
1406static int BNAV_Player_AddNormalPlayByFrames(BNAV_Player_Handle handle)
1407{
1408    uint64_t nextOffset;
1409    BNAV_PktFifoEntry *curFifoEntry;
1410    BNAV_Entry *pEntry;
1411
1412    /* add to the fifo */
1413    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
1414    curFifoEntry->insertpackettype = eBpInsertNone;
1415    curFifoEntry->startByte = handle->currentOffset;
1416
1417#ifdef LOOSE_INDEX_CHECKING
1418retry:
1419#endif
1420    /* find the end of the next frame */
1421    ++handle->currentIndex;
1422    pEntry = BNAV_Player_ReadEntry(handle, handle->currentIndex);
1423    if (!pEntry) {
1424        if (handle->loopMode == eBpSinglePlay)
1425            return -1;
1426
1427        handle->currentIndex = handle->firstIndex;
1428        pEntry = BNAV_Player_ReadEntry(handle, handle->currentIndex);
1429        if (!pEntry)
1430            return -1;
1431    }
1432
1433    if (BNAV_get_frameSize(pEntry) == 0) {
1434        BDBG_ERR(("invalid frame size 0 at index %d", handle->currentIndex));
1435#ifdef LOOSE_INDEX_CHECKING
1436        goto retry;
1437#else
1438        return -1;
1439#endif
1440    }
1441
1442    nextOffset = BNAV_Player_get_frameOffset64(pEntry) + BNAV_get_frameSize(pEntry);
1443    if (handle->packetSize) {
1444        nextOffset -= nextOffset % handle->packetSize;
1445    }
1446
1447    /* feed everything from previous currentOffset to the next currentOffset. drop nothing. */
1448    curFifoEntry->endByte = nextOffset - 1;
1449    handle->currentOffset = curFifoEntry->endByte + 1;
1450
1451    BNAV_Player_AddCurrentToPTSCache(handle);
1452    return 0;
1453}
1454
1455static int BNAV_Player_AddNormalPlay(BNAV_Player_Handle handle)
1456{
1457    uint64_t nextOffset;
1458    BNAV_PktFifoEntry *curFifoEntry;
1459    BNAV_Entry *pEntry;
1460
1461    /* add to the fifo */
1462    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
1463    curFifoEntry->insertpackettype = eBpInsertNone;
1464    curFifoEntry->startByte = handle->currentOffset;
1465
1466    /* find out how much we can read, up to normalPlayBufferSize */
1467    nextOffset = handle->currentOffset;
1468    while ((pEntry = BNAV_Player_ReadEntry(handle, handle->currentIndex))) {
1469        if (BNAV_get_frameSize(pEntry) == 0) {
1470            BDBG_ERR(("invalid frame size 0 at index %d", handle->currentIndex));
1471#ifdef LOOSE_INDEX_CHECKING
1472            handle->currentIndex++;
1473            continue;
1474#else
1475            return -1;
1476#endif
1477        }
1478        nextOffset = BNAV_Player_get_frameOffset64(pEntry) + BNAV_get_frameSize(pEntry);
1479        if (handle->packetSize) {
1480            nextOffset -= nextOffset % handle->packetSize;
1481        }
1482        if (nextOffset > handle->currentOffset + handle->normalPlayBufferSize) {
1483            curFifoEntry->endByte = handle->currentOffset + handle->normalPlayBufferSize - 1;
1484            break;
1485        }
1486        curFifoEntry->endByte = nextOffset - 1;
1487        handle->currentIndex++;
1488        BNAV_Player_AddCurrentToPTSCache(handle);
1489    }
1490
1491    /* do we have something to play? */
1492    if (curFifoEntry->endByte > curFifoEntry->startByte) {
1493        handle->currentOffset = curFifoEntry->endByte + 1;
1494        return 0;
1495    }
1496    else {
1497        /* remove fifo entry - we should only have one entry, so flush will do it. */
1498        BNAV_Player_FlushFifo(handle);
1499
1500        if (handle->loopMode == eBpLoopForever) {
1501            if (!BNAV_Player_UpdateBounds(handle)) {
1502                BNAV_Player_SetCurrentIndex(handle, handle->firstIndex);
1503                return BNAV_Player_AddNormalPlay(handle);
1504            }
1505        }
1506        return -1;
1507    }
1508}
1509
1510static int BNAV_Player_P_FindGOP(BNAV_Player_Handle handle, int num_gops)
1511{
1512    long curIndex = handle->currentIndex;
1513    BNAV_Entry *pStartEntry;
1514
1515    /* if we're starting, get on a GOP */
1516    if (handle->gopTrick.currentStart == -1) {
1517        BNAV_Entry *onePrevEntry = NULL;
1518        BDBG_MSG(("finding GOP"));
1519        while ((pStartEntry = BNAV_Player_ReadEntry(handle, curIndex))) {
1520            if (handle->navVersion == BNAV_Version_AVC){
1521                if (BNAV_get_RandomAccessIndicator((const BNAV_AVC_Entry *)pStartEntry))
1522                    break;
1523            }
1524            else {
1525                if (BNAV_get_frameType(pStartEntry) == eSCTypeIFrame) {
1526                    /* bcmplayer indexes field-encoded streams as two I's. back up and take the first if so. */
1527                    onePrevEntry = BNAV_Player_ReadEntry(handle, curIndex-1);
1528                    if (onePrevEntry && BNAV_get_frameType(onePrevEntry) == eSCTypeIFrame) {
1529                        pStartEntry = onePrevEntry;
1530                        curIndex--;
1531                    }
1532                    else {
1533                        onePrevEntry = NULL;
1534                    }
1535                    break;
1536                }
1537            }
1538            curIndex += handle->playDir;
1539        }
1540        BDBG_MSG(("got %p at %d", pStartEntry, curIndex));
1541        if (!pStartEntry) return -1; /* hit end */
1542
1543        handle->gopTrick.currentStart = curIndex;
1544
1545        /* find GopEnd */
1546        BDBG_MSG(("finding end of GOP"));
1547        if (onePrevEntry) curIndex++;
1548        while ((pStartEntry = BNAV_Player_ReadEntry(handle, ++curIndex))) {
1549            if (handle->navVersion == BNAV_Version_AVC){
1550                if (BNAV_get_RandomAccessIndicator((const BNAV_AVC_Entry *)pStartEntry))
1551                    break;
1552            }
1553            else {
1554                if (BNAV_get_frameType(pStartEntry) == eSCTypeIFrame)
1555                    break;
1556            }
1557        }
1558        BDBG_MSG(("got %p at %d", pStartEntry, curIndex-1));
1559        if (pStartEntry) {
1560            handle->gopTrick.currentEnd = --curIndex;
1561        }
1562        else {
1563            /* if we got a start but not an end, we may be at the end of the file. */
1564            handle->gopTrick.currentEnd = handle->gopTrick.currentStart;
1565            curIndex = handle->gopTrick.currentStart-1;
1566            /* go backward to find the start */
1567            while ((pStartEntry = BNAV_Player_ReadEntry(handle, curIndex))) {
1568                if (handle->navVersion == BNAV_Version_AVC){
1569                    if (BNAV_get_RandomAccessIndicator((const BNAV_AVC_Entry *)pStartEntry))
1570                        break;
1571                }
1572                else {
1573                    if (BNAV_get_frameType(pStartEntry) == eSCTypeIFrame)
1574                        break;
1575                }
1576                curIndex--;
1577            }
1578            if (!pStartEntry) {
1579                BDBG_ERR(("cannot do GOP trick mode on stream without one complete GOP"));
1580                return -1;
1581            }
1582            handle->gopTrick.currentStart = curIndex;
1583        }
1584    }
1585    BDBG_ASSERT(handle->gopTrick.currentStart != -1 && handle->gopTrick.currentEnd != -1);
1586
1587    /* now skip gops */
1588    while (num_gops--) {
1589        if (handle->playDir > 0) {
1590            curIndex = handle->gopTrick.currentEnd;
1591            while ((pStartEntry = BNAV_Player_ReadEntry(handle, ++curIndex))) {
1592                if (handle->navVersion == BNAV_Version_AVC){
1593                    if (BNAV_get_RandomAccessIndicator((const BNAV_AVC_Entry *)pStartEntry))
1594                        break;
1595                }
1596                else {
1597                    if (BNAV_get_frameType(pStartEntry) == eSCTypeIFrame)
1598                        break;
1599                }
1600            }
1601            if (!pStartEntry) return -1; /* hit end */
1602            handle->gopTrick.currentStart = handle->gopTrick.currentEnd;
1603            handle->gopTrick.currentEnd = curIndex;
1604        }
1605        else {
1606            curIndex = handle->gopTrick.currentStart;
1607            while ((pStartEntry = BNAV_Player_ReadEntry(handle, --curIndex))) {
1608                if (handle->navVersion == BNAV_Version_AVC){
1609                    if (BNAV_get_RandomAccessIndicator((const BNAV_AVC_Entry *)pStartEntry))
1610                        break;
1611                }
1612                else {
1613                    if (BNAV_get_frameType(pStartEntry) == eSCTypeIFrame) {
1614                        /* bcmplayer indexes field-encoded streams as two I's. back up and take the first if so. */
1615                        BNAV_Entry *onePrevEntry = BNAV_Player_ReadEntry(handle, curIndex-1);
1616                        if (onePrevEntry && BNAV_get_frameType(onePrevEntry) == eSCTypeIFrame) {
1617                            pStartEntry = onePrevEntry;
1618                            curIndex--;
1619                        }
1620                        break;
1621                    }
1622                }
1623            }
1624            if (!pStartEntry) return -1; /* hit end */
1625            handle->gopTrick.currentEnd = handle->gopTrick.currentStart;
1626            handle->gopTrick.currentStart = curIndex;
1627        }
1628        BDBG_MSG(("GOP at [%d,%d], %d", handle->gopTrick.currentStart, handle->gopTrick.currentEnd, num_gops));
1629    }
1630    BDBG_ASSERT(handle->gopTrick.currentStart != -1 && handle->gopTrick.currentEnd != -1);
1631
1632    return handle->gopTrick.currentStart;
1633}
1634
1635int BNAV_Player_AdvanceIndex(BNAV_Player_Handle handle)
1636{
1637    long        startIndex;
1638    BNAV_Entry *pStartEntry;
1639
1640    /* updateBounds already called from getNextPlayEntry. */
1641    startIndex = handle->currentIndex;
1642    switch(handle->playMode)
1643    {
1644    case eBpPlayDecoderGOPTrick:
1645        /* now advance if we're in the middle of a GOP */
1646        if (handle->gopTrick.currentStart != -1 &&
1647            startIndex != handle->gopTrick.currentEnd )
1648        {
1649            BDBG_MSG(("advance in GOP"));
1650            startIndex++;
1651        }
1652        else
1653        {
1654            BNAV_PktFifoEntry  *curFifoEntry;
1655
1656            /* find a starting GOP or the next GOP */
1657            startIndex = BNAV_Player_P_FindGOP(handle, handle->gopTrick.currentStart == -1 ? 0 : (handle->gopTrick.gopSkip+1));
1658            pStartEntry = BNAV_Player_ReadEntry(handle, startIndex);
1659            if (!pStartEntry) return -1;
1660
1661            /* before sending next I, send a flush command to prevent prediction before I */
1662            curFifoEntry = BNAV_Player_AddFifoEntry(handle);
1663            curFifoEntry->insertpackettype = eBpInsertBTP;
1664            curFifoEntry->pktdata[0] = TT_MODE_INLINE_FLUSH;
1665
1666            /* Insert timing marker indicating the beginning of the next GOP */
1667            curFifoEntry = BNAV_Player_AddFifoEntry(handle);
1668            curFifoEntry->insertpackettype = eBpInsertBTP;
1669            curFifoEntry->pktdata[0] = TT_MODE_PICTURE_TAG;
1670            curFifoEntry->pktdata[9] = handle->gopTrick.pictureTag++;
1671
1672            /* Picture Output "N"  marker
1673            ** AVD will ouput the first 'handle->advanceCount' pictures of this GOP.
1674            */
1675            curFifoEntry = BNAV_Player_AddFifoEntry(handle);
1676            curFifoEntry->insertpackettype = eBpInsertBTP;
1677            curFifoEntry->pktdata[0] = TT_MODE_PIC_OUTPUT_COUNT;
1678            curFifoEntry->pktdata[9] = handle->advanceCount;    /* number of pictures specified by the application */
1679
1680            handle->lastSeqHdrOffset64 = 0;
1681
1682            startIndex = handle->gopTrick.currentStart;
1683
1684        }
1685        break;
1686    case eBpPlayBrcm:
1687        if (handle->playDir == eBpForward)
1688        {
1689            if (!handle->skipNextAdvance)
1690                startIndex = startIndex + handle->advanceCount;
1691            pStartEntry = BNAV_Player_ReadEntry(handle, startIndex);
1692            if (pStartEntry == NULL)
1693            {
1694                if ((handle->loopMode != eBpLoopForever) || (handle->gotEntry == 0))
1695                {
1696                    handle->gotEntry = 1;
1697                    handle->currentIndex = startIndex - handle->advanceCount;
1698                    return -1;
1699                }
1700                handle->gotEntry = 0;   /* Ensure we don't loop more than once without returning */
1701                startIndex = handle->firstIndex; /* Start over from the beginning. */
1702                pStartEntry = BNAV_Player_ReadEntry(handle, startIndex);
1703                if (!pStartEntry) return -1;
1704            }
1705        }
1706        else
1707        {
1708            if (!handle->skipNextAdvance)
1709                startIndex = startIndex - handle->advanceCount;
1710            if (startIndex < 0)
1711                pStartEntry = NULL;
1712            else
1713                pStartEntry = BNAV_Player_ReadEntry(handle, startIndex);
1714            if (pStartEntry == NULL)
1715            {
1716                if ((handle->loopMode != eBpLoopForever) || (handle->gotEntry == 0))
1717                {
1718                    handle->gotEntry = 1;
1719                    handle->currentIndex = startIndex + handle->advanceCount;
1720                    return -1;
1721                }
1722                /* We've reached beginning of stream.  Goto the end. */
1723                handle->gotEntry = 0;   /* Ensure we don't loop more than once without returning */
1724                startIndex = handle->lastIndex;
1725            }
1726        }
1727        break;
1728
1729    case eBpPlayI:
1730    case eBpPlayIP:
1731    case eBpPlaySkipB:
1732    case eBpPlaySkipP:
1733        {
1734            unsigned long tempCount = handle->advanceCount;
1735            int loopAround = 0; /* have we already looped the index */
1736            int keepGoing = 1; /* should we look at the next frame */
1737            long previousIFrame = -1;
1738
1739            while (keepGoing) {
1740                eSCType frameType;
1741
1742                if (handle->skipNextAdvance) {
1743                    /* Only skip the first advance. We have to validate that we're on the
1744                    right kind of frame. */
1745                    handle->skipNextAdvance = 0;
1746                }
1747                else {
1748                    startIndex += handle->playDir;
1749                }
1750                if ((pStartEntry = BNAV_Player_ReadEntry(handle, startIndex)) == NULL)
1751                {
1752                    if (handle->loopMode == eBpSinglePlay) {
1753                        /* if we're not looping, then we need to push out the first/last I frame for a consistent stop */
1754                        if (handle->playMode == eBpPlayI) {
1755                            if (previousIFrame != -1) {
1756                                /* back up and send out the last i frame we skipped */
1757                                startIndex = previousIFrame;
1758                                keepGoing = 0;
1759                                continue;
1760                            }
1761                            else if (handle->iFrameRepeatCount++ < 2) {
1762                                /* repeat the last I frame 2 more times to get through the decoder's pipeline */
1763                                startIndex = handle->currentIndex;
1764                                keepGoing = 0;
1765                                continue;
1766                            }
1767                        }
1768                        /* we're done */
1769                        return -1;
1770                    }
1771
1772                    /* prevent an infinite loop. */
1773                    if (loopAround)
1774                        return -1;
1775
1776                    /* reset startIndex, taking into account the += playDir. */
1777                    if (handle->playDir > 0)
1778                        startIndex = handle->firstIndex - 1;
1779                    else
1780                        startIndex = handle->lastIndex + 1;
1781                    loopAround++;
1782                    continue;
1783                }
1784
1785                frameType = BNAV_get_frameType(pStartEntry);
1786                switch (handle->playMode) {
1787                case eBpPlayIP:
1788                    if (frameType == eSCTypeRPFrame || frameType == eSCTypeIFrame || frameType == eSCTypePFrame) {
1789                        if (!--tempCount)
1790                            keepGoing = 0;
1791                    }
1792                    break;
1793                case eBpPlaySkipB:
1794                    keepGoing = 0;
1795                    if (frameType == eSCTypeBFrame) {
1796                        if (handle->skipCount == handle->advanceCount) {
1797                            handle->skipCount = 0;
1798                            keepGoing = 1;
1799                        }
1800                        else
1801                            handle->skipCount++;
1802                    }
1803                    break;
1804                case eBpPlaySkipP:
1805                    if (frameType == eSCTypeIFrame) {
1806                        keepGoing = 0;
1807                        /* reset skipCount for the next P */
1808                        handle->skipCount = 0;
1809                    }
1810                    else if (frameType == eSCTypePFrame && handle->skipCount != -1) {
1811                        if (handle->skipCount == handle->advanceCount) {
1812                            /* keep going until we hit a I frame */
1813                            handle->skipCount = -1;
1814                        }
1815                        else {
1816                            handle->skipCount++;
1817                            keepGoing = 0;
1818                        }
1819                    }
1820                    break;
1821                case eBpPlayI:
1822                    if (frameType == eSCTypeIFrame) {
1823                        previousIFrame = startIndex;
1824                        if (!--tempCount) {
1825                            /* For field encoded streams, you can get two I pictures which are adjacent to each other.
1826                            For purposes of I frame advanceCount, we should ignore the second I picture.
1827                            This will mess up I-only streams with advanceCount == 1, but that's not really a trick mode
1828                            anyway. */
1829                            if (handle->navVersion == BNAV_Version_AVC && startIndex == handle->currentIndex+1) {
1830                                /* readd to the tempCount and don't set keepGoing */
1831                                tempCount++;
1832                            }
1833                            else {
1834                                keepGoing = 0;
1835                            }
1836                        }
1837                    }
1838                    break;
1839                default:
1840                    break;
1841                }
1842            }
1843        }
1844        break;
1845
1846    default:
1847        break;
1848    }
1849
1850    handle->currentIndex = startIndex;
1851    handle->skipNextAdvance = 0;
1852    BNAV_Player_AddCurrentToPTSCache(handle);
1853    return 0;
1854}
1855
1856/**
1857Feed a frame for non-brcm (host only) based trick mode.
1858**/
1859static int BNAV_Player_AddFrame(BNAV_Player_Handle handle, long entry)
1860{
1861    BNAV_PktFifoEntry  *curFifoEntry;
1862    BNAV_Entry *pStartEntry;
1863    uint64_t seqHdrOffset64;
1864    int result = 0;
1865
1866    BDBG_MSG(("AddFrame %d", entry));
1867
1868    CHECKREAD(pStartEntry = BNAV_Player_ReadEntry(handle, entry));
1869
1870    /* For AVC, send an EOS before every I picture in I frame trick mode to avoid
1871    picture_order_count (poc) reordering. This cannot be used for IP or IPB host trick modes
1872    because the P's and B's might predict before the I. */
1873    if (handle->navVersion == BNAV_Version_AVC && BNAV_get_frameType(pStartEntry) == eSCTypeIFrame &&
1874        handle->playMode == eBpPlayI)
1875    {
1876        curFifoEntry = BNAV_Player_AddFifoEntry(handle);
1877        curFifoEntry->insertpackettype = eBpInsertStartCode;
1878        curFifoEntry->startcode = 0x0A;
1879        /* This will flush the SPS/PPS, so clear the state variable. */
1880        handle->lastSeqHdrOffset64 = 0;
1881    }
1882
1883#ifdef USE_BTPS_FOR_HOST_TRICK_MODES
1884    /* This mode uses BTP packets for host trick modes. This makes for byte-accurate begin/end trims
1885    even with encrypted streams. In this mode, the video decoder must be set to Broadcom Trick Mode
1886    for all trick modes.
1887    */
1888
1889    if (handle->navVersion != BNAV_Version_VC1_PES) {
1890        /* send sequence header if different. for AVC this means just checking the PPS, which is sufficient. */
1891        seqHdrOffset64 = BNAV_Player_get_frameOffset64(pStartEntry) - BNAV_get_seqHdrStartOffset(pStartEntry);
1892        if (handle->packetSize) {
1893            seqHdrOffset64 -= seqHdrOffset64 % handle->packetSize;
1894        }
1895        if (seqHdrOffset64 != handle->lastSeqHdrOffset64)
1896        {
1897            if (BNAV_Player_AddSequenceHeader(handle, pStartEntry, TT_MODE_PROCESS, 0, 0))
1898                return -1;
1899            handle->lastSeqHdrOffset64 = seqHdrOffset64;
1900        }
1901
1902        result = BNAV_Player_AddFrameData(handle, pStartEntry);
1903        if (result) return result;
1904
1905        return result;
1906    }
1907#endif
1908
1909    /* Add fifo entry */
1910    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
1911
1912    curFifoEntry->insertpackettype = eBpInsertNone;
1913
1914    /* back up to TS packet */
1915    curFifoEntry->startByte = BNAV_Player_get_frameOffset64(pStartEntry);
1916    if (handle->packetSize) {
1917        curFifoEntry->startByte -= curFifoEntry->startByte % handle->packetSize;
1918    }
1919
1920    if (handle->navVersion == BNAV_Version_AVC || handle->navVersion == BNAV_Version_VC1_PES) {
1921        BNAV_AVC_Entry *avcEntry = (BNAV_AVC_Entry *)pStartEntry;
1922
1923        /* For AVC host trick modes w/o BTP's, we have to assume the SPS and PPS are adjacent and in
1924        SPS,PPS order. If this isn't true, we'll require BTP's. */
1925
1926        /* Calc the SPS offset */
1927        seqHdrOffset64 = BNAV_Player_get_frameOffset64(pStartEntry) - BNAV_get_SPS_Offset(avcEntry);
1928        if (handle->packetSize) {
1929            seqHdrOffset64 -= seqHdrOffset64 % handle->packetSize;
1930        }
1931    }
1932    else {
1933        /* Calc the seqhdr offset */
1934        seqHdrOffset64 = BNAV_Player_get_frameOffset64(pStartEntry) - BNAV_get_seqHdrStartOffset(pStartEntry);
1935        if (handle->packetSize) {
1936            seqHdrOffset64 -= seqHdrOffset64 % handle->packetSize;
1937        }
1938    }
1939    /* if there's a sequence header in the previous packet (or, for PES streams, close by), also send it */
1940    if (seqHdrOffset64 != handle->lastSeqHdrOffset64 &&
1941        curFifoEntry->startByte - seqHdrOffset64 <= 188 /* This 188 is meant to be hardcoded and not packetSize */)
1942    {
1943        handle->lastSeqHdrOffset64 = seqHdrOffset64;
1944        curFifoEntry->startByte = seqHdrOffset64;
1945    }
1946
1947    /* Now that we know where the read must begin (including possible seqhdr), we can calc the zeroByteCountBegin
1948    so the host can zero out data the decoder shouldn't see */
1949    if (handle->packetSize) {
1950        curFifoEntry->zeroByteCountBegin = (unsigned long)(curFifoEntry->startByte % handle->packetSize);
1951    }
1952
1953    /* set the end feed byte based on actual picture end */
1954    curFifoEntry->endByte = BNAV_Player_get_frameOffset64(pStartEntry) +
1955        BNAV_get_frameSize(pStartEntry);
1956
1957    if (handle->packetSize) {
1958        /* Round end up to nearest transport packet, but tell caller to zero out any bytes after end of picture */
1959        curFifoEntry->zeroByteCountEnd = handle->packetSize - (unsigned long)(curFifoEntry->endByte % handle->packetSize);
1960        if (curFifoEntry->zeroByteCountEnd == handle->packetSize)
1961            curFifoEntry->zeroByteCountEnd = 0;
1962        curFifoEntry->endByte += curFifoEntry->zeroByteCountEnd;
1963    }
1964    curFifoEntry->endByte -= 1; /* sub one since endByte is an offset to the last good byte */
1965
1966    return result;
1967}
1968
1969/**
1970Builds a reference frame.
1971
1972This function has some similar logic to BNAV_Player_AddFrameToFifo, but there
1973are enough differences (especially in handling B frames and various optimizations),
1974that the logic needs to be separated. Building a reference frame is a very simple
1975process. Send all the frames needed to build a complete past predictor and load
1976it into the reference frame buffer.
1977**/
1978static int BNAV_Player_BuildReferenceFrame(BNAV_Player_Handle handle, long entry)
1979{
1980    BNAV_Entry *pStartEntry;
1981    unsigned long rfo;
1982    unsigned long numFrames, lastFrameSize;
1983    int i;
1984    eSCType frametype;
1985    long startingentry;
1986
1987    CHECKREAD_SILENT(pStartEntry = BNAV_Player_ReadEntry(handle, entry));
1988    frametype = BNAV_get_frameType(pStartEntry);
1989    rfo = BNAV_get_refFrameOffset(pStartEntry);
1990
1991    if (handle->navVersion >= BNAV_VersionOpenGopBs && frametype == eSCTypeIFrame) {
1992        /* send the one I frame only, ignore its rfo because it points to
1993        previous GOP */
1994        numFrames = 1;
1995        startingentry = entry;
1996        rfo = 0; /* fake it out */
1997    }
1998    else {
1999        /* Calc how many frames will be sent */
2000        numFrames = 0;
2001        for (i = rfo; i >= 1; i--) {
2002            CHECKREAD_SILENT(pStartEntry = BNAV_Player_ReadEntry(handle, entry - i));
2003            if (BNAV_get_frameType(pStartEntry) != eSCTypeBFrame)
2004                numFrames++;
2005        }
2006        startingentry = entry - rfo;
2007    }
2008
2009    CHECKREAD(pStartEntry = BNAV_Player_ReadEntry(handle, startingentry));
2010    lastFrameSize = BNAV_get_frameSize(pStartEntry);
2011
2012    BDBG_MSG(("BUILD_REFERENCE index=%ld %s, numFrames=%ld",
2013        entry, BNAV_frameTypeStr[BNAV_get_frameType(pStartEntry)], numFrames));
2014    BNAV_Player_AddSequenceHeader(handle, pStartEntry, TT_MODE_BUILD_REFERENCE, 0,
2015#if defined BCHP_7411_VER || B_HAS_RAVE
2016        /* the BUILDREF skip_count is needed for 7411. any picture sent after the skip_count
2017        will be decoded against the refframe and displayed. */
2018        numFrames);
2019#else
2020        /* the original BTP does not count packets, so use 0. Guarav reports that the reference frame is
2021        stored when the next BTP after this arrives. */
2022        0);
2023#endif
2024
2025    /* Add first frame after seqhdr (for I frames, this will be the only frame */
2026    BNAV_Player_AddFrameData(handle, pStartEntry);
2027
2028    /* Set up a process which be interrupted when the fifo fills */
2029    handle->buildRef.inProcess = 1;
2030    handle->buildRef.curOffset = rfo-1;
2031    handle->buildRef.lastFrameSize = lastFrameSize;
2032    handle->buildRef.entry = entry;
2033    return BNAV_Player_BuildReferenceFrame_Process(handle);
2034}
2035
2036/**
2037This is the inner loop inside BNAV_Player_BuildReferenceFrame, but it's implemented
2038using handle->buildRef so that it can be interrupted and resumed. This is necessary
2039to handle large GOP sizes with a fixed size fifo. Otherwise you never know when
2040the next stream might overflow your fifo.
2041**/
2042static int BNAV_Player_BuildReferenceFrame_Process(BNAV_Player_Handle handle)
2043{
2044    /* Now add the rest of the frames for the reference frame */
2045    for (; handle->buildRef.curOffset >= 1; handle->buildRef.curOffset--)
2046    {
2047        BNAV_Entry *pStartEntry;
2048        int frametype;
2049        int index = handle->buildRef.entry - handle->buildRef.curOffset;
2050
2051        /* If we're getting close to filling the fifo, abort. We'll resume
2052        later. The required gap must be >= the maximum number of entries that may
2053        be generated.
2054        That is: seqhdr = 4, frame = 4
2055        */
2056        if (handle->lastFifoEntry >= MAX_NUM_FIFO_ENTRIES - 8) {
2057            BDBG_MSG(("Interrupting BNAV_Player_BuildReferenceFrame_Process %ld, %ld...",
2058                handle->firstFifoEntry, handle->lastFifoEntry));
2059            return 0;
2060        }
2061
2062        CHECKREAD(pStartEntry = BNAV_Player_ReadEntry(handle, index));
2063        frametype = BNAV_get_frameType(pStartEntry);
2064
2065        if (handle->buildRef.lastFrameSize > BNAV_get_seqHdrStartOffset(pStartEntry))
2066        {
2067            BNAV_Player_AddSequenceHeader(handle, pStartEntry, TT_MODE_PROCESS, 0, 0);
2068        }
2069
2070        /* add only non-B frames until we get to the end */
2071        if (frametype != eSCTypeBFrame)
2072        {
2073            BDBG_MSG(("  %d: %s", index, BNAV_frameTypeStr[frametype]));
2074            BNAV_Player_AddFrameData(handle, pStartEntry);
2075        }
2076        handle->buildRef.lastFrameSize = BNAV_get_frameSize(pStartEntry);
2077    }
2078
2079    /* This is now our current reference frame */
2080    handle->curRefFrame = handle->buildRef.entry;
2081    handle->buildRef.inProcess = 0;
2082
2083    return 0;
2084}
2085
2086/**
2087Add a frame for brcm trick mode.
2088
2089If a reference frame needs to be built, this function will exit early and state
2090variables will be set to come back and complete the work on another pass.
2091This adds command packets as needed. One call to this function will generate
2092all of the fifo entries needed to display a frame.
2093**/
2094static int BNAV_Player_AddFrameToFifo(BNAV_Player_Handle handle, long entry)
2095{
2096    BNAV_Entry *pStartEntry;
2097    unsigned long rfo;
2098    unsigned long numFrames = 0, lastFrameSize;
2099    int i;
2100    eSCType frametype;
2101    int extraBFrames = 0;
2102    long startingentry;
2103
2104    CHECKREAD_SILENT(pStartEntry = BNAV_Player_ReadEntry(handle, entry));
2105    rfo = BNAV_get_refFrameOffset(pStartEntry);
2106    frametype = BNAV_get_frameType(pStartEntry);
2107    BDBG_MSG(("%ld: %s", entry, BNAV_frameTypeStr[frametype]));
2108
2109    /* Check if we need a reference frame. If we're restricted from
2110    building a reference, this must be handled differently later on. */
2111    if (handle->useReferenceFrame) {
2112        /* Check if our GOP size is too large. If so, subdivide it. This keeps
2113        bandwidth requirements limited. Some GOP's are known to be 90 frames or more. */
2114        if (rfo > MAX_REFERENCE_FRAME_OFFSET) {
2115            BDBG_MSG((" subdividing GOP, org rfo %ld, refframe %ld", rfo, entry-rfo));
2116            rfo = rfo % MAX_REFERENCE_FRAME_OFFSET;
2117            if (!rfo) rfo = MAX_REFERENCE_FRAME_OFFSET;
2118
2119            /* back up to nearest I or P frame */
2120            while(1) {
2121                CHECKREAD_SILENT(pStartEntry = BNAV_Player_ReadEntry(handle, entry - rfo));
2122                if (BNAV_get_frameType(pStartEntry) == eSCTypeBFrame)
2123                    rfo++;
2124                else
2125                    break;
2126            };
2127            BDBG_MSG((" subdividing GOP, final rfo %ld, refframe %ld", rfo, entry-rfo));
2128        }
2129/* Causes playback to freeze in BCM mode, take out */
2130#if 0
2131        /* initial I frames (rfo == 0) are useless to send for display. They are only good
2132        for references frames. */
2133        if (!rfo)
2134            return -1;
2135#endif
2136
2137        /* build a reference frame if needed */
2138        if (handle->curRefFrame != (int)(entry - rfo))
2139        {
2140            handle->buildRef.needDisplayPicture = 1;
2141            if (BNAV_Player_BuildReferenceFrame(handle, entry - rfo) == -1) {
2142                handle->buildRef.needDisplayPicture = 0;
2143                return -1;
2144            }
2145
2146            /* TODO: I'm using disableExtraBOptimization as a marker for when we're in
2147            host-based frame reverse mode. In this case, we need to build reference and
2148            display a picture in one pass. We should rename this variable. */
2149            if (!handle->disableExtraBOptimization) {
2150                /* By always exiting, we make the processing path the same, whether
2151                the BuildReferenceFrame was interrupted or not. This also keeps fifo
2152                requirements smaller because the reference frame will be processed
2153                completely before the displayed picture will be processed. */
2154                return 0;
2155            }
2156        }
2157        handle->buildRef.needDisplayPicture = 0;
2158    }
2159
2160    /* Figure out our starting point. This may be from a reference frame
2161    or not. */
2162    if (handle->navVersion >= BNAV_VersionOpenGopBs &&
2163        handle->useReferenceFrame)
2164    {
2165        CHECKREAD_SILENT(pStartEntry = BNAV_Player_ReadEntry(handle, entry - rfo));
2166        if (BNAV_get_frameType(pStartEntry) == eSCTypeIFrame) {
2167            /* Don't send the I frame again, so advance to the next non-B frame. */
2168            do {
2169                rfo--;
2170                CHECKREAD_SILENT(pStartEntry = BNAV_Player_ReadEntry(handle, entry - rfo));
2171            } while (BNAV_get_frameType(pStartEntry) == eSCTypeBFrame && rfo > 0);
2172
2173            /* If there's no additional frames to send, then we (unfortunately)
2174            have to resend the reference frame. */
2175            if (rfo == 0)
2176                rfo = BNAV_get_refFrameOffset(pStartEntry);
2177        }
2178    }
2179    else if (!handle->useReferenceFrame) {
2180        /* If we're doing no reference frame, we need to back up further to
2181        get a complete picture. This is essentially saving memory (one less
2182        buffer needed by decoder) at the price of more bandwidth. */
2183        CHECKREAD_SILENT(pStartEntry = BNAV_Player_ReadEntry(handle, entry - rfo));
2184        if (BNAV_get_frameType(pStartEntry) != eSCTypeIFrame) {
2185            rfo += BNAV_get_refFrameOffset(pStartEntry);
2186        }
2187    }
2188
2189    /* Figure out how many frames were going to have to send after this BTP */
2190    for (i = rfo; i >= 0; i--)
2191    {
2192        CHECKREAD_SILENT(pStartEntry = BNAV_Player_ReadEntry(handle, entry - i));
2193        frametype = BNAV_get_frameType(pStartEntry);
2194        if (frametype != eSCTypeBFrame || i == 0)
2195            numFrames++;
2196
2197        /**
2198        * See if there are extra B frames we can send because they predict off the
2199        * same frames. See playertypes.h for discussion.
2200        * NOTE: I don't support the forward direction because you would only realize
2201        * a gain with a GOP format of >2 B's between I/P's, but maybe someone could use it.
2202        * Likewise, I don't support >1x rewind because this would require the same GOP
2203        * format. Maybe someday.
2204        **/
2205        if (frametype == eSCTypeBFrame &&
2206            handle->playDir < 0 && handle->advanceCount == 1 && /* 1x rewind only */
2207            handle->decoderFeatures.supportsCombiningBs && /* firmware must support */
2208            !handle->disableExtraBOptimization /* must be enabled by app */
2209            )
2210        {
2211            if (i != 0)
2212                extraBFrames++;
2213        }
2214        else {
2215            extraBFrames = 0;
2216        }
2217    }
2218
2219    /* startingentry is the first frame to be sent in this sequence */
2220    startingentry = entry - rfo;
2221
2222    CHECKREAD(pStartEntry = BNAV_Player_ReadEntry(handle, startingentry));
2223    lastFrameSize = BNAV_get_frameSize(pStartEntry);
2224    frametype = BNAV_get_frameType(pStartEntry);
2225    /*BDBG_ASSERT(frametype != eSCTypeBFrame);*/
2226
2227    if (handle->playDir > 0)
2228    {
2229        BDBG_MSG(("DISPLAY %d, %ld", 1, numFrames - 1));
2230        BNAV_Player_AddSequenceHeader(handle, pStartEntry, TT_MODE_DISPLAY_FORWARD, 1, numFrames - 1);
2231    }
2232    else
2233    {
2234        /**
2235        * If we're going in reverse and our current entry matches what's in the future
2236        * prediction buffer, then we can display the past prediction buffer.
2237        **/
2238        if (handle->decoderFeatures.supportsDisplayPastBuffer &&
2239            handle->navVersion >= BNAV_VersionOpenGopBs &&
2240            handle->playDir == eBpReverse &&
2241/* TODO: This is hanging the driver/firmware for 3x rewind where alignment is such
2242that no B frames are sent. */
2243            /* (handle->futurePred == entry || frametype == eSCTypeIFrame)) */
2244            handle->futurePred == entry)
2245        {
2246            rfo = 0; /* this will force AddDummyFrame, and that's all we need */
2247            /* TODO: Why is a dummy frame needed after DISPLAY_PAST_BUFFER? */
2248            if (!handle->decoderFeatures.supportsDummyPicture) {
2249                BDBG_ERR(("DisplayPastBuffer requires DummyPicture"));
2250            }
2251
2252            /* the one display frame isn't really needed. But we'll do that later. */
2253            BDBG_MSG(("DISPLAY_PAST_BUFFER %d, %d", 1 + extraBFrames, 0));
2254            BNAV_Player_AddSequenceHeader(handle, pStartEntry, TT_MODE_DISPLAY_PAST_BUFFER, 1 + extraBFrames, 0);
2255        }
2256        else {
2257            BDBG_MSG(("DISPLAY %d, %ld", 1 + extraBFrames, numFrames - 1));
2258            BNAV_Player_AddSequenceHeader(handle, pStartEntry, TT_MODE_DISPLAY_REWIND, 1 + extraBFrames, numFrames - 1);
2259        }
2260    }
2261    /* the prediction frames are invalid at this point */
2262    handle->pastPred = handle->futurePred = -1;
2263
2264    /* The reason we have this unconditional AddFrame is that we've already sent the PROCESS
2265    BTP with the AddSequenceHeader. The possible subsequent AddFrame's in the for loop will
2266    generate new PROCESS BTP's. */
2267    if (rfo == 0 && handle->decoderFeatures.supportsDummyPicture) {
2268        BDBG_MSG(("  %ld: %s (dummy)", startingentry, BNAV_frameTypeStr[frametype]));
2269        BNAV_Player_AddDummyFrame(handle, pStartEntry);
2270    }
2271    else {
2272        BDBG_MSG(("  %ld: %s", startingentry, BNAV_frameTypeStr[frametype]));
2273        BNAV_Player_AddFrameData(handle, pStartEntry);
2274    }
2275
2276    for (i = rfo-1; i >= 0; i--)
2277    {
2278        CHECKREAD(pStartEntry = BNAV_Player_ReadEntry(handle, entry - i));
2279        frametype = BNAV_get_frameType(pStartEntry);
2280
2281        if (lastFrameSize > BNAV_get_seqHdrStartOffset(pStartEntry))
2282        {
2283            BNAV_Player_AddSequenceHeader(handle, pStartEntry, TT_MODE_PROCESS, 0, 0);
2284        }
2285
2286        lastFrameSize = BNAV_get_frameSize(pStartEntry);
2287
2288        /**
2289        * If we're in buildmode, add only non-B frames.
2290        * If we're not in buildmode, add only non-B frames until we get to the end,
2291        * then add a B-frame.
2292        **/
2293        if (frametype != eSCTypeBFrame || i == 0)
2294        {
2295            if (i == 0 && frametype != eSCTypeBFrame && handle->decoderFeatures.supportsDummyPicture) {
2296                BDBG_MSG(("  %ld: %s (dummy)", entry-i, BNAV_frameTypeStr[frametype]));
2297                BNAV_Player_AddDummyFrame(handle, pStartEntry);
2298            }
2299            else {
2300                BDBG_MSG(("  %ld: %s", entry-i, BNAV_frameTypeStr[frametype]));
2301                BNAV_Player_AddFrameData(handle, pStartEntry);
2302            }
2303
2304            /* remember what's in the prediction frames */
2305/* TODO: The dummy frame goes into the future prediction buffer. If it didn't,
2306then we could use that past prediction buffer. */
2307            if (frametype != eSCTypeBFrame) {
2308                handle->pastPred = handle->futurePred;
2309                handle->futurePred = entry-i;
2310            }
2311        }
2312    }
2313
2314    /* send any previous B's that predict against the same frames. */
2315    for (i=1; i<=extraBFrames; i++) {
2316        CHECKREAD(pStartEntry = BNAV_Player_ReadEntry(handle, entry - i));
2317        BNAV_Player_AddFrameData(handle, pStartEntry);
2318    }
2319
2320    /* advance the current index because we sent some extra B's */
2321    if (extraBFrames)
2322        handle->currentIndex -= extraBFrames;
2323
2324    return 0;
2325}
2326
2327
2328/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2329+ INPUTS:   None.
2330+ OUTPUTS:  None.
2331+ RETURNS:  new FIFO entry for playback, NULL if failure
2332+ FUNCTION: This function allocates a new FIFO entry and adds it to the end
2333+           of the FIFO.
2334+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
2335static BNAV_PktFifoEntry *BNAV_Player_AddFifoEntry(BNAV_Player_Handle handle)
2336{
2337    BNAV_PktFifoEntry *p_fifo;
2338
2339    handle->lastFifoEntry++;
2340    if (handle->lastFifoEntry >= MAX_NUM_FIFO_ENTRIES)
2341    {
2342        BDBG_ERR(("bcmplayer ERROR: fifo full!"));
2343        return NULL;
2344    }
2345    p_fifo = &(handle->pktfifo[handle->lastFifoEntry]);
2346
2347    /* Initialize values that may not otherwise get initialized in code */
2348    p_fifo->zeroByteCountBegin = 0;
2349    p_fifo->zeroByteCountEnd = 0;
2350#if defined BCHP_7411_VER
2351    memset(p_fifo->pktdata, 0xFF, sizeof(p_fifo->pktdata));
2352#else
2353    memset(p_fifo->pktdata, 0x00, sizeof(p_fifo->pktdata));
2354#endif
2355
2356    return p_fifo;
2357}
2358
2359static int BNAV_Player_SendData(BNAV_Player_Handle handle,
2360    unsigned long picStartByte, /* index of first byte in first packet for this picture */
2361    unsigned long picEndByte, /* index of last byte in last packet for this picture */
2362    uint64_t feedStartByte, /* packet-aligned absolute offset to start of data */
2363    uint64_t feedEndByte,   /* packet-aligned absolute offset to last byte of data */
2364    unsigned long pts,
2365    int mode, int display, int skip)
2366{
2367#if defined BCHP_7411_VER
2368/**
2369For 7411C/D, the PROCESS command is always used to send all mpeg data.
2370**/
2371    int data_end_packet;
2372    int data_end_byte = picEndByte + 1 - handle->timestampOffset; /* convert to total bytes to keep in packet */
2373    int send_dummy_packet = 0;
2374    BNAV_PktFifoEntry *curFifoEntry;
2375
2376    BSTD_UNUSED(pts);
2377    BSTD_UNUSED(mode);
2378    BSTD_UNUSED(skip);
2379    BSTD_UNUSED(display);
2380
2381    /* Send a command packet */
2382    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
2383    curFifoEntry->insertpackettype = eBpInsertBTP;
2384    curFifoEntry->pktdata[0] = TT_MODE_PROCESS;    /* MODE */
2385    curFifoEntry->pktdata[4] = 0xFFFF0000 |
2386        (picStartByte - handle->timestampOffset);  /* DATA_START_BYTE */
2387    data_end_packet = feedEndByte/handle->packetSize - feedStartByte/handle->packetSize + 1;
2388
2389    /* If DATA_END_PACKET is 1 or 3, we have to change it to 2 or 4 and add
2390    a NULL packet. This is to prevent incorrect start code detection
2391    by the 7411C hardware. We add the NULL packet before the payload because of a nice fluke in the
2392    implementation. If we add the NULL packet after the data, the data_end_byte will not apply, and the host is unable
2393    to clear the end of the packet to the exact byte because of possible PVR encryption. If
2394    we add the NULL packet before the data, we would expect the same problem to shift to the beginning, but it doesn't
2395    because the hardware happens to only apply the data_start_byte to the next packet with the same PID. So
2396    it just happens to work fine. */
2397    if (data_end_packet == 1 || data_end_packet == 3) {
2398        data_end_packet++;
2399        send_dummy_packet = 1;
2400    }
2401    /* DATA_END_PACKET - this is count of total packets.  */
2402    curFifoEntry->pktdata[5] = 0xFF000000 | data_end_packet;
2403    /* DATA_END_BYTE - this is a count of total bytes in the last packet */
2404    curFifoEntry->pktdata[6] = 0xFFFF0000 | data_end_byte;
2405    curFifoEntry->pktdata[7] = 0xFFFF0000; /* content type */
2406
2407    if ( ((pts>>8)&0xFF) == 0x01 || ((pts>>8)&0xFF) == 0x03)
2408        pts += 0x00000100;
2409    curFifoEntry->pktdata[9] = pts; /* PTS */
2410
2411    if (send_dummy_packet) {
2412        curFifoEntry = BNAV_Player_AddFifoEntry(handle);
2413        curFifoEntry->insertpackettype = eBpInsertNULL;
2414    }
2415
2416    /* Send the entire frame data */
2417    curFifoEntry = BNAV_Player_AddFifoEntry(handle);
2418    curFifoEntry->insertpackettype = eBpInsertNone;
2419
2420    curFifoEntry->startByte = feedStartByte;
2421    curFifoEntry->endByte = feedEndByte;
2422
2423    return 0;
2424#elif B_HAS_RAVE
2425/**
2426Original BTP format
2427Different BTP modes are used to send data. Multi-packet blocks require two BTP's, one for the block minus one packet, and
2428one for the last packet. This is because the video transport engine does not count packets.
2429**/
2430    BNAV_PktFifoEntry  *curFifoEntry;
2431
2432    BSTD_UNUSED(mode);
2433    BSTD_UNUSED(skip);
2434    BSTD_UNUSED(display);
2435
2436    /* Send a command packet */
2437    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
2438    curFifoEntry->insertpackettype = eBpInsertBTP;
2439    curFifoEntry->pktdata[0] = TT_MODE_PROCESS;    /* MODE */
2440
2441    if (feedEndByte - feedStartByte < handle->packetSize)
2442    {
2443        curFifoEntry->pktdata[7] = picStartByte - handle->timestampOffset;  /* DISCARD_HEADEND */
2444#if BCHP_CHIP == 7401 && BCHP_VER == BCHP_VER_A0
2445/* 7401 A0 PROCESS BTP is broken for discard_tailend field. Instead, zero out trailing data. This
2446will be fixed on B0. This workaround will not work for encrypted streams. */
2447        curFifoEntry->pktdata[8] = 188;
2448#else
2449        curFifoEntry->pktdata[8] = picEndByte + 1 - handle->timestampOffset;  /* DISCARD_TAILEND */
2450#endif
2451        curFifoEntry->pktdata[9] = pts;  /* PTS */
2452
2453        /* Send the single-packet frame data */
2454        curFifoEntry = BNAV_Player_AddFifoEntry(handle);
2455        curFifoEntry->insertpackettype = eBpInsertNone;
2456        curFifoEntry->startByte = feedStartByte;
2457#if BCHP_CHIP == 7401 && BCHP_VER == BCHP_VER_A0
2458        curFifoEntry->zeroByteCountEnd = handle->packetSize - (picEndByte + 1)  - handle->timestampOffset;
2459#endif
2460        curFifoEntry->endByte = feedEndByte;
2461        return 0;
2462    }
2463
2464    curFifoEntry->pktdata[7] = picStartByte - handle->timestampOffset;  /* DISCARD_HEADEND */
2465    curFifoEntry->pktdata[8] = 188;  /* DISCARD_TAILEND */
2466    curFifoEntry->pktdata[9] = pts;  /* PTS */
2467
2468    /* Send the frame data minus the final packet */
2469    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
2470    curFifoEntry->insertpackettype = eBpInsertNone;
2471    curFifoEntry->startByte = feedStartByte;
2472    curFifoEntry->endByte = feedEndByte - handle->packetSize;
2473
2474    if (picEndByte == handle->packetSize - 1)
2475    {
2476        /* we're sending more than one packet, but our last byte comes at the end of the packet. so we're done */
2477        curFifoEntry->endByte = curFifoEntry->endByte + handle->packetSize;
2478        return 0;
2479    }
2480
2481    /* Fragmented final packet-->send a command packet */
2482    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
2483    curFifoEntry->insertpackettype = eBpInsertBTP;
2484    curFifoEntry->pktdata[0] = TT_MODE_PROCESS;   /* MODE */
2485    curFifoEntry->pktdata[7] = 0;  /* DISCARD_HEADEND */
2486#if BCHP_CHIP == 7401 && BCHP_VER == BCHP_VER_A0
2487    curFifoEntry->pktdata[8] = 188;
2488#else
2489    curFifoEntry->pktdata[8] = picEndByte + 1 - handle->timestampOffset;  /* DISCARD_TAILEND */
2490#endif
2491    curFifoEntry->pktdata[9] = pts;  /* PTS */
2492
2493    /* Send the final packet */
2494    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
2495    curFifoEntry->insertpackettype = eBpInsertNone;
2496    curFifoEntry->startByte = feedEndByte - (handle->packetSize - 1);
2497#if BCHP_CHIP == 7401 && BCHP_VER == BCHP_VER_A0
2498    curFifoEntry->zeroByteCountEnd = handle->packetSize - (picEndByte + 1) - handle->timestampOffset;
2499#endif
2500    curFifoEntry->endByte = feedEndByte;
2501    return 0;
2502#else
2503/**
2504Original BTP format
2505Different BTP modes are used to send data. Multi-packet blocks require two BTP's, one for the block minus one packet, and
2506one for the last packet. This is because the video transport engine does not count packets.
2507**/
2508    BNAV_PktFifoEntry  *curFifoEntry;
2509
2510    /* Send a command packet */
2511    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
2512    curFifoEntry->insertpackettype = eBpInsertBTP;
2513    curFifoEntry->pktdata[0] = mode;        /* BTP type */
2514    curFifoEntry->pktdata[1] = skip;        /* SKIP_COUNT */
2515    curFifoEntry->pktdata[2] = display;     /* DISPLAY_COUNT */
2516
2517    if (feedEndByte - feedStartByte < handle->packetSize)
2518    {
2519        curFifoEntry->pktdata[7] = picStartByte - handle->timestampOffset;  /* DISCARD_HEADEND */
2520        curFifoEntry->pktdata[8] = picEndByte + 1 - handle->timestampOffset;  /* DISCARD_TAILEND */
2521        curFifoEntry->pktdata[9] = pts;  /* PTS */
2522
2523        /* Send the single-packet frame data */
2524        curFifoEntry = BNAV_Player_AddFifoEntry(handle);
2525        curFifoEntry->insertpackettype = eBpInsertNone;
2526        curFifoEntry->startByte = feedStartByte;
2527        curFifoEntry->endByte = feedEndByte;
2528        return 0;
2529    }
2530    curFifoEntry->pktdata[7] = picStartByte - handle->timestampOffset;  /* DISCARD_HEADEND */
2531    curFifoEntry->pktdata[8] = 188;  /* DISCARD_TAILEND */
2532    curFifoEntry->pktdata[9] = pts;  /* PTS */
2533
2534    /* Send the frame data minus the final packet */
2535    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
2536    curFifoEntry->insertpackettype = eBpInsertNone;
2537    curFifoEntry->startByte = feedStartByte;
2538    curFifoEntry->endByte = feedEndByte - handle->packetSize;
2539
2540    if (picEndByte == handle->packetSize - 1)
2541    {
2542        /* we're sending more than one packet, but our last byte comes at the end of the packet. so we're done */
2543        curFifoEntry->endByte = curFifoEntry->endByte + handle->packetSize;
2544        return 0;
2545    }
2546
2547    /* Fragmented final packet-->send a command packet */
2548    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
2549    curFifoEntry->insertpackettype = eBpInsertBTP;
2550    curFifoEntry->pktdata[0] = TT_MODE_PROCESS;   /* MODE */
2551    curFifoEntry->pktdata[7] = 0;  /* DISCARD_HEADEND */
2552    curFifoEntry->pktdata[8] = picEndByte + 1 - handle->timestampOffset;  /* DISCARD_TAILEND */
2553    curFifoEntry->pktdata[9] = pts;  /* PTS */
2554
2555    /* Send the final packet */
2556    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
2557    curFifoEntry->insertpackettype = eBpInsertNone;
2558    curFifoEntry->startByte = feedEndByte - (handle->packetSize - 1);
2559    curFifoEntry->endByte = feedEndByte;
2560    return 0;
2561#endif
2562}
2563
2564/* take a byte-accurate offset and size and compute the packet-aligned offsets and the starting point
2565in the first packet and ending point in the last packet. then call SendData which is responsible for
2566creating the BTP's to get the work done. */
2567static int BNAV_Player_AddData(BNAV_Player_Handle handle, uint64_t offset, unsigned long size, unsigned long pts, int btpMode,
2568    int display, int skip)
2569{
2570    unsigned long packet_start_byte, packet_end_byte;
2571    uint64_t end_offset = offset + size - 1; /* index of last byte */
2572
2573    /* handle transport packet alignment */
2574    packet_start_byte = (unsigned long)(offset % handle->packetSize);
2575    packet_end_byte = (unsigned long)(end_offset % handle->packetSize);
2576    offset -= packet_start_byte;    /* set start byte of data to feed */
2577    end_offset += handle->packetSize - packet_end_byte - 1; /* set end byte of data to feed */
2578
2579#ifndef USE_BTPS_FOR_HOST_TRICK_MODES
2580    /* This is a helpful technique, but should be unnecessary. Instead of trimming the beginning of the first packet,
2581    we can chose to send the whole packet. For many (but not all) streams, this will allow other data like the PES header,
2582    MPEG2 seqhdr or AVC SPS/PPS to be sent. This shouldn't be needed because the PTS should be set via the BTP and the seqhdr
2583    should be indexed and sent separately.
2584    PR 16794 - This is still required for legacy platforms. */
2585    if (handle->playMode != eBpPlayBrcm) {
2586        packet_start_byte = 0;
2587    }
2588#endif
2589
2590    BDBG_ASSERT((end_offset + 1) % handle->packetSize == 0);
2591    BDBG_ASSERT(offset % handle->packetSize == 0);
2592
2593    return BNAV_Player_SendData(handle, packet_start_byte, packet_end_byte, offset, end_offset, pts, btpMode, display, skip);
2594}
2595
2596/**
2597Add a single frame (picture) to the fifo. Use whatever BTP's are necessary to get it decoded.
2598**/
2599static int BNAV_Player_AddFrameData(BNAV_Player_Handle handle, BNAV_Entry *pStartEntry)
2600{
2601    return BNAV_Player_AddData(handle,
2602        BNAV_Player_get_frameOffset64(pStartEntry),
2603        BNAV_get_frameSize(pStartEntry),
2604        BNAV_get_framePts(pStartEntry),
2605        TT_MODE_PROCESS, 0, 0);
2606}
2607
2608static int BNAV_Player_AddDummyFrame(BNAV_Player_Handle handle, BNAV_Entry *pStartEntry)
2609{
2610    BNAV_PktFifoEntry  *curFifoEntry;
2611    unsigned long       pts = BNAV_get_framePts(pStartEntry);
2612
2613    /* PROCESS BTP - only one is needed because the picture is only one packet */
2614    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
2615    curFifoEntry->insertpackettype = eBpInsertBTP;
2616    curFifoEntry->pktdata[0] = TT_MODE_PROCESS;    /* MODE */
2617#if defined BCHP_7411_VER
2618    curFifoEntry->pktdata[4] = 0xFFFF0000|0;  /* DATA_START_BYTE */
2619    curFifoEntry->pktdata[5] = 0xFF000000|2;  /* DATA_END_PACKET */
2620    curFifoEntry->pktdata[6] = 0xFFFF0000|188;  /* DATA_END_BYTE */
2621    curFifoEntry->pktdata[7] = 0xFFFF0000|0;  /* CONTENT_TYPE */
2622
2623    if ( ((pts>>8)&0xFF) == 0x01 || ((pts>>8)&0xFF) == 0x03)
2624        pts += 0x00000100;
2625    curFifoEntry->pktdata[9] = pts; /* PTS */
2626
2627    curFifoEntry = BNAV_Player_AddFifoEntry(handle);
2628    curFifoEntry->insertpackettype = eBpInsertNULL;
2629#else
2630    curFifoEntry->pktdata[7] = 0;  /* DISCARD_HEADEND */
2631    curFifoEntry->pktdata[8] = 188;  /* DISCARD_TAILEND */
2632    curFifoEntry->pktdata[9] = pts;
2633#endif
2634
2635    /* one packet picture */
2636    curFifoEntry = BNAV_Player_AddFifoEntry(handle);
2637    curFifoEntry->insertpackettype = eBpInsertDummy;
2638    return 0;
2639}
2640
2641/**
2642Send a BTP mode command which is always followed by a seqhdr.
2643If mode == TT_MODE_PROCESS, then this is not really a BTP mode command. It is just sending a seqhdr.
2644**/
2645int BNAV_Player_AddSequenceHeader(BNAV_Player_Handle handle, BNAV_Entry *pStartEntry,
2646    int btpMode, int display, int skip)
2647{
2648    if (handle->navVersion == BNAV_Version_AVC || handle->navVersion == BNAV_Version_VC1_PES) {
2649        /* send SPS and PPS, for now, every time */
2650        uint64_t sps_offset, pps_offset;
2651        unsigned long sps_size, pps_size, pts;
2652        BNAV_AVC_Entry *avcEntry = (BNAV_AVC_Entry *)pStartEntry;
2653
2654        sps_offset = BNAV_Player_get_frameOffset64(pStartEntry) - BNAV_get_SPS_Offset(avcEntry);
2655        sps_size = BNAV_get_SPS_Size(avcEntry);
2656        pps_offset = BNAV_Player_get_frameOffset64(pStartEntry) - BNAV_get_seqHdrStartOffset(pStartEntry);
2657        pps_size = BNAV_get_seqHdrSize(pStartEntry);
2658
2659        /* at the beginning of a stream, we might have some SPS or PPS indexes with no data. We can't
2660        decode these frames. */
2661        if (!sps_size || !pps_size) return -1;
2662
2663        pts = BNAV_get_framePts(pStartEntry);
2664        if (sps_offset + sps_size == pps_offset) {
2665            /* send both together */
2666            BNAV_Player_AddData(handle, sps_offset, sps_size + pps_size, pts, 0, 0, 0);
2667        }
2668        else {
2669            /* send separately */
2670            BNAV_Player_AddData(handle, sps_offset, sps_size, pts, 0, 0, 0);
2671            BNAV_Player_AddData(handle, pps_offset, pps_size, pts, 0, 0, 0);
2672        }
2673    }
2674    else {
2675        uint64_t offset = BNAV_Player_get_frameOffset64(pStartEntry) - BNAV_get_seqHdrStartOffset(pStartEntry);
2676        unsigned long size = BNAV_get_seqHdrSize(pStartEntry);
2677
2678        if (!size) return -1;
2679
2680#if defined BCHP_7411_VER
2681        if (btpMode != TT_MODE_PROCESS) {
2682            BNAV_PktFifoEntry  *curFifoEntry;
2683            /* If not a PROCESS command, then send the BTP command separately from the seqhdr data. */
2684            CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
2685            curFifoEntry->insertpackettype = eBpInsertBTP;
2686            curFifoEntry->pktdata[0] = btpMode;   /* MODE */
2687            if (btpMode != TT_MODE_DISPLAY_PAST_BUFFER) {
2688                curFifoEntry->pktdata[1] = 0xFFFF0000 | skip;     /* SKIP_COUNT */
2689                if (btpMode != TT_MODE_BUILD_REFERENCE) {
2690                    curFifoEntry->pktdata[2] = 0xFFFF0000 | display;   /* DISPLAY_COUNT */
2691                    curFifoEntry->pktdata[9] = BNAV_get_framePts(pStartEntry);
2692                }
2693            }
2694        }
2695#elif B_HAS_RAVE
2696        if (btpMode != TT_MODE_PROCESS) {
2697            BNAV_PktFifoEntry  *curFifoEntry;
2698            /* If not a PROCESS command, then send the BTP command separately from the seqhdr data. */
2699            CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
2700            curFifoEntry->insertpackettype = eBpInsertBTP;
2701            curFifoEntry->pktdata[0] = btpMode;   /* MODE */
2702            curFifoEntry->pktdata[1] = skip;     /* SKIP_COUNT */
2703            curFifoEntry->pktdata[2] = display;   /* DISPLAY_COUNT */
2704            curFifoEntry->pktdata[9] = BNAV_get_framePts(pStartEntry);
2705        }
2706#endif
2707
2708        BNAV_Player_AddData(handle, offset, size, BNAV_get_framePts(pStartEntry), btpMode, display, skip);
2709    }
2710    return 0;
2711}
2712
2713/****************
2714The following "Generate" functions are called at GetNextPlayEntry time
2715when the internal fifo is consumed.
2716**/
2717
2718/**
2719Generate a 1 packet dummy picture. Write it to memory pointed to by pkt parameter.
2720**/
2721static void BNAV_Player_GenerateDummyPicture(BNAV_Player_Handle handle, unsigned char *pkt)
2722{
2723    static const unsigned char dummy_picture[] = {
2724        0x00, 0x00, 0x01, 0x00, 0x00, 0x09, 0x57, 0xa8,
2725        0x00, 0x00, 0x01, 0xb5, 0x8f, 0xff, 0xff, 0x1c, /* The 0xB5 extension is required for field-encoded MPEG2 brcm trick modes.
2726                                                           It will cause a problem with MPEG1 streams. If we encounter MPEG1 streams,
2727                                                           we may need to extend the API to get bcmplayer more information. */
2728        0x00, 0x00, 0x01, 0x01, 0x2a, 0x8b, 0xf0, 0xe4,
2729        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2730    };
2731
2732    pkt[handle->timestampOffset+0] = 0x47;   /* SYNC BYTE */
2733    pkt[handle->timestampOffset+1] = (handle->pid >> 8) & 0x1f;
2734    pkt[handle->timestampOffset+2] = handle->pid & 0xff;  /* PID */
2735    pkt[handle->timestampOffset+3] = 0x30; /* not scrambled, adaptation_field then payload, 0 continuity counter */
2736    pkt[handle->timestampOffset+4] = 188 - 5 - sizeof( dummy_picture ); /* leave only 32 bytes of payload */
2737    pkt[handle->timestampOffset+5] = 0x82;
2738    memset(&pkt[handle->timestampOffset+6], 0, 188-6-sizeof(dummy_picture) ); /* zero out adaptation field */
2739    memcpy(&pkt[handle->timestampOffset+188-sizeof(dummy_picture)], dummy_picture, sizeof(dummy_picture)); /* copy dummy picture */
2740}
2741
2742/**
2743Generate a null packet. Write it to memory pointed to by pkt parameter.
2744**/
2745static void BNAV_Player_GenerateNullPacket(BNAV_Player_Handle handle, unsigned char *pkt)
2746{
2747    memset(pkt, 0, handle->packetSize);
2748    pkt[handle->timestampOffset+0] = 0x47;   /* SYNC BYTE */
2749    pkt[handle->timestampOffset+1] = 0;
2750    pkt[handle->timestampOffset+2] = 0;     /* zero pid so it doesn't get filtered out */
2751    pkt[handle->timestampOffset+3] = 0x10; /* not scrambled, not adaptation field, 0 continuity counter */
2752}
2753
2754/**
2755Generate a packet with a single start code.
2756**/
2757static void BNAV_Player_GenerateStartCodePacket(BNAV_Player_Handle handle, unsigned char *pkt, uint8_t startcode)
2758{
2759    pkt[handle->timestampOffset+0] = 0x47;   /* SYNC BYTE */
2760    pkt[handle->timestampOffset+1] = (handle->pid >> 8) & 0x1f;
2761    pkt[handle->timestampOffset+2] = handle->pid & 0xff;  /* PID */
2762    pkt[handle->timestampOffset+3] = 0x30; /* not scrambled, adaptation_field then payload, 0 continuity counter */
2763    pkt[handle->timestampOffset+4] = 188-5-4; /* leave only 4 bytes of payload */
2764    memset(&pkt[handle->timestampOffset+5], 0, 188-5-4); /* zero out adaptation field */
2765    pkt[handle->timestampOffset+184] = 0x00;
2766    pkt[handle->timestampOffset+185] = 0x00;
2767    pkt[handle->timestampOffset+186] = 0x01;
2768    pkt[handle->timestampOffset+187] = startcode;
2769}
2770
2771/**
2772Generate a BTP packet. Write it to memory pointed to by pkt parameter.
2773**/
2774void BNAV_Player_GenerateBTP(BNAV_Player_Handle handle, unsigned long *params, unsigned char *pkt,
2775    int discarding_tailend)
2776{
2777    unsigned i;
2778
2779    pkt[handle->timestampOffset+0] = 0x47;   /* SYNC BYTE */
2780    pkt[handle->timestampOffset+1] = (handle->pid >> 8) & 0x1f;
2781    pkt[handle->timestampOffset+2] = handle->pid & 0xff;  /* PID */
2782    pkt[handle->timestampOffset+3] = 0x20; /* not scrambled, adaptation_field and no payload, 0 continuity counter */
2783    pkt[handle->timestampOffset+4] = 0xb7; /* adaptation field length is 183 - the remainder of the packet */
2784    if (discarding_tailend)
2785        pkt[handle->timestampOffset+5] = 0x02; /* don't set discontinuity_indicator in this condition */
2786    else
2787        pkt[handle->timestampOffset+5] = 0x82;
2788    pkt[handle->timestampOffset+6] = 45; /* Number of relevant bytes */
2789    pkt[handle->timestampOffset+7] = 0x00;  /* Align byte */
2790    pkt[handle->timestampOffset+8] = 0x42;  /* B */
2791    pkt[handle->timestampOffset+9] = 0x52;  /* R */
2792    pkt[handle->timestampOffset+10] = 0x43; /* C */
2793    pkt[handle->timestampOffset+11] = 0x4d; /* M */
2794    for(i=0; i<10; ++i)
2795    {
2796        int base = handle->timestampOffset + 12 + i*4;
2797        pkt[base] = (unsigned char) ((params[i] & 0xff000000) >> 24);
2798        pkt[base+1] = (unsigned char) ((params[i] & 0x00ff0000) >> 16);
2799        pkt[base+2] = (unsigned char) ((params[i] & 0x0000ff00) >> 8);
2800        pkt[base+3] = (unsigned char) (params[i] & 0x000000ff);
2801    }
2802    for(i=handle->timestampOffset+52; i<handle->packetSize; ++i)
2803    {
2804        pkt[i] = 0x00;
2805    }
2806}
2807
2808/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2809+ INPUTS:   handle = pointer to a previously allocated sBcmPlayer structure
2810+           startIndex = index in stream to begin search
2811+           startCode = start code type to search for
2812+           dir = direction to search
2813+ OUTPUTS:  None.
2814+ RETURNS:  SCT index matching this start code type
2815+ FUNCTION: This function searches the SCT table for a matching start code.
2816+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
2817long BNAV_Player_FindStartCodeIndex(BNAV_Player_Handle handle, long startIndex, eSCType startCode, eBpDirectionParam dir)
2818{
2819    BNAV_Entry      *pEntry;
2820    char            startCodeFound = 0;
2821
2822    while (!startCodeFound)
2823    {
2824        CHECKREAD(pEntry = BNAV_Player_ReadEntry(handle, startIndex));
2825
2826        if (startCode == eSCTypeUnknown)
2827        {
2828            startCodeFound = 1;
2829        }
2830        else if (BNAV_get_frameType(pEntry) == startCode)
2831        {
2832            startCodeFound = 1;
2833        }
2834        else
2835        {
2836            startIndex += dir;
2837        }
2838    }
2839
2840    return startIndex;
2841}
2842
2843static long BNAV_Player_P_FindPictureIndex(BNAV_Player_Handle handle, long startIndex, eSCType picCode, eBpDirectionParam dir)
2844{
2845    eBpDirectionParam searchDir = dir;
2846
2847    while (1)
2848    {
2849        BNAV_Entry *pEntry;
2850        eSCType frametype;
2851
2852        pEntry = BNAV_Player_ReadEntry(handle, startIndex);
2853        if (!pEntry)
2854        {
2855            /* TODO: please consider moving this switch of direction to the app. I don't think it's general case. */
2856            if (searchDir == dir)
2857            {
2858                startIndex -= dir;      /* go back one and switch directions */
2859                searchDir = (eBpDirectionParam)(dir * -1);
2860                continue;
2861            }
2862            else
2863            {
2864                return -1;              /* no match found */
2865            }
2866        }
2867
2868        frametype = BNAV_get_frameType(pEntry);
2869        if ((picCode == eSCTypeIFrame && frametype == eSCTypeRPFrame) ||
2870            (picCode == eSCTypeRPFrame && frametype == eSCTypeIFrame))
2871        {
2872            /* If we're looking for I and find RP, or vice versa, bail out because
2873            we may never find the right one. This isn't good for a mixed
2874            HITS/GOP-based stream, but there's no way to handle this well. */
2875            BDBG_WRN(("BNAV_Player_P_FindPictureIndex: detected HITS/GOP-based mismatch."));
2876            return -1;
2877        }
2878        if (picCode == eSCTypeUnknown || frametype == picCode)
2879        {
2880            break;
2881        }
2882        else
2883        {
2884            startIndex += dir;
2885        }
2886    }
2887    return startIndex;
2888}
2889
2890#define DISPLAY_ORDER_SEARCH_THRESHOLD  7   /* Set to value that exceeds number of B frames between I and P */
2891                        /* Seven will work with up to 5 B's between the I and P         */
2892                        /* Need this because when searching forward for a P frame, we   */
2893                        /* will go past B's that are in the future before the P. If we  */
2894                        /* set "read ptr" to position of P, the B's behind it will no   */
2895                        /* longer be searchable, resulting in a full cache search       */
2896
2897#define PTS_JITTER          0x110   /* Decoder may return PTS value +/- X of the value to be found in the cache */
2898                        /* if this value is too low, cache search will reject the best candidate    */
2899                        /* and potentially end up searching the whole cache.                        */
2900                        /* Empirical testing has shown a PTS jitter of 0x100 occurs occaisionally   */
2901
2902#define MIN_GOP_THRESHHOLD      1800*18 /* target window for identifying an all same PTS GOP - setto 18 PAL frames  */
2903
2904#define BRCM_CONVERGE_THRESHHOLD    1800*4  /* -X BRCM trick modes often return PTS values that were not added to the   */
2905                        /* cache. This will cause a full ( time consuming ) cache search and still  */
2906                        /* no matching entry will be found.                                         */
2907                        /* Set this to max PTS difference between targetPTS and PTS found in cache  */
2908                        /* you are willing to accept as a close match.                              */
2909                        /* Change to higher value if long cache searches are found in -Brcm trick   */
2910
2911#define BRCM_DIVERGE_THRESHHOLD     1800*9  /* Similar to BRCM_CONVERGE_THRESHHOLD above.                               */
2912                        /* But, this is a "moving away" watermark. That is mindiff holds how close  */
2913                        /* we got to targetPts, current diff holds how far we have moved away from  */
2914                        /* targetPTS. Set this value too low, and it will falsely find close matches*/
2915                        /* when a better match does exist. Too high and it "wastes" time searching  */
2916                        /* away from close match. Initially best to set high                        */
2917
2918 #define ABS_DIFF( a, b ) ( (a) > (b) ? (a) - (b) : (b) - (a) )
2919
2920void BNAV_Player_SetBackwardPtsCacheSearch( BNAV_Player_Handle handle ) {
2921
2922    handle->doBackwardPtsSearch = 1;
2923}
2924
2925static int countFramesWithSamePts( BNAV_Player_Handle handle, int endPtr, int directionInc, int inRangeIndex, uint32_t mindiff, int *j, uint32_t *gopDiff ) {
2926    int samePtsFrames = 0;
2927    int gopLoops=1;
2928
2929    *gopDiff = -1;
2930
2931oneMoreTime:
2932    while( handle->ptscache[*j].pts == handle->ptscache[inRangeIndex].pts ) {
2933        samePtsFrames++;
2934        if( *j == endPtr ) break;
2935        *j+=directionInc;
2936        if( *j < 0 || *j >= PTS_CACHE_SIZE ) *j = directionInc==1?0:PTS_CACHE_SIZE-1;
2937    }
2938    if( gopLoops && handle->ptscache[*j].pts != handle->ptscache[inRangeIndex].pts ) {
2939        *gopDiff = ABS_DIFF( handle->ptscache[*j].pts , handle->ptscache[inRangeIndex].pts );
2940    }
2941
2942    if( directionInc < 0 && gopLoops ) {
2943        gopLoops--;
2944        if( mindiff > *gopDiff ) {
2945            /* When searching backwards through same PTS gop's, mindiff     */
2946            /* will bring us within range 1 gop too soon, we need to keep   */
2947            /* Keep traversing gop(s) until mindiff is less than gopDiff    */
2948            mindiff -= *gopDiff;
2949            gopLoops++;
2950        }
2951        inRangeIndex = *j;
2952        samePtsFrames=0;
2953        goto oneMoreTime;
2954    }
2955    else {
2956        *j = inRangeIndex;      /* point back to beginning of GOP */
2957    }
2958
2959    if( !gopLoops && handle->ptscache[*j].pts != handle->ptscache[inRangeIndex].pts ) {
2960        /* gopLoops will go to zero on a reverse search, at which time "*j"     */
2961        /* will point to the next GOP, so back up one                           */
2962        *j = *j+(directionInc*-1);
2963        /* coverity[dead_error_line: FALSE] */
2964        /* coverity[dead_error_condition: FALSE] */
2965        if( *j < 0 || *j >= PTS_CACHE_SIZE ) *j = directionInc==1?0:PTS_CACHE_SIZE-1;
2966    }
2967
2968    return samePtsFrames;
2969}
2970
2971long BNAV_Player_FindIndexFromPts(BNAV_Player_Handle handle, unsigned long targetPts, int searchWindow)
2972{
2973    uint32_t mindiff = 0xFFFFFFFF; /* max value */
2974    long index = -1;
2975    int i,directionInc;
2976    int samePtsFrames=0;
2977    int inRangeIndex=-1,backOff;
2978    int startPtr=0, endPtr=0;
2979    uint32_t diff;
2980    int oldrptr = handle->ptscache_rptr;
2981
2982    BSTD_UNUSED(searchWindow);
2983
2984    if( handle->doBackwardPtsSearch  ) {
2985        handle->doBackwardPtsSearch = 0;
2986        /* Search backwards after decoder flush */
2987        directionInc = -1;
2988        startPtr = handle->ptscache_wptr - 1;
2989        if( startPtr < 0 ) startPtr = PTS_CACHE_SIZE-1;
2990        endPtr = handle->ptscache_wptr;
2991    }
2992    else {
2993        directionInc = 1;
2994        endPtr = handle->ptscache_wptr - 1;
2995        if( endPtr < 0 ) endPtr = PTS_CACHE_SIZE-1;
2996        startPtr = handle->ptscache_rptr;
2997    }
2998
2999
3000    backOff = DISPLAY_ORDER_SEARCH_THRESHOLD;
3001    if( handle->playMode == eBpPlayBrcm ) backOff += 3;
3002
3003    for (i = startPtr; i != endPtr; i+=directionInc ) {
3004
3005        if ( i < 0 || i >= PTS_CACHE_SIZE ) {
3006            i = directionInc==1?-1:PTS_CACHE_SIZE;
3007            continue;
3008        }
3009
3010        if (handle->ptscache[i].index == -1) continue;
3011
3012        /* abs diff */
3013        diff = ABS_DIFF( handle->ptscache[i].pts , targetPts );
3014
3015        /* look for min and remember the index */
3016        if (diff < mindiff) {
3017            mindiff = diff;
3018            index = handle->ptscache[i].index;
3019            if( mindiff <= MIN_GOP_THRESHHOLD ) inRangeIndex = i;
3020
3021            /* if close match, we're done now */
3022            if (mindiff < PTS_JITTER ) {
3023                handle->ptscache_rptr = i - backOff;
3024                if( handle->ptscache_rptr < 0 ) handle->ptscache_rptr += PTS_CACHE_SIZE;
3025                break;
3026            }
3027        }
3028        else if ( inRangeIndex != -1 ) {
3029            /* diff is no longer less than mindiff and we have previously got within MIN_GOP_THRESHHOLD of  */
3030            /* targetPTS. But haven't got close enough of a match ( < PTS_JITTER ) to stop searching.       */
3031            /* This happens in the following cases :                                                        */
3032            /*      All frames in the GOP have been encoded with the same PTS                               */
3033            /*      Avc streams which have duplicate PTS I/P frames etc                                     */
3034            /*      in -X Brcm trickmodes, decoder returns a PTS not in the cache.                          */
3035            if( handle->playMode == eBpPlayI ) {
3036                /* Don't attempt interpolation - we are assuming at least I frames have different PTS's */
3037                /*   - exception to this is field encoded AVC streams which may have an odd and even    */
3038                /*     I frame encoded with same PTS.                                                   */
3039                if ( mindiff <= BRCM_CONVERGE_THRESHHOLD && diff > BRCM_DIVERGE_THRESHHOLD ) {
3040                    /* This is needed for case where interpolated PTS are coming back from decoder */
3041                    handle->ptscache_rptr = i - backOff;
3042                    if( handle->ptscache_rptr < 0 ) handle->ptscache_rptr += PTS_CACHE_SIZE;
3043                    break;
3044                }
3045                continue;
3046            }
3047
3048            if( handle->ptscache[i].pts == handle->ptscache[inRangeIndex].pts ) {
3049                uint32_t ptsDiff=0xffffffff, gopDiff=0;
3050                /* We have a GOP with all frames having same PTS, need to interpolate */
3051                /* count Nr of frames in same PTS GOP, and return start of GOP in "i" */
3052                samePtsFrames = countFramesWithSamePts( handle, endPtr, directionInc, inRangeIndex, mindiff, &i, &gopDiff );
3053
3054                index = handle->ptscache[i].index;
3055
3056                ptsDiff = ABS_DIFF( handle->ptscache[i].pts , targetPts );
3057
3058                if( ptsDiff ) index += ptsDiff / ( gopDiff/samePtsFrames );
3059
3060                handle->ptscache_rptr = i - backOff;
3061                if( handle->ptscache_rptr < 0 ) handle->ptscache_rptr += PTS_CACHE_SIZE;
3062                mindiff = 0;    /* we've interpolated so, suppress any warning's that could arise */
3063                break;
3064
3065            }
3066            else {
3067                /* This is not a same PTS GOP, but we don't have a close match                          */
3068                /* Will normally hit this code in -X BRCM modes when the decoder outputs PTS's          */
3069                /* which haven't been added to the cache, but are X frames away from the closest        */
3070                /* match we have in the cache.                                                          */
3071                /* This code will trap those values and stop searching once the current difference      */
3072                /* has exceeded the set threshhold.                                                     */
3073                if ( mindiff <= BRCM_CONVERGE_THRESHHOLD && diff > BRCM_DIVERGE_THRESHHOLD ) {
3074                    handle->ptscache_rptr = i - backOff;
3075                    if( handle->ptscache_rptr < 0 ) handle->ptscache_rptr += PTS_CACHE_SIZE;
3076                    break;
3077                }
3078            }
3079        }
3080    }
3081
3082#if BDBG_DEBUG_BUILD
3083    {
3084    int depth = i - handle->ptscache_rptr;
3085    if (depth < 0)
3086        depth += PTS_CACHE_SIZE;
3087
3088    BDBG_MSG_PTSCACHE(("Got idx: %ld rp: %d wp: %d tgt PTS: (0x%8x), diff: %#x, cache depth: %d ", index, handle->ptscache_rptr, handle->ptscache_wptr, targetPts ,mindiff, depth ));
3089    }
3090#endif
3091
3092    /* If things don't work out right, put out some error messages. */
3093    if (mindiff == 0xFFFFFFFF) {
3094        BDBG_ERR(("No PTS in cache"));
3095        goto error;
3096    }
3097    else if (mindiff >= 100000) {
3098        BDBG_ERR(("Invalid PTS %#x. %d Nearest PTS was %#x.", targetPts, mindiff, targetPts+mindiff));
3099        goto error;
3100    }
3101    else if (mindiff > ( MIN_GOP_THRESHHOLD + PTS_JITTER ) ) {
3102        BDBG_ERR(("Couldn't find PTS %#x. %d Nearest was %#x. Are all PTS's in GOP the same ? May need to adjust MIN_GOP_THRESHHOLD", targetPts, mindiff, targetPts+mindiff));
3103        goto error;
3104    }
3105    else if (mindiff >= (BRCM_CONVERGE_THRESHHOLD + PTS_JITTER ) ) {
3106        BDBG_MSG_PTSCACHE(("Couldn't find PTS %#x. %d Nearest was %#x. In -x Brcm mode ? May need to adjust CONVERGE_THRESHHOLD", targetPts, mindiff, targetPts+mindiff));
3107        goto error;
3108    }
3109
3110    return index;
3111
3112error:
3113    handle->ptscache_rptr = oldrptr;
3114    return -1;
3115}
3116
3117/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3118+ INPUTS:   handle = pointer to a previously allocated sTsPlayer structure
3119+           offsetHi = upper 32 bits of the search offset
3120+           offset = lower 32 bits of the search offset
3121+ OUTPUTS:  None.
3122+ RETURNS:  SCT index covering this byte offset. -1 if seeks fail.
3123+ FUNCTION: This function searches the SCT table for an entry that corresponding
3124+           to the specified byte offset.  If the byte offset is less than the
3125+           offset of the first entry if will return the first entry.  If the
3126+           offset is greater than the offset of the last entry, it will return
3127+           the last entry.
3128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
3129long BNAV_Player_FindIndexFromOffset(BNAV_Player_Handle handle,
3130    unsigned long offsetHi, unsigned long offsetLow)
3131{
3132    BNAV_Entry  *pEntry;
3133    char            entryFound = 0;
3134    long            index;
3135    int             dir = 0;
3136    uint64_t        offset, firstByteOffset, lastByteOffset, testOffset = 0;
3137    BNAV_Entry *first, *last;
3138    int count = 0;
3139
3140    offset = create64(offsetHi, offsetLow);
3141
3142    /* get first and last byte offset of mpeg */
3143    if (BNAV_Player_UpdateBounds(handle))
3144        return -1;
3145    CHECKREAD(first = BNAV_Player_ReadEntry(handle, handle->firstIndex))
3146    firstByteOffset = BNAV_Player_get_frameOffset64(first);
3147    CHECKREAD(last = BNAV_Player_ReadEntry(handle, handle->lastIndex))
3148    lastByteOffset = BNAV_Player_get_frameOffset64(last);
3149
3150    /* check bounds */
3151    if (firstByteOffset >= offset)
3152        return handle->firstIndex;
3153    if (offset >= lastByteOffset)
3154        return handle->lastIndex;
3155
3156    /**
3157    * interpolate to an index
3158    *
3159    * Here's the straightforward math for clarity:
3160    *
3161    * index = (long)(((offset - firstByteOffset) / (float)(lastByteOffset - firstByteOffset) *
3162    *   (handle->lastIndex - handle->firstIndex)) + handle->firstIndex;
3163    *
3164    * Here's support for no native 64 bit type:
3165    **/
3166#ifdef HAVE_FLOAT
3167    {
3168    uint64_t temp1, temp2;
3169    float temp3;
3170
3171    temp1 = lastByteOffset - firstByteOffset;
3172    temp2 = offset - firstByteOffset;
3173    temp3 = ((float)temp2) / temp1;
3174    index = (long)(temp3 * (handle->lastIndex - handle->firstIndex)) + handle->firstIndex;
3175    }
3176#else
3177    {
3178    uint64_t temp1, temp2, temp3;
3179    temp1 = lastByteOffset - firstByteOffset;
3180    temp2 = offset - firstByteOffset;
3181    temp3 = handle->lastIndex - handle->firstIndex;
3182    /* reduce the terms before doing the interpolation to prevent overflow. */
3183    while (temp2 > 100000000) {
3184        temp2 /= 2;
3185        temp1 /= 2;
3186    }
3187    while (temp3 > 100000000) {
3188        temp3 /= 2;
3189        temp1 /= 2;
3190    }
3191    if (temp1 == 0) {
3192        temp3 = 0;
3193    }
3194    else {
3195        temp3 = temp3 * temp2 / temp1;
3196    }
3197    index = (unsigned long)temp3 + handle->firstIndex;
3198    }
3199#endif
3200
3201    /* linear search */
3202    while (!entryFound) {
3203        CHECKREAD_SILENT(pEntry = BNAV_Player_ReadEntry(handle, index))
3204
3205        testOffset = BNAV_Player_get_frameOffset64(pEntry);
3206        if (testOffset > offset)
3207        {
3208            if (dir == 0)
3209                dir = -1;
3210            if (dir > 0)
3211            {
3212                entryFound = 1;
3213                /* back up one */
3214                index -= dir;
3215            }
3216            else
3217                index += dir;
3218        }
3219        else
3220        {
3221            if (dir == 0)
3222                dir = 1;
3223            if (dir < 0)
3224                entryFound = 1;
3225            else
3226                index += dir;
3227        }
3228        count++;
3229    }
3230
3231    BDBG_MSG(("IndexFromOffset, %d loops, diff %ld", count,
3232        (unsigned long)(testOffset - offset)));
3233    return index;
3234}
3235
3236/**
3237* IndexFromTimestamp has identical logic to IndexFromOffset
3238**/
3239long BNAV_Player_FindIndexFromTimestamp(BNAV_Player_Handle handle, unsigned long timestamp)
3240{
3241    BNAV_Entry  *pEntry;
3242    char            entryFound = 0;
3243    long            index;
3244    int             dir = 0;
3245    unsigned long firstTimestamp, lastTimestamp, testTimestamp = 0;
3246    BNAV_Entry *first, *last;
3247    int count = 0;
3248
3249    /* get first and last timestamp of mpeg */
3250    if (BNAV_Player_UpdateBounds(handle))
3251        return -1;
3252    CHECKREAD(first = BNAV_Player_ReadEntry(handle, handle->firstIndex))
3253    firstTimestamp = BNAV_get_timestamp(first);
3254    CHECKREAD(last = BNAV_Player_ReadEntry(handle, handle->lastIndex))
3255    lastTimestamp = BNAV_get_timestamp(last);
3256
3257    BDBG_MSG(("IndexFromTimestamp: timestamps %ld,%ld,%ld",
3258        firstTimestamp,timestamp,lastTimestamp));
3259
3260    /* check bounds */
3261    if (firstTimestamp >= timestamp)
3262        return handle->firstIndex;
3263    if (timestamp >= lastTimestamp)
3264        return handle->lastIndex;
3265
3266    /* interpolate to an index */
3267#ifdef HAVE_FLOAT
3268    index = (long)(((timestamp - firstTimestamp) / (float)(lastTimestamp - firstTimestamp)) *
3269        (handle->lastIndex - handle->firstIndex)) + handle->firstIndex;
3270#else
3271    {
3272        /*
3273        a 1 hour recording will have a lastTimestamp of 1000 * 60 * 60 = 3,600,000.
3274        at 30 fps, a 1 hour recording will have a lastIndex of 30 * 60 * 60 = 108,000.
3275        we can reduce these terms before doing the interpolation to prevent overflow.
3276        */
3277        unsigned timestampPartDiff = timestamp - firstTimestamp;
3278        unsigned timestampWholeDiff = lastTimestamp - firstTimestamp;
3279        unsigned indexDiff = handle->lastIndex - handle->firstIndex;
3280        /* reduce timestamp first because it increases faster */
3281        while (timestampPartDiff > 65535) {
3282            timestampPartDiff /= 2;
3283            timestampWholeDiff /= 2;
3284        }
3285        while (indexDiff > 100000) {
3286            indexDiff /= 2;
3287            timestampWholeDiff /= 2;
3288        }
3289        if (timestampWholeDiff == 0) {
3290            index = handle->firstIndex;
3291        }
3292        else {
3293            index = (timestampPartDiff * indexDiff / timestampWholeDiff) + handle->firstIndex;
3294        }
3295    }
3296#endif
3297
3298    BDBG_MSG(("IndexFromTimestamp: indexes %ld,%ld,%ld, cur %ld",
3299        handle->firstIndex,index,handle->lastIndex,handle->currentIndex));
3300    if ((index == handle->firstIndex) || (index == handle->lastIndex)) {
3301        /* Shortcut if this is a boundary condition */
3302        return index;
3303    }
3304    /* linear search */
3305    while (!entryFound) {
3306        CHECKREAD(pEntry = BNAV_Player_ReadEntry(handle, index))
3307
3308        testTimestamp = BNAV_get_timestamp(pEntry);
3309        if (testTimestamp > timestamp)
3310        {
3311            if (dir == 0)
3312                dir = -1;
3313            if (dir > 0)
3314            {
3315                entryFound = 1;
3316                /* back up one */
3317                index -= dir;
3318            }
3319            else
3320                index += dir;
3321        }
3322        else if (testTimestamp == timestamp)
3323        {
3324            entryFound = 1;
3325        }
3326        else
3327        {
3328            if (dir == 0)
3329                dir = 1;
3330            if (dir < 0)
3331                entryFound = 1;
3332            else
3333                index += dir;
3334        }
3335        count++;
3336    }
3337
3338    BDBG_MSG(("IndexFromTimestamp, %d loops, diff %ld, index %ld", count, testTimestamp - timestamp, index));
3339    return index;
3340}
3341
3342void BNAV_Player_PrintCachePerformance(const BNAV_Player_Handle handle) {
3343    int hits = handle->navCacheReads-handle->navCacheMisses;
3344    printf("cache: %d hits, %ld misses, %ld fails. %0.1f%% hit ratio\n",
3345        hits,
3346        handle->navCacheMisses,
3347        handle->navCacheFails,
3348        100.0*hits/handle->navCacheReads);
3349}
3350
3351int BNAV_Player_ReadIndex(BNAV_Player_Handle handle, int index, BNAV_Entry *entry) {
3352    BNAV_Entry *i;
3353    CHECKREAD(i = BNAV_Player_ReadEntry(handle, index));
3354    memcpy(entry, i, handle->navFileIndexEntrySize);
3355    return 0;
3356}
3357
3358int BNAV_Player_IsHits(BNAV_Player_Handle handle, int searchRange) {
3359    int index = 0;
3360    while (searchRange--) {
3361        int frametype;
3362        BNAV_Entry *i = BNAV_Player_ReadEntry(handle, index++);
3363        if (!i)
3364            break;
3365        frametype = BNAV_get_frameType(i);
3366        if (frametype == eSCTypeRPFrame)
3367            return 1;
3368        else if (frametype == eSCTypeIFrame)
3369            return 0;
3370    }
3371    return -1;
3372}
3373
3374static int BNAV_Player_DetectNavTableVersion(BNAV_Player_Handle handle, int isPes)
3375{
3376    BNAV_Entry *pEntry;
3377
3378    BSTD_UNUSED(isPes);
3379
3380    BNAV_Player_UpdateBounds(handle);
3381    pEntry = BNAV_Player_ReadEntry(handle, handle->firstIndex);
3382    if (!pEntry) {
3383        BDBG_ERR(("BNAV_Player_DetectNavTableVersion: no entry 0"));
3384        return -1;
3385    }
3386    handle->navVersion = BNAV_get_version(pEntry);
3387    return 0;
3388}
3389
3390void BNAV_Player_GetPlayMode(const BNAV_Player_Handle handle, BNAV_Player_PlayMode *mode) {
3391    mode->playMode = handle->playMode;
3392    mode->playModeModifier = handle->advanceCount * handle->playDir;
3393    mode->loopMode = handle->loopMode;
3394    mode->disableExtraBOptimization = handle->disableExtraBOptimization;
3395}
3396
3397int BNAV_Player_SetPlayMode(BNAV_Player_Handle handle, const BNAV_Player_PlayMode *mode)
3398{
3399    int playModeModifier = mode->playModeModifier;
3400
3401    BDBG_MSG(("setPlayMode mode=%d,mode_modifier=%d,loop=%d", mode->playMode, mode->playModeModifier, mode->loopMode));
3402
3403    if (handle->navVersion == BNAV_Version_TimestampOnly) {
3404        if (mode->playMode != eBpPlayNormal) {
3405            BDBG_ERR(("BNAV_Version_TimestampOnly only supports eBpPlayNormal"));
3406            return -1;
3407        }
3408    }
3409
3410    /* Validate the parameters. */
3411    if (mode->playMode == eBpPlayIP || mode->playMode == eBpPlayNormal || mode->playMode == eBpPlayNormalByFrames) {
3412        playModeModifier = 1;
3413    }
3414    else if (mode->playMode == eBpPlayDecoderGOPTrick) {
3415        if (playModeModifier == 0) {
3416            BDBG_ERR(("eBpPlayDecoderGOPTrick cannot have playModeModifier == 0."));
3417            return -1;
3418        }
3419    /* Check if DQT can be supported using the nav file */
3420    if (handle->navVersion == BNAV_Version_AVC){
3421        long        startIndex;
3422        startIndex = BNAV_Player_P_FindGOP(handle, 0);
3423        if(!BNAV_Player_ReadEntry(handle, startIndex)){
3424        BDBG_WRN(("Current index file does not support GOP trickmodes. Please recreate the index to support GOP trickmodes"));
3425        return -1;
3426        }
3427    }
3428        handle->gopTrick.gopSkip = i_abs(playModeModifier)/100;
3429        playModeModifier = playModeModifier % 100;
3430    }
3431    else if (playModeModifier == 0) {
3432        BDBG_ERR(("PlayMode cannot have playModeModifier == 0."));
3433        return -1;
3434    }
3435    else if (playModeModifier < 0 && mode->playMode != eBpPlayI && mode->playMode != eBpPlayBrcm) {
3436        BDBG_ERR(("PlayModeModifier cannot be <0 for this mode."));
3437        return -1;
3438    }
3439
3440    if (handle->navVersion == BNAV_Version_VC1_PES || handle->navVersion == BNAV_Version_AVC) {
3441        if (mode->playMode == eBpPlayBrcm) {
3442            BDBG_ERR(("VC1/AVC Broadcom Trick Modes not supported"));
3443            return -1;
3444        }
3445    }
3446    if (handle->navVersion == BNAV_Version_AVC) {
3447        if (mode->playMode == eBpPlaySkipP) {
3448            /* AVC P frames don't have unidirectional prediction, so we can't drop some P's. */
3449            BDBG_ERR(("SkipP does not work with the AVC codec"));
3450            return -1;
3451        }
3452    }
3453
3454    if (mode->playMode == eBpPlayBrcm && !handle->decoderFeatures.supportsBroadcomTrickModes) {
3455        BDBG_ERR(("Decoder does not support Broadcom Trick Modes."));
3456        return -1;
3457    }
3458    if (mode->playMode == eBpPlayBrcm && playModeModifier == 1) {
3459        BDBG_ERR(("Broadcom Trick Modes cannot have mode modifier of 1."));
3460        return -1;
3461    }
3462
3463    /* loop mode can change */
3464    handle->loopMode = mode->loopMode;
3465
3466    /* if we're staying in playmode, don't change anything past this point */
3467    if (mode->playMode == handle->playMode && handle->playMode == eBpPlayNormal) {
3468        return 0;
3469    }
3470
3471    handle->playMode = mode->playMode;
3472    handle->playDir = playModeModifier>0?eBpForward:eBpReverse;
3473    handle->advanceCount = playModeModifier>0?playModeModifier:-playModeModifier;
3474    handle->curRefFrame = -1;
3475    handle->disableExtraBOptimization = mode->disableExtraBOptimization;
3476    BNAV_Player_SetCurrentIndex(handle, handle->currentIndex);
3477    return 0;
3478}
3479
3480long BNAV_Player_FindIFrameFromIndex(BNAV_Player_Handle handle, long index, eBpDirectionParam dir)
3481{
3482    if (index == -1)
3483        index = handle->currentIndex;
3484
3485    if (handle->navVersion == BNAV_Version_TimestampOnly) {
3486        return index;
3487    }
3488
3489    /* verify that dir is always 1/-1, because this algorithm breaks if you pass in 0. */
3490    dir = (dir > 0)?1:-1;
3491
3492    index = BNAV_Player_P_FindPictureIndex(handle, index, eSCTypeIFrame, dir);
3493
3494    /* TODO: bcmindexer now indexes MPEG field encoded streams as a single NAV entry per field pair.
3495    if we can do the same for AVC, then this code can be removed. this would be best because backing up one
3496    I picture is basically a guess. */
3497    if (dir < 0) {
3498        long previousIndex;
3499        previousIndex = BNAV_Player_P_FindPictureIndex(handle, index-1, eSCTypeIFrame, dir);
3500        if (index-previousIndex == 1) {
3501            /* When searching backwards in field encoded streams, return the 1st field in the field pair, not the 2nd */
3502            BDBG_MSG(("1st field index=%d, 2nd field index=%d", previousIndex, index));
3503            index = previousIndex;
3504        }
3505    }
3506
3507    return index;
3508}
3509
3510bool BNAV_Player_IndexIsBFrame( BNAV_Player_Handle handle, long index ) {
3511    BNAV_Entry *pEntry = 0;
3512    eSCType frametype;
3513    bool rc=false;
3514
3515    pEntry = BNAV_Player_ReadEntry(handle, index);
3516    if( pEntry ) {
3517            frametype = BNAV_get_frameType(pEntry);
3518            if ( frametype == eSCTypeBFrame ) rc = true;
3519    }
3520
3521    return rc;
3522}
3523
3524int BNAV_Player_SetCurrentIndex(BNAV_Player_Handle handle, long index)
3525{
3526    BNAV_Entry *pEntry;
3527
3528    BDBG_MSG(("SetCurrentIndex %ld", index));
3529    if (BNAV_Player_UpdateBounds(handle)) {
3530        BDBG_WRN(("SetCurrentIndex failed: %ld UpdateBounds", index));
3531        return -1;
3532    }
3533    pEntry = BNAV_Player_ReadEntry(handle, index);
3534    if (!pEntry) {
3535        BDBG_WRN(("SetCurrentIndex failed: %ld ReadEntry", index));
3536        return -1;
3537    }
3538
3539    handle->currentIndex = index;
3540    if (handle->playMode == eBpPlayNormal) {
3541        /* Back up to the TS-packet aligned sequence header. From this point,
3542        bcmplayer sends all data. */
3543        uint64_t temp = BNAV_Player_get_frameOffset64(pEntry);
3544        temp = temp - BNAV_get_seqHdrStartOffset(pEntry);
3545        if (handle->packetSize) {
3546            handle->currentOffset = temp - temp % handle->packetSize;
3547        }
3548        else {
3549            handle->currentOffset = temp;
3550        }
3551        handle->lastSeqHdrOffset64 = handle->currentOffset;
3552    }
3553    else {
3554        handle->lastSeqHdrOffset64 = 0;
3555    }
3556    BNAV_Player_FlushFifo(handle);
3557
3558#if 0 /* no longer need empty btp packet,RAVE has improved flush,keeping this for debugging */
3559    /* PR 27274 - send a harmless PROCESS BTP through the system so any pending PROCESS is
3560    nullified. Also see PR's 25759, 26647, 20997. */
3561    {
3562    BNAV_PktFifoEntry *curFifoEntry;
3563    CHECKREAD(curFifoEntry = BNAV_Player_AddFifoEntry(handle));
3564    curFifoEntry->insertpackettype = eBpInsertBTP;
3565    curFifoEntry->pktdata[0] = TT_MODE_PROCESS;    /* MODE */
3566    curFifoEntry->pktdata[7] = 0; /* don't trim anything. */
3567    curFifoEntry->pktdata[8] = 188; /* don't trim anything. */
3568    }
3569#endif
3570
3571    handle->skipCount = 0;
3572    handle->skipNextAdvance = 1;
3573    handle->iFrameRepeatCount = 0;
3574    handle->buildRef.inProcess = 0;
3575    handle->buildRef.needDisplayPicture = 0;
3576    handle->gopTrick.currentStart = -1;
3577    handle->gopTrick.pictureTag = 0;
3578    return 0;
3579}
3580
3581/* resize buffer and clear cache. even if not resizing, always reset for consistent behavior. */
3582static void BNAV_Player_SetCacheSize(BNAV_Player_Handle handle, int cacheSize)
3583{
3584    int cacheBytes = handle->navFileIndexEntrySize * cacheSize;
3585
3586    if (handle->navCacheSize == cacheSize && handle->navCacheBytes == cacheBytes)
3587        goto reset;
3588
3589    handle->navCacheSize = cacheSize;
3590    handle->navCacheBytes = cacheBytes;
3591    handle->navCacheOverlap = cacheSize/4;
3592
3593    /* realloc memory */
3594    if (handle->navCache)
3595        free(handle->navCache);
3596    handle->navCache = (unsigned char *)malloc(handle->navCacheBytes);
3597
3598reset:
3599    handle->navCacheFails = 0;
3600    handle->navCacheMisses = 0;
3601    handle->navCacheReads = 0;
3602    handle->navCacheIndexStart = -1;
3603    handle->navCacheIndexEnd = -1;
3604}
3605
3606int BNAV_Player_SetBounds(BNAV_Player_Handle handle, long firstIndex, long lastIndex)
3607{
3608    if (firstIndex > lastIndex || firstIndex < 0)
3609        return -1;
3610    handle->firstIndex = firstIndex;
3611    handle->lastIndex = lastIndex;
3612
3613    /* If you ever call SetBounds, then no longer use the callback. */
3614    handle->boundsCb = NULL;
3615
3616    /*TODO: should we check SetCurrentIndex and force it within bounds?*/
3617    return 0;
3618}
3619
3620void BNAV_Player_GetSettings(BNAV_Player_Handle handle, BNAV_Player_Settings *settings)
3621{
3622    settings->cacheSize = handle->navCacheSize;
3623    settings->normalPlayBufferSize = handle->normalPlayBufferSize;
3624    settings->debugMode = handle->debugMode;
3625    memcpy(&settings->decoderFeatures, &handle->decoderFeatures, sizeof(handle->decoderFeatures));
3626    settings->videoPid = handle->pid;
3627    settings->navVersion = handle->navVersion;
3628    settings->readCb = handle->readCb;
3629    settings->tellCb = handle->tellCb;
3630    settings->seekCb = handle->seekCb;
3631    settings->boundsCb = handle->boundsCb;
3632    settings->filePointer = handle->filePointer;
3633    settings->firstIndex = handle->firstIndex;
3634    settings->lastIndex = handle->lastIndex;
3635    /*settings->isPes = handle->isPes;*/
3636}
3637
3638void BNAV_Player_SetDebugMode(BNAV_Player_Handle handle, BNAV_Player_DebugMode debugMode)
3639{
3640    handle->debugMode = debugMode;
3641}
3642
3643int BNAV_Player_DefaultGetBounds(BNAV_Player_Handle handle, void *filePointer, long *firstIndex, long *lastIndex)
3644{
3645    long size;
3646    if ((*handle->seekCb)(filePointer, 0, SEEK_END))
3647        return -1;
3648    size = (*handle->tellCb)(filePointer);
3649    if (size == -1)
3650        return -1;
3651
3652    *firstIndex = 0;
3653    *lastIndex = (size/handle->navFileIndexEntrySize) - 1;
3654    return 0;
3655}
3656
3657#define TOTAL_SANITY_CHECKS 100
3658static int BNAV_Player_p_SanityCheck(BNAV_Player_Handle handle)
3659{
3660    int i;
3661    uint64_t last = 0;
3662    int version = -1;
3663
3664    if (BNAV_Player_UpdateBounds(handle))
3665        return -1;
3666    for (i=0;i<TOTAL_SANITY_CHECKS;i++) {
3667        uint64_t next;
3668        BNAV_Entry *pEntry = BNAV_Player_ReadEntry(handle, i);
3669        if (!pEntry)
3670            return 0; /* it's ok to have nothing */
3671
3672        /* offsets should always increase */
3673        next = BNAV_Player_get_frameOffset64(pEntry);
3674        if (next < last)
3675            return -1;
3676        last = next;
3677
3678        /* version should be the same */
3679        if (version == -1)
3680            version = BNAV_get_version(pEntry);
3681        else if (version != BNAV_get_version(pEntry))
3682            return -1;
3683    }
3684    return 0;
3685}
Note: See TracBrowser for help on using the repository browser.