source: svn/newcon3bcm2_21bu/BSEAV/api/src/nexus/bsettop_pvr.c @ 22

Last change on this file since 22 was 22, checked in by phkim, 11 years ago
  1. phkim
  2. newcon3sk 를 kctv 로 브랜치 함
  • Property svn:executable set to *
File size: 71.0 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2003-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: bsettop_pvr.c $
11 * $brcm_Revision: 102 $
12 * $brcm_Date: 6/24/10 12:25p $
13 *
14 * Module Description:
15 *
16 * Revision History:
17 *
18 * $brcm_Log: /BSEAV/api/src/nexus/bsettop_pvr.c $
19 *
20 * 102   6/24/10 12:25p mward
21 * SW7125-491:  Coverity Defect ID:22323,  22324.  CHECKED_RETURN (from
22 * NEXUS_Playback_GetStatus()).
23 *
24 * 101   6/23/10 1:00p erickson
25 * SW7550-462: fix frame advance change-of-directions. bplayback_pause
26 * needs to give control of trick mode selection back to nexus.
27 *
28 * 100   6/22/10 4:28p mphillip
29 * SW7550-463: Clear keyslot when there is security but no DMA
30 *
31 * 99   6/18/10 3:09p erickson
32 * SW7550-424: fix PVR_SUPPORT=n
33 *
34 * 98   6/11/10 11:19a mphillip
35 * SW7550-380: Free keyslot after playback is stopped, not before.
36 *
37 * 97   6/10/10 4:59p erickson
38 * SWDEPRECATED-2726: implement bsettop_fileio_fifo
39 *
40 * 96   6/10/10 2:45p mphillip
41 * SW7550-380: Enable non-DMA PVR encryption for 7550 and similar
42 * platforms
43 *
44 * 95   5/18/10 11:17a erickson
45 * SW7550-424: fix warning for PVR_SUPPORT=n
46 *
47 * 94   2/11/10 2:54p erickson
48 * SW7550-252: fix dma/security testes
49 *
50 * 93   1/8/10 10:11a erickson
51 * SW7400-2645: tpit api change
52 *
53 * 92   12/22/09 1:37p erickson
54 * SW3548-2677: fix warnings
55 *
56 * 91   12/1/09 4:51p mward
57 * SW7125-129: Enable TPIT indexing for H264 recording. Needed for DQT.
58 *
59 * 91   12/1/09 4:49p mward
60 * SW7125-129: Enable TPIT indexing for H264 recording. Needed for DQT.
61 *
62 * SW7125-129/1   11/25/09 4:25p mward
63 * SW7125-129:  Enable TPIT indexing for H264 recording.  Needed for DQT.
64 *
65 * 90   9/24/09 1:46p gmohile
66 * SW7405-2659 : DQT should be enabled for reverse trick modes
67 *
68 * 89   9/23/09 5:36p ahulse
69 * SW7405-2724: Switch MAD off when in playback pause to allow accurate
70 * frame stepping
71 *
72 * 88   9/9/09 6:48p ahulse
73 * SW7405-2724: Add override so settopAPI can use accurate seek
74 *
75 * 87   9/7/09 4:44p ssood
76 * SW7420-340: modified live streaming api to differentiate it w/ network
77 * recording
78 *
79 * 86   9/1/09 2:00p gmohile
80 * SW7403-861 : Fixed avi trickmodes
81 *
82 * 85   8/17/09 1:44p erickson
83 * PR56180: fix warning
84 *
85 * 84   7/29/09 1:50p katrep
86 * PR56180: cset th default max decode rate to 4 x normal playback speed
87 *
88 * 83   7/21/09 7:18p katrep
89 * PR56977: updated set trickmodes according to nexus api definitions.
90 *
91 * 82   7/20/09 4:23p vishk
92 * PR 56180: SettopAPI Shim: Allows user to specify expected maximum
93 * decoder rate
94 *
95 * 81   7/17/09 12:24p katrep
96 * PR56423: nexus playback module no longer set the audio muute
97 * apllication need to mute the audio for host and decoder trickmodes.
98 *
99 * 80   7/13/09 3:56p jtna
100 * PR56423: fix GOP trickmode
101 *
102 * 79   7/9/09 5:52p katrep
103 * PR56707: Audi mute shuld be done after trick modes are set correctly
104 * othrewise audio is lost
105 *
106 * 78   7/9/09 5:23p katrep
107 * PR56703: Fixed trickmodes on video only streams
108 *
109 * 77   6/24/09 5:53p katrep
110 * PR56180: Compiler warning
111 *
112 * 76   6/23/09 3:36p mward
113 * PR 56274: PR 56275: Coverity Defect  FORWARD_NULL.
114 *
115 * 75   6/22/09 6:44p jtna
116 * PR56180: NEXUS_PlaybackTrickModeSettings.overrideStcTrick is superceded
117 * by maxDecoderRate
118 *
119 * 74   6/22/09 6:38p mward
120 * PR 52099: Mute audio for slow trick modes <= half speed.
121 *
122 * 73   6/22/09 5:26p jtna
123 * PR55571: fix I/IP-only decoder trick modes
124 *
125 * 72   6/15/09 4:59p jtna
126 * PR43001: add support for TTS+encryption record/playback
127 *
128 * 71   6/12/09 11:10a jtna
129 * PR43001: support TS/TTS record
130 *
131 * 70   5/11/09 4:32p ssood
132 * PR54955: Record TTS streams over HTTP: indicate to IP Applib that it is
133 * a TTS stream
134 *
135 * 69   4/21/09 4:13p katrep
136 * PR52519: For mp4 and mkv file can do playback stop,start test
137 *
138 * 68   4/16/09 1:04p katrep
139 * PR50207: Stop playback before closing the stream.
140 *
141 * 67   4/15/09 2:40p katrep
142 * PR53824: Correctly use overrideStcTrick to perevnt all the trickmodes
143 * to default to stc trickmodes.Also fixed issue of resume playback from
144 * ongoing decoder trickmodes
145 *
146 * 66   4/9/09 3:43p erickson
147 * PR52519: reenabled the test NEXUS_Playback_Start code so that files
148 * with bad indexes can still play. added better comments so this code
149 * doesn't get commented out again.
150 *
151 * 65   3/9/09 6:59p nickh
152 * PR52996: Fix compilation errors when NEXUS_HAS_SECURITY is disabled
153 *
154 * 64   2/26/09 11:50a katrep
155 * PR52519: Removed unnecessary nexus playbach start and stop to fix the
156 * timeshifted record/playback in the latest nexus
157 *
158 * 63   2/25/09 6:44p katrep
159 * PR52099: For decoder trickmodes need to mute audio outside of nexus
160 *
161 * 62   2/25/09 11:36a katrep
162 * PR52099: Add support for decoder trick modes
163 *
164 * 61   2/4/09 6:18p katrep
165 * PR47815: Add debug
166 *
167 * 60   2/2/09 2:54p gmohile
168 * PR 47815 : Add manual control of trickmodes
169 *
170 * 59   12/24/08 12:42p mphillip
171 * PR49607: Keyladder key derivation support added for encrypted PVR in
172 * nexus shim
173 *
174 * 58   12/24/08 11:56a jgarrett
175 * PR 50703: Allowing security module to be absent
176 *
177 * 57   11/10/08 5:49p jrubio
178 * PR48782: make sure that ip is seperated by the B_HAS_IP flags
179 *
180 * 56   11/7/08 3:00p ssood
181 * PR48782: added network record support
182 *
183 * 55   10/17/08 4:02p katrep
184 * PR47690: Add option to generate index index on video pid during allpass
185 * record, disabled by default.To enable define ALLPASS_RECORD_WITH_INDEX
186 *
187 * 54   10/16/08 6:20p katrep
188 * PR47690: Adding allpass record from playback parser
189 *
190 * 53   10/15/08 2:42p mphillip
191 * PR45211: Reset encryption parameters when doing an unencrypted record
192 *
193 * 52   10/9/08 2:24p erickson
194 * PR47608: added stcTrick based on use_rap_trick_modes env variable
195 *
196 * 51   10/7/08 11:33p erickson
197 * PR47232: NEXUS_PlaypumpSettings.timestamp api change
198 *
199 * 50   9/25/08 1:06p katrep
200 * PR47154: Add support for recording with null packets and without null
201 * packets
202 *
203 * 49   9/22/08 1:53p katrep
204 * PR47154: More fine tuning of allpass record
205 *
206 * 48   9/19/08 7:49p katrep
207 * PR47154: Add support for allpass record
208 *
209 * 47   9/15/08 5:34p jrubio
210 * PR46925:  fix PVR_SUPPORT=n compile issue
211 *
212 * 46   9/4/08 6:00p vsilyaev
213 * PR 44493: Propagate timestamp configuration
214 *
215 * 45   8/29/08 5:43p vsilyaev
216 * PR 33812: Make goto_indx alias of goto_timestamp
217 *
218 * 44   8/8/08 6:27p katrep
219 * PR45213: Bring the nexus playback setting to reset state after the
220 * playback is stopped.
221 *
222 * 43   8/5/08 10:24a erickson
223 * PR45422: add DIVX_DRM_SUPPORT
224 *
225 * 42   7/28/08 3:35p katrep
226 * PR43242: Support changing the loopback modes inside the eof,bof
227 * callbacks
228 *
229 * 41   7/22/08 2:59p erickson
230 * PR44874: allow static allocation of bstream for playback. this is
231 * required to support bstream_close after a bplayback_stop.
232 *
233 * 40   7/10/08 3:23p katrep
234 * PR43636: Add support MSDRM ND
235 *
236 * 39   7/2/08 3:47p erickson
237 * PR42150: added BDBG_ERR if not bplaypump_decode_mode_all
238 *
239 * 38   7/2/08 12:33p erickson
240 * PR36836: report has_index correctly
241 *
242 * 37   6/27/08 3:36p mphillip
243 * PR42901: Free PVR keyslot on close/stop, support encrypted record
244 *
245 * 36   6/26/08 6:21p mphillip
246 * PR42901: Encrypted PVR playback support
247 *
248 * 35   6/25/08 6:12p vsilyaev
249 * PR 41869: Use keySlotHandle instead of keySlot[Number]
250 *
251 * 34   6/24/08 4:10p erickson
252 * PR44107: rename to TrickMode
253 *
254 * 33   6/16/08 6:29p vsilyaev
255 * PR 43636: Fixed key passing
256 *
257 * 32   6/12/08 9:07p katrep
258 * PR43636: Add support for MSDRM
259 *
260 * 31   6/11/08 7:20p ssood
261 * PR42739: added virtual interface back to the playback module to allow
262 * ip implementation in addition to the regular playback implementation
263 *
264 * 30   5/22/08 3:37p erickson
265 * PR36068: remove 1.2x for now
266 *
267 * 29   5/16/08 3:38p erickson
268 * PR36068: clean up DBG output
269 *
270 * 28   5/14/08 1:24p vsilyaev
271 * PR 42119: Preserve PES->TS packetizer settings over
272 * Playpump_Stop/Playpump_Start calls
273 *
274 * 27   5/13/08 5:14p erickson
275 * PR42119: don't call NEXUS_Playback_Start until all pid channels are
276 * opened
277 *
278 * 26   5/6/08 11:36a erickson
279 * PR42365: impl playback callbacks
280 *
281 * 25   5/2/08 9:20a erickson
282 * PR42339: fix pid channel alloc for PVR
283 *
284 * 24   5/1/08 4:08p erickson
285 * PR42339: properly connect and disconnect timeshifting
286 *
287 * 23   4/28/08 11:54a erickson
288 * PR42197: remove NEXUS_ParserBand_ePlayback enums
289 *
290 * 22   4/10/08 5:10p erickson
291 * PR40832: set NEXUS_PlaybackSettings.timeshifting
292 *
293 * 21   4/10/08 9:58a erickson
294 * PR36068: coverity fix
295 *
296 * 20   4/9/08 5:54p jgarrett
297 * PR 41567: Opening playback video pid at start time
298 *
299 * 19   4/7/08 12:04p erickson
300 * PR41431: call NEXUS_Playback_Start from inside bplayback_start
301 *
302 * 18   4/7/08 10:40a jgarrett
303 * PR 41362: Revising pid channel management
304 *
305 * 17   4/4/08 10:43a jgarrett
306 * PR 41312: Synchronizing callbacks
307 *
308 * 16   3/20/08 1:56a erickson
309 * PR36068: impl goto_timestamp
310 *
311 * 15   3/14/08 3:02p katrep
312 * PR40031:Implement some more shhim layer apis
313 *
314 * 15   3/14/08 2:59p katrep
315 * PR40031:Implement some more shhim layer apis
316 *
317 * 14   3/13/08 12:34p erickson
318 * PR36068: fix signed/unsigned math
319 *
320 * 13   3/6/08 4:10p erickson
321 * PR36068: api change
322 *
323 * 12   2/4/08 10:07a erickson
324 * PR36068: api update
325 *
326 * 11   1/8/08 3:21p erickson
327 * PR36068: fix trick modes and record stop
328 *
329 * 10   1/2/08 9:55a erickson
330 * PR36068: Playback changes
331 *
332 * 9   12/20/07 10:28a erickson
333 * PR37590: add timeshifting
334 *
335 * 8   12/4/07 3:09p erickson
336 * PR36068: playpumpSettings.transportType added
337 *
338 * 7   12/3/07 4:59p erickson
339 * PR36068: rework audio, defer playback start until after decode start
340 *
341 * 6   11/14/07 1:29p erickson
342 * PR36068: added record
343 *
344 * 5   11/13/07 11:58a erickson
345 * PR36068: trick modes working
346 *
347 * 4   11/12/07 2:34p erickson
348 * PR36068: update
349 *
350 * 3   10/16/07 12:35p erickson
351 * PR36068: brutus up over settop api/nexus
352 *
353 * 2   10/15/07 4:13p erickson
354 * PR36068: initial
355 *
356 * 1   10/15/07 2:36p erickson
357 * PR36068: initial
358 *
359 ***************************************************************************/
360#include "bsettop_impl.h"
361#include <stdlib.h>
362
363#if B_HAS_IP
364#include "b_playback_ip_lib.h"
365#endif
366
367BDBG_MODULE(pvr);
368
369/* #define ALLPASS_RECORD_WITH_INDEX 1 */
370
371#if (defined NEXUS_HAS_PLAYBACK ) || (defined NEXUS_HAS_RECORD)
372/* This is called from nexus and fires an event */
373static void b_generic_callback(void *context, int param)
374{
375
376    B_EventHandle event = (B_EventHandle)param;
377    BSTD_UNUSED(context);
378    B_Event_Set(event);
379}
380#endif
381
382#if NEXUS_HAS_PLAYBACK
383static void bplayback_p_end_of_stream_handler(void *context)
384{
385    bplayback_t playback = context;
386    if (playback->params.end_of_stream) {
387        bplayback_loopmode loopmode;
388        b_unlock();
389        loopmode = (*playback->params.end_of_stream)(playback->params.callback_context);
390        b_lock();
391        if (loopmode != playback->params.loopmode.end_of_stream) {
392            NEXUS_PlaybackSettings nPlaybackSettings;
393            NEXUS_PlaybackStatus nPlaybackStatus;
394            NEXUS_Playback_GetSettings(playback->nPlayback,&nPlaybackSettings);
395            nPlaybackSettings.endOfStreamAction = (NEXUS_PlaybackLoopMode)loopmode;
396            NEXUS_Playback_SetSettings(playback->nPlayback,&nPlaybackSettings);
397            playback->params.loopmode.end_of_stream = loopmode;
398            if (NEXUS_Playback_GetStatus(playback->nPlayback,&nPlaybackStatus)!= NEXUS_SUCCESS) {
399                BDBG_ERR(("%s: ERROR: NEXUS_Playback_GetStatus() Failed\n", __FUNCTION__));
400                                return;
401                        }
402            switch(nPlaybackStatus.state)
403            {
404            default:
405            case NEXUS_PlaybackState_eStopped:
406            case NEXUS_PlaybackState_eTrickMode:
407                /* do nothing just changed the loop mode */
408                break;
409            case NEXUS_PlaybackState_ePlaying:
410                if(loopmode == bplayback_loopmode_pause)
411                    NEXUS_Playback_Pause(playback->nPlayback);
412                break;
413            case NEXUS_PlaybackState_ePaused:
414                if(loopmode == bplayback_loopmode_loop)
415                    NEXUS_Playback_Play(playback->nPlayback);
416                break;
417            }
418            BDBG_WRN(("eof changing the playback loopmode to %d",nPlaybackSettings.endOfStreamAction));
419        }
420    }
421}
422#endif
423
424
425#if NEXUS_HAS_PLAYBACK
426static void bplayback_p_beginning_of_stream_handler(void *context)
427{
428    bplayback_t playback = context;
429    if (playback->params.beginning_of_stream) {
430        bplayback_loopmode loopmode;
431        b_unlock();
432        loopmode = (*playback->params.beginning_of_stream)(playback->params.callback_context);
433        b_lock();
434        if (loopmode != playback->params.loopmode.beginning_of_stream) {
435            NEXUS_PlaybackSettings nPlaybackSettings;
436            NEXUS_PlaybackStatus nPlaybackStatus;
437            NEXUS_Playback_GetSettings(playback->nPlayback,&nPlaybackSettings);
438            nPlaybackSettings.beginningOfStreamAction = (NEXUS_PlaybackLoopMode)loopmode;
439            NEXUS_Playback_SetSettings(playback->nPlayback,&nPlaybackSettings);
440            playback->params.loopmode.beginning_of_stream = loopmode;
441            if (NEXUS_Playback_GetStatus(playback->nPlayback,&nPlaybackStatus)!= NEXUS_SUCCESS) {
442                BDBG_ERR(("%s: ERROR: NEXUS_Playback_GetStatus() Failed\n", __FUNCTION__));
443                                return;
444                        }
445            switch(nPlaybackStatus.state)
446            {
447            default:
448            case NEXUS_PlaybackState_eStopped:
449            case NEXUS_PlaybackState_eTrickMode:
450                /* do nothing just changed the loop mode */
451                break;
452            case NEXUS_PlaybackState_ePlaying:
453                if(loopmode == bplayback_loopmode_pause)
454                    NEXUS_Playback_Pause(playback->nPlayback);
455                break;
456            case NEXUS_PlaybackState_ePaused:
457                if(loopmode == bplayback_loopmode_loop)
458                    NEXUS_Playback_Play(playback->nPlayback);
459                break;
460            }
461            BDBG_WRN(("bof changing the playback loopmode to %d",nPlaybackSettings.beginningOfStreamAction));
462        }
463    }
464}
465#endif
466
467#if NEXUS_HAS_PLAYBACK
468static void bplayback_p_error_handler(void *context)
469{
470    bplayback_t playback = context;
471    if (playback->params.error) {
472        b_unlock();
473        (*playback->params.error)(playback->params.callback_context);
474        b_lock();
475    }
476}
477#endif
478
479bplayback_file_t bplayback_file_open(const char *mpeg_file_name, const char *index_file_name)
480{
481    return bplayback_p_file_open(mpeg_file_name, index_file_name, NULL);
482}
483
484bplayback_file_t bplayback_p_file_open(const char *mpeg_file_name, const char *index_file_name, bfile_out_fifo_t writer)
485{
486#if NEXUS_HAS_PLAYBACK
487    bplayback_file_t file = BKNI_Malloc(sizeof(*file));
488    BDBG_WRN(("FILE %s , %s",mpeg_file_name, index_file_name ));
489    file->has_index = (index_file_name != NULL);
490
491    if (writer) {
492        file->nFile = NEXUS_FifoPlay_Open(mpeg_file_name, index_file_name, ((brecord_file_t)writer)->nFileFifo);
493    }
494    else {
495        file->nFile = NEXUS_FilePlay_OpenPosix(mpeg_file_name, index_file_name);
496    }
497
498    if (!file->nFile) {
499        bplayback_file_close(file);
500        return NULL;
501    }
502
503    return file;
504#else
505    BSTD_UNUSED(mpeg_file_name);
506    BSTD_UNUSED(index_file_name);
507    BSTD_UNUSED(writer);
508    return NULL;
509#endif
510}
511
512void bplayback_file_close(bplayback_file_t file)
513{
514#if NEXUS_HAS_PLAYBACK
515    BDBG_MSG(("%s: file %p\n", __FUNCTION__, file));
516    if (file->nFile) {
517        NEXUS_FilePlay_Close(file->nFile);
518    }
519    BKNI_Free(file);
520#else
521    BSTD_UNUSED(file);
522#endif
523}
524
525void bplayback_params_init_indx(bplayback_params *params, bplayback_t playback)
526{
527    BSTD_UNUSED(playback);
528    BKNI_Memset(params, 0, sizeof(*params));
529}
530
531/* start playback now that we have a consumer */
532bresult bplayback_p_start(bplayback_t playback)
533{
534#if NEXUS_HAS_PLAYBACK
535    NEXUS_PlaybackSettings nSettings;
536    NEXUS_Error rc;
537
538    BDBG_MSG(("bplayback_p_start"));
539    NEXUS_Playback_GetSettings(playback->nPlayback, &nSettings);
540    nSettings.stcChannel = playback->stream->consumers.decode ? playback->stream->consumers.decode->stcChannel : NULL;
541    nSettings.startPaused = false;
542    nSettings.stcTrick = !bsettop_get_config("use_rap_trick_modes") && nSettings.stcChannel ;
543    nSettings.accurateSeek = bsettop_get_config("use_accurate_seek");
544    rc = NEXUS_Playback_SetSettings(playback->nPlayback, &nSettings);
545
546    /* We don't call NEXUS_Playback_Start until after we have a consumer. The media framework requires all pids (video and audio)
547    before processing any data. */
548    rc = NEXUS_Playback_Start(playback->nPlayback, playback->source->nFile, NULL);
549    if (rc) return BSETTOP_ERROR(rc);
550#else
551    BSTD_UNUSED(playback);
552#endif
553
554    return 0;
555
556}
557
558bstream_t bplayback_start_timeshifting_indx(bplayback_t playback, bplaypump_t playpump, const bstream_mpeg *mpeg,
559    bplayback_file_t source, const bplayback_params *params, brecord_t record)
560{
561#if NEXUS_HAS_PLAYBACK
562    NEXUS_PlaybackSettings nSettings;
563    NEXUS_Error rc;
564
565   BDBG_MSG(("bplayback_start %p", playback));
566    if (playback->stream) {
567        BDBG_ERR(("already started"));
568        return NULL;
569    }
570
571    /* set minimum settings for test start */
572    NEXUS_Playback_GetSettings(playback->nPlayback, &nSettings);
573    nSettings.playpump = playpump->nPlaypump;
574    nSettings.playpumpSettings.transportType = b_mpegtype2nexus(mpeg->mpeg_type);
575    rc = NEXUS_Playback_SetSettings(playback->nPlayback, &nSettings);
576    if (rc) {BSETTOP_ERROR(rc); return NULL;}
577
578    /* mkv and mp4 can not be started without pid channnel configured */
579    if (mpeg->mpeg_type != bstream_mpeg_type_mkv &&  mpeg->mpeg_type != bstream_mpeg_type_mp4 && mpeg->mpeg_type != bstream_mpeg_type_avi)
580    {
581        /* this is just a test start. this is necessary to see if the file and index are good.
582        if not, we want bplayback_start to fail immediately.
583        actual playback will start when consumer is started (record or decode)*/
584        rc = NEXUS_Playback_Start(playback->nPlayback, source->nFile, NULL);
585        if (rc!=NEXUS_SUCCESS)
586        {
587            rc = BSETTOP_ERROR(rc);
588            return NULL;
589        }
590        NEXUS_Playback_Stop(playback->nPlayback);
591    }
592
593    /* Now, continue setting the rest of the settings. */
594    /* The nexus shim uses bplayback_params.loopmode.XXX. Magnum-based Settop API does not. */
595    BDBG_CASSERT(bplayback_loopmode_play == NEXUS_PlaybackLoopMode_ePlay);
596    nSettings.endOfStreamAction = (bplayback_loopmode)params->loopmode.end_of_stream;
597    nSettings.beginningOfStreamAction = (bplayback_loopmode)params->loopmode.beginning_of_stream;
598    nSettings.timeshifting = (record != NULL);
599    nSettings.endOfStreamCallback.callback = b_generic_callback;
600    nSettings.endOfStreamCallback.context = playback;
601    nSettings.endOfStreamCallback.param = (int)playback->end_of_stream_event;
602    nSettings.beginningOfStreamCallback.callback = b_generic_callback;
603    nSettings.beginningOfStreamCallback.context = playback;
604    nSettings.beginningOfStreamCallback.param = (int)playback->beginning_of_stream_event;
605    nSettings.errorCallback.callback = b_generic_callback;
606    nSettings.errorCallback.context = playback;
607    nSettings.errorCallback.param = (int)playback->error_event;
608    nSettings.playpumpSettings.timestamp.type = params->timestamp_enabled ?
609        NEXUS_TransportTimestampType_eMod300 : /* TODO: DSS */
610        NEXUS_TransportTimestampType_eNone;
611
612    if (mpeg->mpeg_type == bstream_mpeg_type_ts && mpeg->encryption.type != bencryption_type_none) {
613#if NEXUS_HAS_SECURITY
614        if (!mpeg->encryption.key_ladder) {
615            switch (mpeg->encryption.type) {
616            case bencryption_type_des:
617                if (mpeg->encryption.key_length != 64) {
618                    BSETTOP_ERROR(berr_invalid_parameter);
619                    return NULL;
620                }
621                break;
622            case bencryption_type_3des:
623                if (mpeg->encryption.key_length != 128) {
624                    BSETTOP_ERROR(berr_invalid_parameter);
625                    return NULL;
626                }
627                break;
628            case bencryption_type_aes:
629                if (mpeg->encryption.key_length != 128) {
630                    BSETTOP_ERROR(berr_invalid_parameter);
631                    return NULL;
632                }
633                break;
634            default:
635                BDBG_ERR(("Unsupported PVR encryption algorithm"));
636                BSETTOP_ERROR(berr_invalid_parameter);
637                return NULL;
638            }
639        } else if (mpeg->encryption.key_length != 8*sizeof(bcrypto_keyladder_data) || !mpeg->encryption.long_key) {
640            BSETTOP_ERROR(berr_invalid_parameter); return NULL;
641        }
642        nSettings.playpumpSettings.securityContext = b_keyslot_m2m_allocate(&mpeg->encryption, false, params->timestamp_enabled);
643        playback->hKeySlot = nSettings.playpumpSettings.securityContext;
644#if NEXUS_HAS_DMA
645        nSettings.playpumpSettings.securityDma = g_dma.hDma;
646        BDBG_MSG(("Enabling decryption on playback: slot: %p, dma: %p",nSettings.playpumpSettings.securityContext,nSettings.playpumpSettings.securityDma));
647#else
648        BDBG_MSG(("Enabling decryption on playback: slot: %p",nSettings.playpumpSettings.securityContext));
649#endif
650        if (!nSettings.playpumpSettings.securityContext
651#if NEXUS_HAS_DMA
652                || !nSettings.playpumpSettings.securityDma
653#endif
654                ) {
655            BDBG_ERR(("Enabling encryption on playback FAILED!"));
656#if NEXUS_HAS_DMA
657            BDBG_ERR(("slot: %p, dma: %p",nSettings.playpumpSettings.securityContext,nSettings.playpumpSettings.securityDma));
658#else
659            BDBG_ERR(("slot: %p",nSettings.playpumpSettings.securityContext));
660#endif
661            BSETTOP_ERROR(berr_external_error);
662            return NULL;
663        }
664#else
665        BDBG_ERR(("PVR encryption is not supported"));
666        BSETTOP_ERROR(berr_invalid_parameter);
667        return NULL;
668#endif
669    }
670#if B_HAS_MSDRM_PD || B_HAS_MSDRM_ND
671    if(mpeg->mpeg_type == bstream_mpeg_type_asf) {
672        nSettings.playpumpSettings.securityContext = (NEXUS_KeySlotHandle) (*(void **)mpeg->encryption.key);
673    }
674#endif
675#if B_HAS_DIVX_DRM
676    if(mpeg->mpeg_type == bstream_mpeg_type_avi) {
677        nSettings.playpumpSettings.securityContext = (NEXUS_KeySlotHandle) (*(void **)mpeg->encryption.key);
678    }
679#endif
680
681    nSettings.startPaused = true;
682    rc = NEXUS_Playback_SetSettings(playback->nPlayback, &nSettings);
683    if (rc) {BSETTOP_ERROR(rc); return NULL;}
684
685    if (record) {
686        rc = NEXUS_Record_AddPlayback(record->nRecord, playback->nPlayback);
687        if (rc) {rc = BSETTOP_ERROR(rc); return NULL;}
688        playback->record = record;
689        record->playback = playback;
690    }
691
692    playback->stream = playback->stream_alloc;
693    rc = bstream_p_set(playback->stream_alloc, mpeg);
694    if (rc) {rc = BSETTOP_ERROR(rc); goto err_stream;}
695
696    playback->params = *params;
697    playback->source = source;
698
699    return playback->stream;
700
701err_stream:
702    playback->stream = NULL;
703    if ( record )
704    {
705        NEXUS_Record_RemovePlayback(record->nRecord, playback->nPlayback);
706        playback->record = NULL;
707        record->playback = NULL;
708    }
709#else
710    BSTD_UNUSED(playback);
711    BSTD_UNUSED(mpeg);
712    BSTD_UNUSED(playpump);
713    BSTD_UNUSED(record);
714    BSTD_UNUSED(params);
715    BSTD_UNUSED(source);
716#endif
717
718    return NULL;
719}
720
721bstream_t bplayback_start_indx(bplayback_t playback, bplaypump_t playpump, const bstream_mpeg *mpeg,
722    bplayback_file_t source, const bplayback_params *params)
723{
724#if NEXUS_HAS_PLAYBACK
725    return bplayback_start_timeshifting_indx(playback, playpump, mpeg, source, params, NULL);
726#else
727    BSTD_UNUSED(playback);
728    BSTD_UNUSED(playpump);
729    BSTD_UNUSED(mpeg);
730    BSTD_UNUSED(source);
731    BSTD_UNUSED(params);
732    return NULL;
733#endif
734}
735
736bresult bplayback_stop_timeshifting_indx(bplayback_t playback)
737{
738#if NEXUS_HAS_PLAYBACK
739    if (playback->record) {
740        NEXUS_Error rc;
741        NEXUS_PlaybackSettings nPlaybackSettings;
742
743        NEXUS_Playback_GetSettings(playback->nPlayback,&nPlaybackSettings);
744        nPlaybackSettings.timeshifting = false;
745        NEXUS_Playback_SetSettings(playback->nPlayback,&nPlaybackSettings);
746
747        rc = NEXUS_Record_RemovePlayback(playback->record->nRecord, playback->nPlayback);
748        if (rc) return BSETTOP_ERROR(rc);
749        playback->record->playback = NULL;
750        playback->record = NULL;
751    }
752#else
753    BSTD_UNUSED(playback);
754#endif
755    return 0;
756}
757
758bresult bplayback_stop_indx(bplayback_t playback)
759{
760#if NEXUS_HAS_PLAYBACK
761
762    NEXUS_PlaybackSettings nPlaybackSettings;
763
764    BDBG_MSG(("bplayback_stop %p", playback));
765    if (!playback->stream) {
766        BDBG_ERR(("not started"));
767        return BSETTOP_ERROR(berr_not_available);
768    }
769
770    if (playback->record) {
771        bplayback_stop_timeshifting_indx(playback);
772    }
773
774    /*PR50207:playback must be stopped before closing the stream */
775    NEXUS_Playback_Stop(playback->nPlayback);
776    bstream_p_close(playback->stream);
777
778    playback->stream = NULL;
779
780    if (playback->hKeySlot) {
781        b_keyslot_m2m_free(playback->hKeySlot);
782        playback->hKeySlot = NULL;
783    }
784
785    /* reset playback settings */
786    NEXUS_Playback_GetDefaultSettings(&nPlaybackSettings);
787    NEXUS_Playback_SetSettings(playback->nPlayback,&nPlaybackSettings);
788#else
789    BSTD_UNUSED(playback);
790#endif
791
792    return 0;
793}
794
795void bplayback_trickmode_params_init(bplayback_trickmode_params *params)
796{
797    BKNI_Memset(params, 0, sizeof(*params));
798    params->mode = bplayback_player_mode_normal;
799    params->mode_modifier = 1; /* don't care */
800    params->slow_motion_rate = 1; /* none */
801    params->decode_mode = bplaypump_decode_mode_all;
802    /* By default allow 4x STC trickmodes */
803    params->maxDecoderRate = 4*BPLAYBACK_NORMALPLAY_SPEED;
804}
805
806bresult bplayback_get_status_indx(bplayback_t p, bplayback_status *status)
807{
808#if NEXUS_HAS_PLAYBACK
809    NEXUS_PlaybackStatus nStatus;
810    NEXUS_Error rc;
811
812    BKNI_Memset(status, 0, sizeof(*status));
813
814    rc = NEXUS_Playback_GetStatus(p->nPlayback, &nStatus);
815    if (rc) return BSETTOP_ERROR(rc);
816
817    status->position.mpeg_file_offset = nStatus.position;
818    status->position.index_offset = nStatus.position;
819    status->position.has_index = p->source->has_index;
820    status->position.timestamp = nStatus.position;
821
822    status->mpeg_file_size = nStatus.last; /* Nexus doesn't provide this. Get from File if needed. */
823    status->has_index = p->source->has_index;
824    status->index_first_offset = nStatus.first; /* Nexus doesn't provide this. Not needed. */
825    status->index_last_offset = nStatus.last; /* Nexus doesn't provide this. Not needed. */
826    status->fifo_depth = nStatus.fifoDepth;
827    status->fifo_size = nStatus.fifoSize;
828    status->bytes_played = nStatus.bytesPlayed;
829    status->last_timestamp = nStatus.last;
830    status->first_timestamp = nStatus.first;
831
832    switch (nStatus.state) {
833    default:
834    case NEXUS_PlaybackState_eStopped: status->state = bplayback_state_stopped; break;
835    case NEXUS_PlaybackState_ePlaying: status->state = bplayback_state_playing; break;
836    case NEXUS_PlaybackState_ePaused: status->state = bplayback_state_paused; break;
837    case NEXUS_PlaybackState_eTrickMode: status->state = bplayback_state_trickmode; break;
838    /* note: no frameadvance */
839    }
840    status->trickmode_params = p->trick_mode_params;
841#else
842    BSTD_UNUSED(p);
843    BSTD_UNUSED(status);
844#endif
845
846    return 0;
847}
848
849bresult bplayback_pause_indx(bplayback_t p)
850{
851#if NEXUS_HAS_PLAYBACK
852    NEXUS_Error rc;
853    NEXUS_PlaybackTrickModeSettings trickModeSettings;
854    bdecode_window_t window = p->stream->consumers.decode->window;
855
856    bdecode_p_window_set_no_delay( window, true );
857
858    /* Give nexus control of the trick mode selection for frame advance. this allows for change of direction,
859    brcm/host selection based on codec, etc.
860    This is needed because bplayback_trickmode_indx() takes that trick mode control away from nexus in order to
861    map the old Settop API trick modes directly to the video decoder. */
862    NEXUS_Playback_GetDefaultTrickModeSettings(&trickModeSettings);
863    trickModeSettings.mode = NEXUS_PlaybackHostTrickMode_eNone;
864    trickModeSettings.rate = 0; /* this is actually a don't care, but setting to 0 is safe.
865                                   the actual pause is NEXUS_Playback_Pause */
866    trickModeSettings.rateControl = NEXUS_PlaybackRateControl_eStream;
867    rc = NEXUS_Playback_TrickMode(p->nPlayback, &trickModeSettings);
868    if (rc) return BSETTOP_ERROR(rc);
869
870    rc = NEXUS_Playback_Pause(p->nPlayback);
871    if (rc) return BSETTOP_ERROR(rc);
872#else
873    BSTD_UNUSED(p);
874#endif
875
876    return 0;
877}
878
879bresult bplayback_catchup_record_indx(bplayback_t p)
880{
881#if NEXUS_HAS_PLAYBACK
882    NEXUS_PlaybackStatus playbackStatus;
883    NEXUS_Error rc;
884
885    rc = NEXUS_Playback_GetStatus(p->nPlayback, &playbackStatus);
886    if (rc) return BERR_TRACE(rc);
887
888    rc = NEXUS_Playback_Seek(p->nPlayback, playbackStatus.last - 3000);
889    if (rc) return BERR_TRACE(rc);
890#else
891    BSTD_UNUSED(p);
892#endif
893    return 0;
894}
895
896bresult bplayback_play_indx(bplayback_t p)
897{
898#if NEXUS_HAS_PLAYBACK
899    NEXUS_Error rc;
900    bdecode_t decode = p->stream->consumers.decode;
901    NEXUS_AudioDecoderTrickState audioDecoderTrickState;
902    bdecode_window_t window = p->stream->consumers.decode->window;
903    BDBG_MSG(("bplayback_play_indx"));
904
905    bdecode_p_window_set_no_delay( window, false );
906
907    rc = NEXUS_Playback_Play(p->nPlayback);
908    if (rc) return BSETTOP_ERROR(rc);
909    /* restore to normal playback if we were doing decoder trickmodes */
910    if (decode && decode->video_decode && decode->video_decode->nVideoDecoder)
911    {
912        NEXUS_VideoDecoderTrickState decoderTrickState;
913        NEXUS_VideoDecoder_GetTrickState(decode->video_decode->nVideoDecoder,&decoderTrickState);
914        if (decoderTrickState.decodeMode != NEXUS_VideoDecoderDecodeMode_eAll)
915        {
916            decoderTrickState.decodeMode = NEXUS_VideoDecoderDecodeMode_eAll;
917            rc = NEXUS_VideoDecoder_SetTrickState(decode->video_decode->nVideoDecoder,&decoderTrickState);
918            if (rc) return BSETTOP_ERROR(rc);
919
920        }
921    }
922    if (decode && decode->audio_decode && decode->audio_decode->nAudioDecoder)
923    {
924        NEXUS_AudioDecoder_GetTrickState(decode->audio_decode->nAudioDecoder,&audioDecoderTrickState);
925        if (audioDecoderTrickState.muted)
926        {
927            audioDecoderTrickState.muted=false;
928            audioDecoderTrickState.rate=NEXUS_NORMAL_DECODE_RATE;
929            rc = NEXUS_AudioDecoder_SetTrickState(decode->audio_decode->nAudioDecoder,&audioDecoderTrickState);
930            if (rc) return BSETTOP_ERROR(rc);
931        }
932    }
933    if (decode && decode->audio_decode && decode->audio_decode->secondary_audio_decode && decode->audio_decode->secondary_audio_decode->nAudioDecoder)
934    {
935        NEXUS_AudioDecoder_GetTrickState(decode->audio_decode->secondary_audio_decode->nAudioDecoder,&audioDecoderTrickState);
936        if (audioDecoderTrickState.muted)
937        {
938            audioDecoderTrickState.muted=false;
939            audioDecoderTrickState.rate=NEXUS_NORMAL_DECODE_RATE;
940            rc = NEXUS_AudioDecoder_SetTrickState(decode->audio_decode->secondary_audio_decode->nAudioDecoder,&audioDecoderTrickState);
941            if (rc) return BSETTOP_ERROR(rc);
942        }
943    }
944
945#else
946    BSTD_UNUSED(p);
947#endif
948
949    return 0;
950}
951
952bresult bplayback_frameadvance_indx(bplayback_t p, bplayback_player_mode playermode, bool forward)
953{
954#if NEXUS_HAS_PLAYBACK
955    NEXUS_Error rc;
956
957    BSTD_UNUSED(playermode);
958
959    rc = NEXUS_Playback_FrameAdvance(p->nPlayback, forward);
960    if (rc) return BSETTOP_ERROR(rc);
961#else
962    BSTD_UNUSED(p);
963    BSTD_UNUSED(playermode);
964    BSTD_UNUSED(forward);
965#endif
966    return 0;
967}
968
969bresult bplayback_trickmode_indx(bplayback_t p, const bplayback_trickmode_params *trickmode)
970{
971#if NEXUS_HAS_PLAYBACK
972    NEXUS_Error rc;
973    NEXUS_PlaybackTrickModeSettings trickModeSettings;
974    int rate;
975    bdecode_t decode = p->stream->consumers.decode;
976
977    BDBG_MSG(("trickmode %d,decode trickmode %d,modifier %d",trickmode->mode,trickmode->decode_mode,trickmode->mode_modifier));
978
979    NEXUS_Playback_GetDefaultTrickModeSettings(&trickModeSettings);
980
981    /* Convert from Settop API trick mode to Nexus rate. This involves some large
982    assumptions. The only accurate method is to use bplayback_player_mode_by_rate. */
983    rate = NEXUS_NORMAL_PLAY_SPEED;
984
985    switch (trickmode->mode) {
986    case bplayback_player_mode_normal:
987        trickModeSettings.mode = NEXUS_PlaybackHostTrickMode_eNormal;
988        break;
989    case bplayback_player_mode_i:
990        trickModeSettings.mode = NEXUS_PlaybackHostTrickMode_ePlayI;
991        break;
992    case bplayback_player_mode_skip_b:
993        trickModeSettings.mode = NEXUS_PlaybackHostTrickMode_ePlaySkipB;
994        break;
995    case bplayback_player_mode_ip:
996        trickModeSettings.mode = NEXUS_PlaybackHostTrickMode_ePlayIP;
997        break;
998    case bplayback_player_mode_skip_p:
999        trickModeSettings.mode = NEXUS_PlaybackHostTrickMode_ePlaySkipP;
1000        break;
1001    case bplayback_player_mode_brcm:
1002        trickModeSettings.mode = NEXUS_PlaybackHostTrickMode_ePlayBrcm;
1003        break;
1004    case bplayback_player_mode_by_gop:
1005        trickModeSettings.mode = NEXUS_PlaybackHostTrickMode_ePlayGop;
1006        break;
1007    case bplayback_player_mode_by_rate:
1008        trickModeSettings.mode = NEXUS_PlaybackHostTrickMode_eNone;
1009        rate = trickModeSettings.rate = trickmode->mode_modifier * NEXUS_NORMAL_PLAY_SPEED / BPLAYBACK_NORMALPLAY_SPEED;
1010        trickModeSettings.rateControl=NEXUS_PlaybackRateControl_eStream;
1011        break;
1012    }
1013
1014    /* Decoder Trick mode handling */
1015    if (decode && decode->video_decode && decode->video_decode->nVideoDecoder)
1016    {
1017        switch (trickmode->decode_mode)
1018        {
1019        case bplaypump_decode_mode_i:
1020            trickModeSettings.skipControl = NEXUS_PlaybackSkipControl_eDecoder;
1021            trickModeSettings.rateControl=NEXUS_PlaybackRateControl_eDecoder;
1022            trickModeSettings.mode = NEXUS_PlaybackHostTrickMode_ePlayI;
1023            break;
1024        case bplaypump_decode_mode_ip:
1025            trickModeSettings.skipControl = NEXUS_PlaybackSkipControl_eDecoder;
1026            trickModeSettings.rateControl=NEXUS_PlaybackRateControl_eDecoder;
1027            trickModeSettings.mode = NEXUS_PlaybackHostTrickMode_ePlayIP;
1028            break;
1029        default:
1030            /*trickModeSettings.skipControl = NEXUS_PlaybackSkipControl_eHost;
1031            trickModeSettings.rateControl=NEXUS_PlaybackRateControl_eStream;*/
1032            break;
1033        }
1034    }
1035
1036    trickModeSettings.mode_modifier = trickmode->mode_modifier;
1037
1038    if (trickmode->slow_motion_rate > 1) {
1039        rate /= (int)trickmode->slow_motion_rate;
1040    }
1041
1042    trickModeSettings.rate = rate;
1043    trickModeSettings.maxDecoderRate = trickmode->maxDecoderRate * NEXUS_NORMAL_PLAY_SPEED/BPLAYBACK_NORMALPLAY_SPEED;
1044
1045    if( bsettop_get_config("max_decoder_rate")) {
1046        trickModeSettings.maxDecoderRate= atoi(bsettop_get_config("max_decoder_rate"))*NEXUS_NORMAL_PLAY_SPEED;
1047    }
1048
1049    BDBG_WRN(("trickmode rate %d,mode %d,%s rate ctrl,%s skip mode,max decode rate %d",
1050              trickModeSettings.rate,trickModeSettings.mode,trickModeSettings.rateControl?"decoder":"stream",
1051              trickModeSettings.skipControl?"decoder":"host",trickModeSettings.maxDecoderRate));
1052
1053    rc = NEXUS_Playback_TrickMode(p->nPlayback, &trickModeSettings);
1054    if (rc) return BSETTOP_ERROR(rc);
1055
1056    p->trick_mode_params = *trickmode;
1057#else
1058    BSTD_UNUSED(trickmode);
1059    BSTD_UNUSED(p);
1060#endif
1061
1062    return 0;
1063}
1064
1065static const bplayback_trickmode_params
1066g_revTrickModes[] = {
1067    {bplayback_player_mode_brcm,  -1, 1, bplaypump_decode_mode_all, 0, 0 },
1068    {bplayback_player_mode_brcm,  -2, 1, bplaypump_decode_mode_all, 0, 0 },
1069    {bplayback_player_mode_brcm,  -5, 1, bplaypump_decode_mode_all, 0, 0 },
1070    {bplayback_player_mode_brcm,  -7, 1, bplaypump_decode_mode_all, 0, 0 },
1071    {bplayback_player_mode_i,     -1, 1, bplaypump_decode_mode_all, 0, 0 },
1072    {bplayback_player_mode_i,     -2, 1, bplaypump_decode_mode_all, 0, 0 },
1073    {bplayback_player_mode_i,     -5, 1, bplaypump_decode_mode_all, 0, 0 },
1074    {bplayback_player_mode_i,     -10, 1, bplaypump_decode_mode_all, 0, 0 },
1075    {bplayback_player_mode_i,     -25, 1, bplaypump_decode_mode_all, 0, 0 },
1076    {bplayback_player_mode_i,     -50, 1, bplaypump_decode_mode_all, 0, 0 },
1077    {bplayback_player_mode_i,     -100, 1, bplaypump_decode_mode_all, 0, 0 },
1078    {bplayback_player_mode_i,     -200, 1, bplaypump_decode_mode_all, 0, 0 }
1079};
1080
1081static const bplayback_trickmode_params
1082g_fwdTrickModes[] = {
1083#if 0
1084/* not supported yet */
1085    {bplayback_player_mode_by_rate, 120, 1, bplaypump_decode_mode_all, 0 }, /* 1.2x STC trick mode */
1086#endif
1087    {bplayback_player_mode_skip_b,  1, 1, bplaypump_decode_mode_all, 0, 0 }, /* play only one B between P's and I's */
1088    {bplayback_player_mode_ip,     0, 1, bplaypump_decode_mode_all, 0, 0 },
1089    {bplayback_player_mode_skip_p,  1, 1, bplaypump_decode_mode_all, 0, 0 }, /* play only one P between I's */
1090    {bplayback_player_mode_i,      1, 1, bplaypump_decode_mode_all, 0, 0 },
1091    {bplayback_player_mode_i,      2, 1, bplaypump_decode_mode_all, 0, 0 },
1092    {bplayback_player_mode_i,      5, 1, bplaypump_decode_mode_all, 0, 0 },
1093    {bplayback_player_mode_i,      10, 1, bplaypump_decode_mode_all, 0, 0 },
1094    {bplayback_player_mode_i,      25, 1, bplaypump_decode_mode_all, 0, 0 },
1095    {bplayback_player_mode_i,      50, 1, bplaypump_decode_mode_all, 0, 0 },
1096    {bplayback_player_mode_i,      100, 1, bplaypump_decode_mode_all, 0, 0 },
1097    {bplayback_player_mode_i,      200, 1, bplaypump_decode_mode_all, 0, 0 }
1098};
1099
1100static void trick_getTrickModeSettings(int rate, bplayback_trickmode_params *params)
1101{
1102    if (rate > 1) {
1103        int total;
1104        rate -= 2;
1105        total = sizeof(g_fwdTrickModes)/sizeof(g_fwdTrickModes[0]);
1106        if (rate >= total) rate = total-1;
1107        *params = g_fwdTrickModes[rate];
1108    }
1109    else if (rate < 0) {
1110        int total;
1111        rate *= -1;
1112        rate -= 1;
1113        total = sizeof(g_revTrickModes)/sizeof(g_revTrickModes[0]);
1114        if (rate >= total) rate = total-1;
1115        *params = g_revTrickModes[rate];
1116    }
1117    else {
1118        static bplayback_trickmode_params normal = {bplayback_player_mode_normal, 1, 1, bplaypump_decode_mode_all, 0, 0};
1119        *params = normal;
1120    }
1121}
1122
1123bresult bplayback_get_trickmode_by_rate_indx(bplayback_t p, int rate, bplayback_trickmode_params *params)
1124{
1125
1126    bool allow_brcm_trick_modes = bsettop_get_config("no_brcm_trick_modes") == NULL;
1127    BSTD_UNUSED(p);
1128
1129    bplayback_trickmode_params_init(params);
1130
1131    if (rate == BPLAYBACK_NORMALPLAY_SPEED || rate == 0) {
1132        /* normal play isn't a trick mode */
1133        return BSETTOP_ERROR(berr_invalid_parameter);
1134    } else if (rate > BPLAYBACK_NORMALPLAY_SPEED) {
1135        /* fast forward */
1136        int fastrate = (rate + BPLAYBACK_NORMALPLAY_SPEED - 1) / BPLAYBACK_NORMALPLAY_SPEED;
1137        BDBG_ASSERT(fastrate >= 2);
1138        trick_getTrickModeSettings(fastrate, params);
1139    } else if (rate <= -BPLAYBACK_NORMALPLAY_SPEED) {
1140        /* rewind, including 1x rewind */
1141        int fastrate = rate / BPLAYBACK_NORMALPLAY_SPEED;
1142        BDBG_ASSERT(fastrate <= -1);
1143        trick_getTrickModeSettings(fastrate, params);
1144    } else {
1145        /* slow forward or reverse */
1146        if (rate < 0) {
1147            params->mode = allow_brcm_trick_modes ? bplayback_player_mode_brcm : bplayback_player_mode_i;
1148            params->mode_modifier = -1;
1149            rate = -rate;
1150        }
1151        params->slow_motion_rate = BPLAYBACK_NORMALPLAY_SPEED/rate;
1152    }
1153    return b_ok;
1154}
1155
1156
1157long bplayback_goto_timestamp_indx(bplayback_t p, long timestamp, int whence)
1158{
1159#if NEXUS_HAS_PLAYBACK
1160
1161    NEXUS_Error rc;
1162    NEXUS_PlaybackStatus nStatus;
1163
1164    rc = NEXUS_Playback_GetStatus(p->nPlayback, &nStatus);
1165    if (rc) {BSETTOP_ERROR(rc); return -1;}
1166
1167    switch (whence) {
1168    case SEEK_SET:
1169        break;
1170    case SEEK_CUR:
1171        timestamp += nStatus.position;
1172        break;
1173    case SEEK_END:
1174        timestamp += nStatus.last;
1175        break;
1176    }
1177
1178    rc = NEXUS_Playback_Seek(p->nPlayback, timestamp);
1179    if (rc) {BSETTOP_ERROR(rc); return -1;}
1180
1181    rc = NEXUS_Playback_GetStatus(p->nPlayback, &nStatus);
1182    if (rc) {BSETTOP_ERROR(rc); return -1;}
1183
1184    return nStatus.position;
1185#else
1186    BSTD_UNUSED(p);
1187    BSTD_UNUSED(timestamp);
1188    BSTD_UNUSED(whence);
1189    return 0;
1190#endif
1191
1192}
1193
1194long bplayback_goto_index_indx(bplayback_t p, long index_offset, int whence)
1195{
1196    /* TODO: Nexus support seek into streams in terms of time
1197       we need figure out ways to convert index_offset to msec */
1198    return bplayback_goto_timestamp_indx(p, index_offset, whence);
1199}
1200
1201off_t bplayback_goto_mpeg_file_offset_indx(bplayback_t p, off_t mpeg_file_offset, int whence)
1202{
1203    /* TODO: Nexus support seek into streams in terms of time
1204       we need figure out ways to convert file offset to msec in the stream */
1205    BSTD_UNUSED(p);
1206    BSTD_UNUSED(mpeg_file_offset);
1207    BSTD_UNUSED(whence);
1208    BSETTOP_ERROR(berr_not_supported);
1209    return -1;
1210}
1211
1212#if NEXUS_HAS_RECORD
1213static void brecord_p_error_handler(void *context);
1214static void brecord_p_overflow_handler(void *context);
1215#endif
1216
1217brecord_t brecord_open(void)
1218{
1219
1220#if NEXUS_HAS_RECORD
1221    brecord_t record = BKNI_Malloc(sizeof(*record));
1222    BKNI_Memset(record, 0, sizeof(*record));
1223
1224    record->nRecord = NEXUS_Record_Create();
1225    if (!record->nRecord) {
1226        BKNI_Free(record);
1227        return NULL;
1228    }
1229
1230    record->errorEvent = B_Event_Create(NULL);
1231    if ( NULL == record->errorEvent )
1232    {
1233        BSETTOP_ERROR(berr_external_error);
1234        goto error;
1235    }
1236
1237    record->overflowEvent = B_Event_Create(NULL);
1238    if ( NULL == record->overflowEvent )
1239    {
1240        BSETTOP_ERROR(berr_external_error);
1241        goto error;
1242    }
1243
1244    record->errorEventId = b_event_register(record->errorEvent, brecord_p_error_handler, record);
1245    if ( NULL == record->errorEventId )
1246    {
1247        BSETTOP_ERROR(berr_external_error);
1248        goto error;
1249    }
1250
1251    record->overflowEventId = b_event_register(record->overflowEvent, brecord_p_overflow_handler, record);
1252    if ( NULL == record->overflowEventId )
1253    {
1254        BSETTOP_ERROR(berr_external_error);
1255        goto error;
1256    }
1257
1258    return record;
1259
1260error:
1261    brecord_close(record);
1262    return NULL;
1263#else
1264    return NULL;
1265#endif
1266}
1267
1268void brecord_close(brecord_t record)
1269{
1270
1271#if NEXUS_HAS_RECORD
1272    if (record->started) {
1273        brecord_stop(record);
1274    }
1275
1276    if ( NULL != record->overflowEventId )
1277    {
1278        b_event_unregister(record->overflowEventId);
1279    }
1280    if ( NULL != record->errorEventId )
1281    {
1282        b_event_unregister(record->errorEventId);
1283    }
1284    if ( NULL != record->overflowEvent )
1285    {
1286        B_Event_Destroy(record->overflowEvent);
1287    }
1288    if ( NULL != record->errorEvent )
1289    {
1290        B_Event_Destroy(record->errorEvent);
1291    }
1292
1293    NEXUS_Record_Destroy(record->nRecord);
1294    BKNI_Free(record);
1295#else
1296    BSTD_UNUSED(record);
1297#endif
1298}
1299
1300void brecord_params_init(brecord_params *params, brecord_t record)
1301{
1302    BSTD_UNUSED(record);
1303    BKNI_Memset(params, 0, sizeof(*params));
1304    params->index_format = bindex_format_bcm;
1305    bencryption_params_init(&params->encryption);
1306}
1307
1308brecord_file_t brecord_file_open(const char *mpeg_file_name, const char *index_file_name)
1309{
1310    return brecord_p_file_open(mpeg_file_name, index_file_name, false);
1311}
1312
1313brecord_file_t brecord_p_file_open(const char *mpeg_file_name, const char *index_file_name, bool fifo)
1314{
1315#if NEXUS_HAS_RECORD
1316    brecord_file_t file = BKNI_Malloc(sizeof(*file));
1317    BKNI_Memset(file, 0, sizeof(*file));
1318
1319    if (fifo) {
1320        file->nFileFifo = NEXUS_FifoRecord_Create(mpeg_file_name, index_file_name);
1321        if (!file->nFileFifo) {
1322            BKNI_Free(file);
1323            return NULL;
1324        }
1325        file->nFile = NEXUS_FifoRecord_GetFile(file->nFileFifo);
1326        if (!file->nFile) {
1327            BKNI_Free(file);
1328            return NULL;
1329        }
1330    }
1331    else {
1332        file->nFile = NEXUS_FileRecord_OpenPosix(mpeg_file_name, index_file_name);
1333        if (!file->nFile) {
1334            BKNI_Free(file);
1335            return NULL;
1336        }
1337    }
1338    return file;
1339#else
1340    BSTD_UNUSED(mpeg_file_name);
1341    BSTD_UNUSED(index_file_name);
1342    BSTD_UNUSED(fifo);
1343    return NULL;
1344#endif
1345}
1346
1347brecord_file_t
1348brecord_file_open_network( const char *mpeg_file_name, const char *index_file_name, const bsocket_params * params, const bstream_mpeg * mpeg_info )
1349{
1350#if B_HAS_IP
1351    B_PlaybackIpSocketOpenSettings socketSettings;
1352    B_PlaybackIpPsiInfo psi;
1353    B_PlaybackIpError rc;
1354
1355    brecord_file_t file = BKNI_Malloc(sizeof(*file));
1356    BKNI_Memset(file, 0, sizeof(*file));
1357    BKNI_Memset(&socketSettings, 0, sizeof(socketSettings));
1358    snprintf(socketSettings.ipAddr,
1359                sizeof(socketSettings.ipAddr),
1360                "%d.%d.%d.%d",params->addr.ipv4.host[0],
1361                params->addr.ipv4.host[1],params->addr.ipv4.host[2],
1362                params->addr.ipv4.host[3]);
1363    socketSettings.port = params->addr.ipv4.port;
1364    socketSettings.protocol = B_PlaybackIpProtocol_eHttp;
1365    BDBG_WRN(("%s: Recording %s to IP Addr %s, port %d\n",
1366                __FUNCTION__, mpeg_file_name, socketSettings.ipAddr, socketSettings.port));
1367    BKNI_Memset(&psi, 0, sizeof(psi));
1368    psi.videoPid = mpeg_info->video[0].pid;
1369    psi.audioPid = mpeg_info->audio[0].pid;
1370    psi.pcrPid = mpeg_info->pcr_pid;
1371    psi.videoCodec = (NEXUS_VideoCodec)mpeg_info->video[0].format;
1372    psi.audioCodec = (NEXUS_AudioCodec)mpeg_info->audio[0].format;
1373    psi.transportTimeStampEnabled = params->timestamp_enabled;
1374
1375    rc = B_PlaybackIp_NetworkRecordingStart(&socketSettings, mpeg_file_name, index_file_name, &psi, &file->nFile);
1376    if (rc) {
1377        BKNI_Free(file);
1378        return NULL;
1379    }
1380    BDBG_MSG(("%s: record started, brecord_file %p\n", __FUNCTION__, file));
1381    return file;
1382#else
1383   BSTD_UNUSED(mpeg_file_name);
1384   BSTD_UNUSED(index_file_name);
1385   BSTD_UNUSED(params);
1386   BSTD_UNUSED(mpeg_info);
1387   return NULL;
1388#endif
1389
1390}
1391
1392void brecord_file_close(brecord_file_t file)
1393{
1394#if NEXUS_HAS_RECORD
1395    BDBG_MSG(("%s: brecord_file %p\n", __FUNCTION__, file));
1396    NEXUS_FileRecord_Close(file->nFile);
1397    BKNI_Free(file);
1398#else
1399    BSTD_UNUSED(file);
1400#endif
1401}
1402
1403#if NEXUS_HAS_RECORD
1404static void brecord_p_error_handler(void *context)
1405{
1406    brecord_t record = (brecord_t)context;
1407    if (record->params.error) {
1408        b_unlock();
1409        (*record->params.error)(record->params.callback_context, record->errorcode);
1410        b_lock();
1411    }
1412}
1413#endif
1414
1415#if NEXUS_HAS_RECORD
1416static void brecord_p_overflow_handler(void *context)
1417{
1418    brecord_t record = (brecord_t)context;
1419    if (record->params.overflow) {
1420        bool stop = false;
1421        b_unlock();
1422        (*record->params.overflow)(record->params.callback_context, &stop);
1423        b_lock();
1424        /* stop outparam is unused */
1425    }
1426}
1427#endif
1428
1429bresult brecord_start(brecord_t record, brecpump_t recpump, bstream_t stream, brecord_file_t file, const brecord_params *params)
1430{
1431#if NEXUS_HAS_RECORD
1432    NEXUS_Error rc;
1433    NEXUS_RecordSettings recordCfg;
1434
1435    BDBG_ASSERT(NULL != params);
1436    record->params = *params;
1437
1438    if ( stream->consumers.record )
1439    {
1440        BDBG_ERR(("Can only connect a single record to a stream"));
1441        return BSETTOP_ERROR(berr_invalid_parameter);
1442    }
1443
1444    if (record->started) {
1445        brecord_stop(record);
1446    }
1447
1448    NEXUS_Record_GetSettings(record->nRecord, &recordCfg);
1449    recordCfg.indexFormat = params->index_format == bindex_format_bcm?NEXUS_RecordIndexType_eBcm:NEXUS_RecordIndexType_eNone;
1450    recordCfg.recpump = recpump->nRecpump;
1451    recordCfg.stopOnOverflow = true;
1452    recordCfg.overflowCallback.callback = b_generic_callback;
1453    recordCfg.overflowCallback.context = record;
1454    recordCfg.overflowCallback.param = (int)record->overflowEvent;
1455    recordCfg.errorCallback.callback = b_generic_callback;
1456    recordCfg.errorCallback.context = record;
1457    recordCfg.errorCallback.param = (int)record->errorEvent;
1458    recordCfg.recpumpSettings.timestampType = params->timestamp_enabled ?
1459        NEXUS_TransportTimestampType_eBinary : NEXUS_TransportTimestampType_eNone;
1460
1461    if (params->encryption.type != bencryption_type_none) {
1462#if NEXUS_HAS_SECURITY
1463        if (!params->encryption.key_ladder) {
1464            switch (params->encryption.type) {
1465            case bencryption_type_des:
1466                if (params->encryption.key_length != 64)
1467                    return BSETTOP_ERROR(berr_invalid_parameter);
1468                break;
1469            case bencryption_type_3des:
1470                if (params->encryption.key_length != 128)
1471                    return BSETTOP_ERROR(berr_invalid_parameter);
1472                break;
1473            case bencryption_type_aes:
1474                if (params->encryption.key_length != 128)
1475                    return BSETTOP_ERROR(berr_invalid_parameter);
1476                break;
1477            default:
1478                BDBG_ERR(("Unsupported PVR encryption algorithm"));
1479                return BSETTOP_ERROR(berr_invalid_parameter);
1480            }
1481        } else if (params->encryption.key_length != 8*sizeof(bcrypto_keyladder_data) || !params->encryption.long_key) {
1482            return BSETTOP_ERROR(berr_invalid_parameter);
1483        }
1484        recordCfg.recpumpSettings.securityContext = b_keyslot_m2m_allocate(&params->encryption,true,
1485            recordCfg.recpumpSettings.timestampType==NEXUS_TransportTimestampType_eNone?false:true);
1486        record->hKeySlot = recordCfg.recpumpSettings.securityContext;
1487#if NEXUS_HAS_DMA
1488        recordCfg.recpumpSettings.securityDma = g_dma.hDma;
1489        BDBG_MSG(("Enabling encryption on record: slot: %p, dma: %p",recordCfg.recpumpSettings.securityContext,recordCfg.recpumpSettings.securityDma));
1490#else
1491        BDBG_MSG(("Enabling encryption on record: slot: %p",recordCfg.recpumpSettings.securityContext));
1492#endif
1493        if (!recordCfg.recpumpSettings.securityContext
1494#if NEXUS_HAS_DMA
1495                || !recordCfg.recpumpSettings.securityDma
1496#endif
1497                ) {
1498            BDBG_ERR(("Enabling encryption on record FAILED!"));
1499#if NEXUS_HAS_DMA
1500            BDBG_ERR(("slot: %p, dma: %p",recordCfg.recpumpSettings.securityContext,recordCfg.recpumpSettings.securityDma));
1501#else
1502            BDBG_ERR(("slot: %p",recordCfg.recpumpSettings.securityContext));
1503#endif
1504            return BSETTOP_ERROR(berr_external_error);
1505        }
1506#else
1507        BDBG_ERR(("PVR encryption is not supported"));
1508        return BSETTOP_ERROR(berr_invalid_parameter);
1509#endif
1510    } else {
1511#if NEXUS_HAS_SECURITY
1512        recordCfg.recpumpSettings.securityContext = NULL;
1513#if NEXUS_HAS_DMA
1514        recordCfg.recpumpSettings.securityDma = NULL;
1515#endif
1516#endif
1517    }
1518    NEXUS_Record_SetSettings(record->nRecord, &recordCfg);
1519
1520    record->stream = stream;
1521
1522    brecord_p_mpeg_change(record, &stream->mpeg);
1523
1524    rc = NEXUS_Record_Start(record->nRecord, file->nFile);
1525    if (rc)
1526    {
1527        record->stream = NULL;
1528        brecord_p_mpeg_change(record, NULL);
1529        return BSETTOP_ERROR(berr_external_error);
1530    }
1531
1532    record->started = true;
1533    stream->consumers.record = record;
1534
1535    /* We have a consumer, start playback if data is coming from playback */
1536    if (stream->producer.playback) {
1537        rc = bplayback_p_start(stream->producer.playback);
1538    }
1539
1540#else
1541    BSTD_UNUSED(record);
1542    BSTD_UNUSED(recpump);
1543    BSTD_UNUSED(stream);
1544    BSTD_UNUSED(file);
1545    BSTD_UNUSED(params);
1546#endif
1547    return 0;
1548}
1549
1550void brecord_get_status(brecord_t record, brecord_status *status)
1551{
1552#if NEXUS_HAS_RECORD
1553    NEXUS_RecordStatus nStatus;
1554    BKNI_Memset(status, 0, sizeof(*status));
1555    NEXUS_Record_GetStatus(record->nRecord, &nStatus);
1556
1557    status->mpeg_bytes_recorded = nStatus.recpumpStatus.data.bytesRecorded;
1558    status->mpeg_fifo_depth = nStatus.recpumpStatus.data.fifoDepth;
1559    status->mpeg_fifo_size = nStatus.recpumpStatus.data.fifoSize;
1560    status->has_index = nStatus.recpumpStatus.hasIndex;
1561    status->index_bytes_recorded = nStatus.recpumpStatus.index.bytesRecorded;
1562    status->index_fifo_depth = nStatus.recpumpStatus.index.fifoDepth;
1563    status->index_fifo_size = nStatus.recpumpStatus.index.fifoSize;
1564    status->last_timestamp = nStatus.lastTimestamp;
1565#else
1566    BSTD_UNUSED(record);
1567    BSTD_UNUSED(status);
1568#endif
1569}
1570
1571bresult brecord_stop(brecord_t record)
1572{
1573#if NEXUS_HAS_RECORD
1574    if (!record->started) {
1575        return 0;
1576    }
1577
1578    if (record->playback) {
1579        return BSETTOP_ERROR(berr_not_supported);
1580    }
1581
1582    NEXUS_Record_Stop(record->nRecord);
1583    record->started = false;
1584
1585    /* Remove all pid channels */
1586    brecord_p_mpeg_change(record, NULL);
1587
1588    if ( record->stream )
1589    {
1590        record->stream->consumers.record = NULL;
1591        record->stream = NULL;
1592    }
1593
1594
1595    if (record->hKeySlot) {
1596        b_keyslot_m2m_free(record->hKeySlot);
1597        record->hKeySlot = NULL;
1598    }
1599#else
1600    BSTD_UNUSED(record);
1601#endif
1602    return 0;
1603}
1604
1605bplayback_t botfplay_open(bobject_t feeder_id)
1606{
1607    /* TODO */
1608    BSTD_UNUSED(feeder_id);
1609    BSETTOP_ERROR(berr_not_supported);
1610    return NULL;
1611}
1612
1613void bsocket_params_init(bsocket_params *params)
1614{
1615    BSTD_UNUSED(params);
1616    return;
1617}
1618
1619bstream_t brecord_socket_open(brecord_t record, const bsocket_params *params)
1620{
1621    /* TODO */
1622    BSTD_UNUSED(record);
1623    BSTD_UNUSED(params);
1624    BSETTOP_ERROR(berr_not_supported);
1625    return NULL;
1626}
1627
1628void brecord_t_socket_close(brecord_t record)
1629{
1630    /* TODO */
1631    BSTD_UNUSED(record);
1632    BSETTOP_ERROR(berr_not_supported);
1633}
1634
1635brecord_t brecord_ip_open(void)
1636{
1637    /* TODO */
1638    BSETTOP_ERROR(berr_not_supported);
1639    return NULL;
1640}
1641
1642#if NEXUS_HAS_RECORD
1643static void brecord_p_mpeg_change_allpass(brecord_t record , const bstream_mpeg *new_settings)
1644{
1645    uint16_t pid=0;
1646    int index=0;
1647    NEXUS_Error errCode;
1648    bstream_t stream = record->stream;
1649    NEXUS_RecordPidChannelSettings *pRecordPidChannnelSetting=NULL;
1650
1651    if (stream->producer.playback)
1652    {
1653        NEXUS_PlaybackSettings playbackSettings;
1654        NEXUS_PlaypumpStatus playpumpStatus;
1655        NEXUS_Playback_GetSettings(stream->producer.playback->nPlayback, &playbackSettings);
1656        NEXUS_Playpump_GetStatus(playbackSettings.playpump,&playpumpStatus);
1657        if (new_settings->audio[0].pid == 0xFFFF)
1658        {
1659            pid = 0xFFFF;
1660            playbackSettings.playpumpSettings.acceptNullPackets=false;
1661        }
1662        else
1663        {
1664            pid = 0x1FFF;
1665            playbackSettings.playpumpSettings.acceptNullPackets=true;
1666        }
1667        playbackSettings.playpumpSettings.allPass=true;
1668        NEXUS_Playback_SetSettings(stream->producer.playback->nPlayback, &playbackSettings);
1669        BDBG_WRN(("Setting playback %d to allpass mode %s null packets",playpumpStatus.index,
1670                  playbackSettings.playpumpSettings.acceptNullPackets?"with":"without"));
1671    }
1672    else if (stream->producer.playpump)
1673    {
1674        NEXUS_PlaypumpSettings playpumpSettings;
1675        NEXUS_PlaypumpStatus playpumpStatus;
1676        NEXUS_Playpump_GetSettings(stream->producer.playpump->nPlaypump, &playpumpSettings);
1677        NEXUS_Playpump_GetStatus(stream->producer.playpump->nPlaypump,&playpumpStatus);
1678        if (new_settings->audio[0].pid == 0xFFFF)
1679        {
1680            pid = 0xFFFF;
1681            playpumpSettings.acceptNullPackets=false;
1682        }
1683        else
1684        {
1685            pid = 0x1FFF;
1686            playpumpSettings.acceptNullPackets=true;
1687        }
1688        playpumpSettings.allPass=true;
1689        NEXUS_Playpump_SetSettings(stream->producer.playpump->nPlaypump, &playpumpSettings);
1690        BDBG_WRN(("Setting playpump %d to allpass mode %s null packets",playpumpStatus.index,
1691                  playpumpSettings.acceptNullPackets?"with":"without"));
1692    }
1693    else if (stream->producer.band)
1694    {
1695        NEXUS_ParserBandSettings parserBandSettings;
1696        NEXUS_ParserBand_GetSettings(stream->parser_band->nParserBand, &parserBandSettings);
1697        if (new_settings->audio[0].pid == 0xFFFF)
1698        {
1699            pid = 0xFFFF;
1700            parserBandSettings.acceptNullPackets=false;
1701        }
1702        else
1703        {
1704            pid = 0x1FFF;
1705            parserBandSettings.acceptNullPackets=true;
1706        }
1707
1708        parserBandSettings.allPass=true;
1709        NEXUS_ParserBand_SetSettings(stream->parser_band->nParserBand, &parserBandSettings);
1710
1711        BDBG_WRN(("Setting parser band %d to allpass mode %s null packets",stream->parser_band->nParserBand,
1712                  parserBandSettings.acceptNullPackets?"with":"without"));
1713    }
1714    else
1715    {
1716        BDBG_ERR(("Unknown producer"));
1717        return;
1718    }
1719
1720    /* remove and close pid record pid channels */
1721    for ( index=0; index < BSETTOP_MAX_PROGRAMS; index++ )
1722    {
1723        if ( record->videoPid[index] )
1724        {
1725            NEXUS_Record_RemovePidChannel(record->nRecord, record->videoPid[index]);
1726            bstream_p_close_pid(record->stream, record->videoPid[index]);
1727            record->videoPid[index] = NULL;
1728        }
1729        if ( record->audioPid[index] )
1730        {
1731            NEXUS_Record_RemovePidChannel(record->nRecord, record->audioPid[index]);
1732            bstream_p_close_pid(record->stream, record->audioPid[index]);
1733            record->audioPid[index] = NULL;
1734        }
1735        if ( record->ancillaryPid[index] )
1736        {
1737            NEXUS_Record_RemovePidChannel(record->nRecord, record->ancillaryPid[index]);
1738            bstream_p_close_pid(record->stream, record->ancillaryPid[index]);
1739            record->ancillaryPid[index] = NULL;
1740        }
1741    }
1742    /* Add pid channnel to record */
1743    record->videoPid[0] = bstream_p_open_pid(stream,pid,bstream_pid_type_other);
1744    if ( NULL == record->videoPid[0] )
1745    {
1746        BDBG_WRN(("Unable to allocate record pid channel for all pass record"));
1747        BSETTOP_ERROR(berr_external_error);
1748    }
1749
1750#if ALLPASS_RECORD_WITH_INDEX
1751    {
1752        NEXUS_RecordPidChannelSettings pidCfg;
1753        NEXUS_Record_GetDefaultPidChannelSettings(&pidCfg);
1754        pidCfg.recpumpSettings.pidType = NEXUS_PidType_eVideo;
1755        pidCfg.recpumpSettings.pidTypeSettings.video.index = true;
1756        pidCfg.recpumpSettings.pidTypeSettings.video.codec = b_videocodec2nexus(new_settings->video[1].format);
1757        /* generate index using pid number instead of pid chanel number */
1758        pidCfg.recpumpSettings.pidTypeSettings.video.pid = new_settings->video[1].pid;
1759        pRecordPidChannnelSetting= &pidCfg;
1760    }
1761#endif
1762
1763    errCode = NEXUS_Record_AddPidChannel(record->nRecord, record->videoPid[0], pRecordPidChannnelSetting);
1764    if ( errCode )
1765    {
1766        BDBG_ERR(("Unable to add record pid channel"));
1767        BSETTOP_ERROR(berr_external_error);
1768    }
1769}
1770#endif
1771
1772void brecord_p_mpeg_change(brecord_t record, const bstream_mpeg *new_settings)
1773{
1774#if NEXUS_HAS_RECORD
1775    int index;
1776    NEXUS_Error errCode;
1777#if 0
1778    bstream_mpeg empty_settings;
1779#endif
1780
1781    BDBG_ASSERT(NULL != record);
1782    BDBG_ASSERT(NULL != record->stream);
1783
1784    /* check to see if we all pass record is requested */
1785    if (new_settings)
1786    {
1787        for ( index=0; index < BSETTOP_MAX_PROGRAMS; index++ )
1788        {
1789            if (new_settings->ancillary[index].pid)
1790                break;
1791            if (new_settings->audio[index].pid && new_settings->audio[index].pid != 0xFFFF && new_settings->audio[index].pid != 0x1FFF  )
1792                break;
1793#if ALLPASS_RECORD_WITH_INDEX
1794            /* Ignore the video PID */
1795            if(index==1)
1796                continue;
1797#endif
1798            if (new_settings->video[index].pid)
1799                break;
1800        }
1801        if (index == BSETTOP_MAX_PROGRAMS)
1802        {
1803            /* all pass record is reqested */
1804            brecord_p_mpeg_change_allpass(record,new_settings);
1805            return;
1806        }
1807    }
1808    else
1809    {
1810        /* remove and close pid record pid channels */
1811        for ( index=0; index < BSETTOP_MAX_PROGRAMS; index++ )
1812        {
1813            if ( record->videoPid[index] )
1814            {
1815                NEXUS_Record_RemovePidChannel(record->nRecord, record->videoPid[index]);
1816                bstream_p_close_pid(record->stream, record->videoPid[index]);
1817                record->videoPid[index] = NULL;
1818            }
1819            if ( record->audioPid[index] )
1820            {
1821                NEXUS_Record_RemovePidChannel(record->nRecord, record->audioPid[index]);
1822                bstream_p_close_pid(record->stream, record->audioPid[index]);
1823                record->audioPid[index] = NULL;
1824            }
1825            if ( record->ancillaryPid[index] )
1826            {
1827                NEXUS_Record_RemovePidChannel(record->nRecord, record->ancillaryPid[index]);
1828                bstream_p_close_pid(record->stream, record->ancillaryPid[index]);
1829                record->ancillaryPid[index] = NULL;
1830            }
1831        }
1832        return;
1833    }
1834
1835#if 0
1836    /* Free all PID channels with NULL settings */
1837    if ( NULL == new_settings )
1838    {
1839        bstream_mpeg_init(&empty_settings);
1840        new_settings = &empty_settings;
1841    }
1842#endif
1843
1844    BDBG_WRN(("Record MPEG change"));
1845
1846    for ( index=0; index < BSETTOP_MAX_PROGRAMS; index++ )
1847    {
1848        if ( (record->stream->mpeg.video[index].pid != new_settings->video[index].pid) ||
1849             (new_settings->video[index].pid != 0 && new_settings->video[index].pid < 0x1fff &&
1850              NULL == record->videoPid[index]) )
1851        {
1852            if ( record->videoPid[index] )
1853            {
1854                NEXUS_Record_RemovePidChannel(record->nRecord, record->videoPid[index]);
1855                bstream_p_close_pid(record->stream, record->videoPid[index]);
1856                record->videoPid[index] = NULL;
1857            }
1858            if ( new_settings->video[index].pid != 0 &&
1859                 new_settings->video[index].pid < 0x1fff )
1860            {
1861                record->videoPid[index] = bstream_p_open_pid(record->stream, new_settings->video[index].pid, bstream_pid_type_video);
1862                if ( NULL == record->videoPid[index] )
1863                {
1864                    BDBG_WRN(("Unable to allocate record pid channel for pid 0x%x (%d)", record->videoPid[index], record->videoPid[index]));
1865                    BSETTOP_ERROR(berr_external_error);
1866                }
1867                else
1868                {
1869                    bool setRapTpit = false;
1870                    NEXUS_RecordPidChannelSettings addPidChannelSettings;
1871                    NEXUS_Record_GetDefaultPidChannelSettings(&addPidChannelSettings);
1872                    addPidChannelSettings.recpumpSettings.pidType = NEXUS_PidType_eVideo;
1873                    addPidChannelSettings.recpumpSettings.pidTypeSettings.video.codec = b_videocodec2nexus(new_settings->video[index].format);
1874                    addPidChannelSettings.recpumpSettings.pidType = NEXUS_PidType_eVideo;
1875                    if ( 0 == index && record->params.index_format != bindex_format_none )
1876                    {
1877                        BDBG_WRN(("Enabling video indexing (index=0)"));
1878                        addPidChannelSettings.recpumpSettings.pidTypeSettings.video.index = true;
1879                        if (addPidChannelSettings.recpumpSettings.pidTypeSettings.video.codec == NEXUS_VideoCodec_eH264)
1880                        {
1881                            setRapTpit = true;
1882                        }
1883                    }
1884                    else
1885                    {
1886                        BDBG_WRN(("Disabling video indexing"));
1887                        addPidChannelSettings.recpumpSettings.pidTypeSettings.video.index = false;
1888                    }
1889                    errCode = NEXUS_Record_AddPidChannel(record->nRecord, record->videoPid[index], &addPidChannelSettings);
1890                    if ( errCode )
1891                    {
1892                        BDBG_ERR(("Unable to add record pid channel"));
1893                        BSETTOP_ERROR(berr_external_error);
1894                    }
1895
1896                    if (setRapTpit) {
1897                        NEXUS_RecpumpTpitFilter filter;
1898                        NEXUS_RecordSettings recordCfg;
1899
1900                        NEXUS_Record_GetSettings(record->nRecord, &recordCfg);
1901                        NEXUS_Recpump_GetDefaultTpitFilter(&filter);
1902                        filter.config.mpeg.randomAccessIndicatorEnable = true;
1903                        filter.config.mpeg.randomAccessIndicatorCompValue = true;
1904                        errCode = NEXUS_Recpump_SetTpitFilter(recordCfg.recpump, record->videoPid[index], &filter);
1905                        if ( errCode )
1906                        {
1907                            BDBG_ERR(("Unable to set TPIT filter for H264 RAP's"));
1908                            BSETTOP_ERROR(berr_external_error);
1909                        }
1910                    }
1911                }
1912            }
1913        }
1914        if ( (record->stream->mpeg.audio[index].pid != new_settings->audio[index].pid) ||
1915             (new_settings->audio[index].pid != 0 && new_settings->audio[index].pid < 0x1fff &&
1916              NULL == record->audioPid[index]) )
1917        {
1918            if ( record->audioPid[index] )
1919            {
1920                NEXUS_Record_RemovePidChannel(record->nRecord, record->audioPid[index]);
1921                bstream_p_close_pid(record->stream, record->audioPid[index]);
1922                record->audioPid[index] = NULL;
1923            }
1924            if ( new_settings->audio[index].pid != 0 &&
1925                 new_settings->audio[index].pid < 0x1fff )
1926            {
1927                record->audioPid[index] = bstream_p_open_pid(record->stream, new_settings->audio[index].pid, bstream_pid_type_other);
1928                if ( NULL == record->audioPid[index] )
1929                {
1930                    BDBG_WRN(("Unable to allocate record pid channel for pid 0x%x (%d)", new_settings->audio[index].pid, new_settings->audio[index].pid));
1931                    BSETTOP_ERROR(berr_external_error);
1932                }
1933                else
1934                {
1935                    errCode = NEXUS_Record_AddPidChannel(record->nRecord, record->audioPid[index], NULL);
1936                    if ( errCode )
1937                    {
1938                        BDBG_ERR(("Unable to add record pid channel"));
1939                        BSETTOP_ERROR(berr_external_error);
1940                    }
1941                }
1942            }
1943        }
1944        if ( (record->stream->mpeg.ancillary[index].pid != new_settings->ancillary[index].pid) ||
1945             (new_settings->ancillary[index].pid != 0 && new_settings->ancillary[index].pid < BSETTOP_PAT_PID &&
1946              NULL == record->ancillaryPid[index]) )
1947        {
1948            if ( record->ancillaryPid[index] )
1949            {
1950                NEXUS_Record_RemovePidChannel(record->nRecord, record->ancillaryPid[index]);
1951                bstream_p_close_pid(record->stream, record->ancillaryPid[index]);
1952                record->ancillaryPid[index] = NULL;
1953            }
1954            if ( new_settings->ancillary[index].pid != 0 &&
1955                 new_settings->ancillary[index].pid < BSETTOP_PAT_PID )
1956            {
1957                uint16_t pid;
1958                pid = new_settings->ancillary[index].pid;
1959                if ( pid == BSETTOP_PAT_PID )
1960                {
1961                    pid = 0;
1962                }
1963                record->ancillaryPid[index] = bstream_p_open_pid(record->stream, pid, bstream_pid_type_other);
1964                if ( NULL == record->ancillaryPid[index] )
1965                {
1966                    BDBG_WRN(("Unable to allocate record pid channel for pid 0x%x (%d)", pid, pid));
1967                    BSETTOP_ERROR(berr_external_error);
1968                }
1969                else
1970                {
1971                    errCode = NEXUS_Record_AddPidChannel(record->nRecord, record->ancillaryPid[index], NULL);
1972                    if ( errCode )
1973                    {
1974                        BDBG_ERR(("Unable to add record pid channel"));
1975                        BSETTOP_ERROR(berr_external_error);
1976                    }
1977                }
1978            }
1979        }
1980    }
1981#else
1982    BSTD_UNUSED(new_settings);
1983    BSTD_UNUSED(record);
1984#endif
1985
1986}
1987
1988void bplayback_close_indx(bplayback_t playback)
1989{
1990#if NEXUS_HAS_PLAYBACK
1991    if (playback->stream) {
1992        bplayback_stop_indx(playback);
1993    }
1994
1995    BDBG_ASSERT(playback->stream_alloc);
1996    playback->stream_alloc->static_alloc = false; /* bstream_close can now free this */
1997    bstream_close(playback->stream_alloc);
1998
1999    if ( NULL != playback->beginning_of_stream_event_id )
2000    {
2001        b_event_unregister(playback->beginning_of_stream_event_id);
2002    }
2003    if ( NULL != playback->end_of_stream_event_id )
2004    {
2005        b_event_unregister(playback->end_of_stream_event_id);
2006    }
2007    if ( NULL != playback->error_event_id )
2008    {
2009        b_event_unregister(playback->error_event_id);
2010    }
2011
2012    if ( NULL != playback->beginning_of_stream_event )
2013    {
2014        B_Event_Destroy(playback->beginning_of_stream_event);
2015    }
2016    if ( NULL != playback->end_of_stream_event )
2017    {
2018        B_Event_Destroy(playback->end_of_stream_event);
2019    }
2020    if ( NULL != playback->error_event )
2021    {
2022        B_Event_Destroy(playback->error_event);
2023    }
2024
2025    NEXUS_Playback_Destroy(playback->nPlayback);
2026    BKNI_Free(playback);
2027#else
2028    BSTD_UNUSED(playback);
2029#endif
2030}
2031
2032bplayback_t bplayback_open(void)
2033{
2034#if NEXUS_HAS_PLAYBACK
2035    bplayback_t playback = BKNI_Malloc(sizeof(*playback));
2036
2037    BKNI_Memset(playback, 0, sizeof(*playback));
2038    playback->nPlayback = NEXUS_Playback_Create();
2039
2040    playback->end_of_stream_event = B_Event_Create(NULL);
2041    if ( NULL == playback->end_of_stream_event )
2042    {
2043        BSETTOP_ERROR(berr_external_error);
2044        goto error;
2045    }
2046    playback->beginning_of_stream_event = B_Event_Create(NULL);
2047    if ( NULL == playback->beginning_of_stream_event )
2048    {
2049        BSETTOP_ERROR(berr_external_error);
2050        goto error;
2051    }
2052    playback->error_event = B_Event_Create(NULL);
2053    if ( NULL == playback->error_event )
2054    {
2055        BSETTOP_ERROR(berr_external_error);
2056        goto error;
2057    }
2058    playback->end_of_stream_event_id = b_event_register(playback->end_of_stream_event, bplayback_p_end_of_stream_handler, playback);
2059    if ( NULL == playback->end_of_stream_event_id )
2060    {
2061        BSETTOP_ERROR(berr_external_error);
2062        goto error;
2063    }
2064    playback->beginning_of_stream_event_id = b_event_register(playback->beginning_of_stream_event, bplayback_p_beginning_of_stream_handler, playback);
2065    if ( NULL == playback->beginning_of_stream_event_id )
2066    {
2067        BSETTOP_ERROR(berr_external_error);
2068        goto error;
2069    }
2070    playback->error_event_id = b_event_register(playback->error_event, bplayback_p_error_handler, playback);
2071    if ( NULL == playback->error_event_id )
2072    {
2073        BSETTOP_ERROR(berr_external_error);
2074        goto error;
2075    }
2076
2077    /* initialize interface */
2078    bplayback_iface_init(&playback->iface);
2079    playback->iface.params_init = bplayback_params_init_indx;
2080    playback->iface.start = bplayback_start_indx;
2081    playback->iface.start_timeshifting = bplayback_start_timeshifting_indx;
2082    playback->iface.stop_timeshifting = bplayback_stop_timeshifting_indx;
2083    playback->iface.stop = bplayback_stop_indx;
2084    playback->iface.get_status = bplayback_get_status_indx;
2085    playback->iface.pause = bplayback_pause_indx;
2086    playback->iface.catchup_record = bplayback_catchup_record_indx;
2087    playback->iface.play = bplayback_play_indx;
2088    playback->iface.frameadvance = bplayback_frameadvance_indx;
2089    playback->iface.trickmode = bplayback_trickmode_indx;
2090    playback->iface.get_trickmode_by_rate = bplayback_get_trickmode_by_rate_indx;
2091    playback->iface.goto_index = bplayback_goto_index_indx;
2092    playback->iface.goto_timestamp = bplayback_goto_timestamp_indx;
2093    playback->iface.goto_mpeg_file_offset = bplayback_goto_mpeg_file_offset_indx;
2094    playback->iface.close = bplayback_close_indx;
2095
2096    playback->stream_alloc = bstream_p_open(NULL, NULL, playback, 0, NULL);
2097    if ( NULL == playback->stream_alloc )
2098    {
2099        BSETTOP_ERROR(berr_external_error);
2100        goto error;
2101    }
2102    playback->stream_alloc->static_alloc = true; /* bstream_close will not free this */
2103
2104    return playback;
2105
2106error:
2107    BKNI_Free(playback);
2108    return NULL;
2109#else
2110    return NULL;
2111#endif
2112}
2113
Note: See TracBrowser for help on using the repository browser.