source: svn/newcon3bcm2_21bu/nexus/modules/file/src/nexus_file_fifo.c

Last change on this file was 76, checked in by megakiss, 10 years ago

1W 대기전력을 만족시키기 위하여 POWEROFF시 튜너를 Standby 상태로 함

  • Property svn:executable set to *
File size: 43.2 KB
Line 
1/***************************************************************************
2 *     (c)2005-2011 Broadcom Corporation
3 *
4 *  This program is the proprietary software of Broadcom Corporation and/or its licensors,
5 *  and may only be used, duplicated, modified or distributed pursuant to the terms and
6 *  conditions of a separate, written license agreement executed between you and Broadcom
7 *  (an "Authorized License").  Except as set forth in an Authorized License, Broadcom grants
8 *  no license (express or implied), right to use, or waiver of any kind with respect to the
9 *  Software, and Broadcom expressly reserves all rights in and to the Software and all
10 *  intellectual property rights therein.  IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU
11 *  HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY
12 *  NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE.
13 *
14 *  Except as expressly set forth in the Authorized License,
15 *
16 *  1.     This program, including its structure, sequence and organization, constitutes the valuable trade
17 *  secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof,
18 *  and to use this information only in connection with your use of Broadcom integrated circuit products.
19 *
20 *  2.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
21 *  AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR
22 *  WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
23 *  THE SOFTWARE.  BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES
24 *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE,
25 *  LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION
26 *  OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF
27 *  USE OR PERFORMANCE OF THE SOFTWARE.
28 *
29 *  3.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS
30 *  LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR
31 *  EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR
32 *  USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF
33 *  THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT
34 *  ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
35 *  LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF
36 *  ANY LIMITED REMEDY.
37 *
38 * $brcm_Workfile: nexus_file_fifo.c $
39 * $brcm_Revision: 15 $
40 * $brcm_Date: 6/28/11 11:07a $
41 *
42 * Module Description:
43 *
44 * Revision History:
45 *
46 * $brcm_Log: /nexus/modules/file/src/nexus_file_fifo.c $
47 *
48 * 15   6/28/11 11:07a vsilyaev
49 * SW7420-1139: Trim of the metadata offset
50 *
51 * 14   5/26/11 7:01p vsilyaev
52 * SW7335-1249: Added option to pereiodically write metadata into a disk
53 *  file
54 *
55 * 13   2/25/11 12:47p erickson
56 * SW7125-818: use BNAV_GetEntrySize
57 *
58 * 12   5/24/10 10:49a jtna
59 * SW7550-439: Coverity Defect ID:21994 ATOMICITY
60 *
61 * 11   4/2/10 2:37p erickson
62 * SW7405-3833: nexus_file_pvr.h is now part of the public API
63 *
64 * 10   11/9/09 6:49p mphillip
65 * SW7405-3361: Fix header zeroing when opening for playback without
66 *  record
67 *
68 * 9   9/16/09 6:27p mphillip
69 * SW7405-3035: Check in I/O cleanup changes
70 *
71 * 8   9/15/09 11:19a mphillip
72 * SWDEPRECATED-3998: Set trim position to the first available offset when
73 *  requested trim location is earlier.
74 *
75 * 7   6/4/09 5:01p erickson
76 * PR54129: align file to 188 for non O_DIRECT. don't align trim offset if
77 *  non O DIRECT. fix DBG.
78 *
79 * 6   3/16/09 10:51a vsilyaev
80 * PR 52405:  Fixed race condition in fifo_read
81 *
82 * 5   3/5/09 5:46p vsilyaev
83 * PR 52579: Updated circular FIFO/timeshifting code
84 *
85 * 4   1/27/09 10:53a erickson
86 * PR50367: added memset
87 *
88 * 3   6/4/08 1:33p rjlewis
89 * PR40352: off_t is 32-bits in VxWorks -- use 64.
90 *
91 * 2   5/12/08 1:27p vsilyaev
92 * PR 41567: Use NULL pid (0x1FFF) for video, to make NAV Player happy
93 *
94 * 1   1/18/08 2:16p jgarrett
95 * PR 38808: Merging to main branch
96 *
97 * Nexus_Devel/2   11/13/07 1:00p vsilyaev
98 * PR 37015: Improved use of O_DIRECT in API
99 *
100 * $old_brcm_Log: /BSEAV/api/src/pvr/bsettop_fileio_fifo.c $
101 *
102 * 23   11/8/07 2:16p ahulse
103 * PR36192: Set up a trim gap so that bcmplayer and other apps never read
104 * from index to be trimmed
105 *
106 * 22   11/1/07 12:10p jackli
107 * PR36646: suppress BDBG_MSG_IO
108 *
109 * 21   10/25/07 2:23p jtna
110 * PR35936: Coverity Defect ID:3993 NULL_RETURNS
111 *
112 * 20   4/12/07 1:58p jackli
113 * PR29779: change bpvrfifo_signature
114 *
115 * 19   4/12/07 1:43p jackli
116 * PR29779: error when timeshift buffer > 4G
117 *
118 * 18   10/4/06 2:02p vsilyaev
119 * PR 23826: Added function to initialize bplayback_file structure
120 *
121 * 17   8/3/06 5:37p rjlewis
122 * PR23249: compiler warnings.
123 *
124 * 16   7/31/06 5:52p jrubio
125 * PR22697: Do not open read Index descriptor with O_DIRECT flag.
126 *
127 * 15   4/7/06 4:50p vsilyaev
128 * PR 20680: More fixes in removing bpvr_buf
129 *
130 * 14   4/7/06 3:50p vsilyaev
131 * PR 20680: Added bfile library
132 *
133 * 13   4/4/06 1:06p mphillip
134 * PR20605: Fix a missing free.
135 *
136 * 12   3/29/06 8:13p vle
137 * PR 20512: correct assertion condition when call bpvrfifo_write_release.
138 *
139 * 10   3/15/06 4:47p mphillip
140 * PR18183: Minor typo in previous checkin
141 *
142 * 9   3/15/06 4:45p mphillip
143 * PR18183: Clear the new file structure prior to use.
144 *
145 * 8   3/7/06 10:06a erickson
146 * PR19853: use BNAV_AVC_Entry for VC1 PES
147 *
148 * 7   12/23/05 4:10p vsilyaev
149 * PR 18183: Renamed API functions
150 *
151 * 5   12/19/05 3:22p rjlewis
152 * PR18183: vxworks doesn't have <sys/fcntl.h>
153 *
154 * 4   11/30/05 3:13p vsilyaev
155 * PR 18183: Improved FIFO file support
156 *
157 * 3   11/21/05 3:42p vsilyaev
158 * PR 18183: Renamed size function to bounds, so it would remain useful
159 * with trimmed files
160 *
161 * 2   11/18/05 2:27p vsilyaev
162 * PR 18183: Added periodic trimmer
163 *
164 * 1   11/17/05 4:22p vsilyaev
165 * PR 18183: Added circular(FIFO) file
166 *
167 ***************************************************************************/
168#include "nexus_file_module.h"
169#include "bstd.h"
170#include "bkni.h"
171#include "bkni_multi.h"
172#include "blst_queue.h"
173#include "bcmplayer.h"
174#include "bcmindexer.h"
175#include "bfile_io.h"
176#include "nexus_file_pvr.h"
177#include "nexus_file_types.h"
178#include "nexus_file_posix.h"
179
180BDBG_MODULE(fileio_fifo);
181
182
183
184struct bpvrfifo_entry {
185    off_t size; /* size of the entry */
186    off_t voff; /* file 'virtual' offset */
187    off_t doff; /* disk 'physical' offset */
188};
189
190struct bpvrfifo_signature {
191    char signature[16];
192};
193
194static const struct bpvrfifo_signature bpvrfifo_signature =
195{
196    "bpvrFiFo 0.21"
197};
198static void bfile_fifo_write_snapshot_locked(struct NEXUS_FifoRecord *file);
199
200
201#define BFIFO_N_ENTRYS  5
202struct bpvrfifo_header {
203    union {
204        struct {
205            struct bpvrfifo_signature signature;
206            struct bpvrfifo_entry entrys[BFIFO_N_ENTRYS+1];
207        } h;
208        uint8_t buf[512]; /* for performance reasons header shall be multiplier of the FS block size */
209    } data; /* this is persistent portion of index (e.g. part that is saved on the disk */
210    /* we use dual lock scheme, lock is acquired every time when header table is accessed,  and busy flag is set wherever there is an active transaction, in this manner we allow simultaneous read and write transactions, and effectively serialize trim with both read and write */
211    BKNI_MutexHandle lock;
212    unsigned busy; /* busy counter, if busy > 0 then there is an active write or read, and trim has to fail */
213    unsigned prev_trim;     /* previously trimmed value */
214    unsigned trim_gap;      /* Gap between real start of file and next trim point */
215};
216#define B_ENTRY(f,i) (&(f)->header->data.h.entrys[(i)])
217#define b_lock(x) BKNI_AcquireMutex(x->header->lock)
218#define b_unlock(x) BKNI_ReleaseMutex(x->header->lock)
219
220struct bfile_io_write_fifo {
221    struct bfile_io_write self;
222    struct bfile_io_write_posix data;
223    struct bpvrfifo_header *header;
224    struct bpvrfifo_header _header;
225    off_t offset; /* current virtual offset, also known as a file size */
226    off_t size; /* size of the file on a disk */
227    off_t start;  /* offset, where writeable area begins */
228    unsigned ref_cnt; /* number of references, including itself */
229    struct NEXUS_FifoRecord *writeSnapshotFile;
230};
231
232struct bfile_io_read_fifo {
233    struct bfile_io_read self;
234    struct bfile_io_read_posix data;
235    struct bpvrfifo_header *header;
236    off_t cur_pos; /* current virtual offset */
237    struct bfile_io_write_fifo *writer;
238};
239
240#define B_ENTRY_CLEAR(f,i) do{ B_ENTRY(f,i)->doff=-1;B_ENTRY(f,i)->voff=0;B_ENTRY(f,i)->size=0;}while(0)
241#define B_ENTRY_IS_EMPTY(f,i) (B_ENTRY(f,i)->doff==-1)
242
243#if 0
244#define BDBG_MSG_IO(i, x) BDBG_INSTANCE_MSG(i, x)
245#else
246#define BDBG_MSG_IO(i, x)
247#endif
248
249#if 0
250#define B_DUMP_ENTRY(file) do{unsigned i;for(i=0;i<BFIFO_N_ENTRYS;i++) {BDBG_MSG_IO(file, ("%#x:%u %lld %lld %u", file, i, B_ENTRY(file,i)->voff, B_ENTRY(file,i)->doff, (unsigned)B_ENTRY(file,i)->size));}}while(0)
251#else
252#define B_DUMP_ENTRY(file)
253#endif
254
255
256static ssize_t
257b_read(struct bfile_io_read_posix *fd, void *buf, size_t count)
258{
259    return fd->self.read(&fd->self, buf, count);
260}
261
262static off_t
263b_rseek(struct bfile_io_read_posix *fd, off_t offset, int whence)
264{
265    return fd->self.seek(&fd->self, offset, whence);
266}
267
268static ssize_t
269b_write(struct bfile_io_write_posix *fd, const void *buf, size_t count)
270{
271    return fd->self.write(&fd->self, buf, count);
272}
273
274static off_t
275b_wseek(struct bfile_io_write_posix *fd, off_t offset, int whence)
276{
277    return bfile_io_write_posix_seek(fd, offset, whence);
278}
279
280static ssize_t
281bpvrfifo_write(bfile_io_write_t fd, const void *buf_, size_t length)
282{
283    struct bfile_io_write_fifo *file = (struct bfile_io_write_fifo*) fd;
284    ssize_t result;
285    const void *buf = buf_;
286    unsigned i;
287
288    BDBG_ASSERT(file->header);
289    BDBG_MSG_IO(file, (">write:%u %lld:%u", file->header->busy, file->offset, (unsigned)length ));
290    b_lock(file);
291    file->header->busy++;
292    for(result=0;length>0;) {
293        size_t to_write = length;
294        ssize_t rc;
295        struct bpvrfifo_entry *entry;
296        off_t boundary;
297        off_t rc_off;
298
299
300
301        for(entry=NULL,i=0;i<BFIFO_N_ENTRYS;i++) {
302            if (B_ENTRY_IS_EMPTY(file,i)) {
303                break;
304            }
305            if(B_ENTRY(file,i)->voff + B_ENTRY(file,i)->size == file->offset) {
306                entry = B_ENTRY(file, i);
307                break;
308            }
309        }
310        if (!entry) {
311            BDBG_WRN(("can't write on descriptor %#x:%lld", (unsigned)file,file->offset));
312            result = -1;
313            break;
314        }
315        if (entry[1].doff!=-1) {
316            boundary = entry[1].doff;
317        } else {
318            boundary = file->size;
319        }
320        if (to_write > boundary - (entry->doff + entry->size)) {
321           to_write = boundary - (entry->doff + entry->size);
322        }
323        if (to_write<=0) {
324            break;
325        }
326        BDBG_MSG_IO(file, (">writing:%#x [%lld/%lld/%lld/%d] (%u/%u/%lld) %#x", entry->voff, entry->doff, boundary, entry-B_ENTRY(file,0), (unsigned)result, (unsigned)to_write, (unsigned)length, file->offset, (unsigned)buf));
327        b_unlock(file);
328        rc_off = b_wseek(&file->data, entry->doff + entry->size, SEEK_SET);
329        b_lock(file);
330        BDBG_MSG_IO(file, ("wseek:%#x %lld -> %lld", entry->doff + entry->size, rc_off));
331        if (rc_off != entry->doff + entry->size) {
332            if (result==0) {
333                if (rc_off < 0) {
334                    result = (ssize_t)rc_off; /* propagate error */
335                } else {
336                    result = -1;
337                }
338            }
339            break;
340        }
341        b_unlock(file);
342        rc = b_write(&file->data, buf, to_write);
343        b_lock(file);
344        BDBG_MSG_IO(file, ("<writing:%#x [%lld/%lld/%lld/%d] (%u/%u/%lld) %#x->%d", entry->voff, entry->doff, boundary, entry-B_ENTRY(file,0), (unsigned)result, (unsigned)to_write, (unsigned)length, file->offset, (unsigned)buf, (int)rc));
345        if (rc<=0) {
346            if  (result==0) {
347                result = rc; /* propagate error */
348            }
349            break;
350        }
351        BDBG_ASSERT((size_t)rc <= to_write);
352        result += rc;
353        length -= (size_t) rc;
354        buf = (const uint8_t *)buf + rc;
355        entry->size = entry->size + rc;
356        file->offset = file->offset + rc;
357        BDBG_ASSERT(entry->doff+entry->size <= file->size);
358        if (entry->doff + entry->size == file->size) {
359            entry = B_ENTRY(file, 0);
360            /* reached the end of file, now is a time to allocate new chunk */
361            if (entry->doff == file->start) {
362                BDBG_MSG(("write overflow"));
363            } else {
364                BDBG_MSG_IO(file, ("write wraparound"));
365                if (entry->doff != -1)  {
366                    BDBG_ASSERT(B_ENTRY(file,BFIFO_N_ENTRYS-1)->doff==-1);
367                    /* new entry _always_ should go on top, so shift old entrys down, so we could keep entries sorted by the 'doff' field */
368                    for(i=BFIFO_N_ENTRYS-1;i>0;i--) {
369                        *B_ENTRY(file,i) = *B_ENTRY(file, i-1);
370                    }
371                }
372                entry->voff = file->offset;
373                entry->doff = file->start;
374                entry->size = 0;
375            }
376        }
377    }
378    file->header->busy--;
379    B_DUMP_ENTRY(file);
380    BDBG_MSG_IO(file, ("<write:%u %lld:%u -> %d", file->header->busy, file->offset, (unsigned)length, (int)result));
381    if(file->writeSnapshotFile) {
382        bfile_fifo_write_snapshot_locked(file->writeSnapshotFile);
383        file->writeSnapshotFile = NULL;
384    }
385    b_unlock(file);
386    return result;
387}
388
389#ifdef DIRECT_IO_SUPPORT
390/* we need to maintain data file aligned by 4096 (for DIRECT I/O) and 188 aligned to keep it valid transport packet */
391/* it rounds in 192K */
392#define B_DATA_ALIGN  ((188/4)*4096)
393#else
394#define B_DATA_ALIGN  (188)
395#endif
396
397static ssize_t
398bpvrfifo_read(bfile_io_read_t fd, void *buf_, size_t length)
399{
400    struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo*) fd;
401    ssize_t result;
402    void *buf = buf_;
403    unsigned i;
404    ssize_t rc;
405
406
407    BDBG_ASSERT(file->header);
408    BDBG_MSG_IO(file, (">read:%u %lld:%u", file->header->busy, file->cur_pos, (unsigned)length));
409    b_lock(file);
410    file->header->busy++;
411    for(result=0;length>0;) {
412        off_t rc_off, seek_off;
413        size_t to_read = length;
414
415        {
416            const struct bpvrfifo_entry *entry; /* when lock is released writer could update move entries around, so protect access to the volatile storage */
417
418
419            for(entry=NULL,i=0;i<BFIFO_N_ENTRYS;i++) {
420                if (B_ENTRY(file,i)->doff==-1) {
421                    break;
422                }
423                if( B_ENTRY(file,i)->voff <= file->cur_pos &&
424                    B_ENTRY(file,i)->voff + B_ENTRY(file, i)->size > file->cur_pos) {
425                    entry = B_ENTRY(file,i);
426                    break;
427                }
428            }
429            if (!entry) {
430                if (result==0) {
431                    if (B_ENTRY(file, 0)->voff > file->cur_pos) {
432                        BDBG_WRN(("out of bounds offset %#x,%lld", (unsigned)file,file->cur_pos));
433                        result = -1;
434                    }
435                }
436                break;
437            }
438            if (to_read > entry->size - (file->cur_pos - entry->voff)) {
439                to_read =  entry->size - (file->cur_pos - entry->voff);
440            }
441            seek_off = entry->doff + (file->cur_pos - entry->voff);
442            BDBG_MSG_IO(file, (">reading: [%lld/%lld/%d -> %lld] (%u/%u/%u/%lld) %#x", entry->voff, entry->doff, entry-B_ENTRY(file,0), seek_off, (unsigned)result, (unsigned)to_read, (unsigned)length, file->cur_pos, (unsigned)buf));
443        }
444        b_unlock(file);
445        rc_off = b_rseek(&file->data, seek_off, SEEK_SET);
446        b_lock(file);
447        BDBG_MSG_IO(file, ("rseek: %lld -> %lld", seek_off, rc_off));
448        if (rc_off != seek_off) {
449            if (result==0) {
450                if (rc_off < 0) {
451                    result = (ssize_t)rc_off; /* propagate error */
452                } else {
453                    /* coverity[use] */
454                    BDBG_WRN(("bpvrfifo_read: %#lx can't seek to %lld(instead %lld)", (unsigned long)file, seek_off, rc_off));
455                    result = -1;
456                }
457            }
458            break;
459        }
460        b_unlock(file);
461        rc = b_read(&file->data, buf, to_read);
462        b_lock(file);
463        BDBG_MSG_IO(file, ("<reading: %lld (%u/%u/%u/%lld) %#x->%d", seek_off, (unsigned)result, (unsigned)to_read, (unsigned)length, file->cur_pos, (unsigned)buf, (int)rc));
464        if (rc!=(ssize_t)to_read) {
465            if (result==0) {
466                result = rc; /* propagate error */
467            }
468            break;
469        }
470        BDBG_ASSERT((size_t)rc <= to_read);
471        result += rc;
472        buf = (uint8_t *)buf + rc;
473        length -= (size_t) rc;
474        file->cur_pos = file->cur_pos + rc;
475    }
476    file->header->busy--;
477    B_DUMP_ENTRY(file);
478    BDBG_MSG_IO(file, ("<read:%u %lld:%u=%d", file->header->busy, file->cur_pos, (unsigned)length, (int)result));
479
480    b_unlock(file);
481    return result;
482}
483
484
485static int
486bpvrfifo_bounds_locked(const struct bfile_io_read_fifo *file, off_t *first, off_t *last)
487{
488    unsigned i;
489
490    BDBG_ASSERT(file->header);
491
492    if (B_ENTRY_IS_EMPTY(file,0)) {
493        *first = *last = 0;
494    } else {
495        *first = B_ENTRY(file,0)->voff;
496        *last = B_ENTRY(file,0)->voff + B_ENTRY(file,0)->size;
497    }
498
499    for(i=1;i<BFIFO_N_ENTRYS;i++) {
500        if (B_ENTRY_IS_EMPTY(file,i)) {
501            break;
502        }
503        if(B_ENTRY(file,i)->voff >= *last) {
504            *last = B_ENTRY(file,i)->voff + B_ENTRY(file,i)->size;
505        }
506        if(B_ENTRY(file,i)->voff < *first) {
507            *first = B_ENTRY(file,i)->voff;
508        }
509    }
510
511    if( file->header->trim_gap ) {
512        *first += (off_t)(file->header->trim_gap);
513    }
514
515
516    return 0;
517}
518
519static int
520bpvrfifo_bounds(bfile_io_read_t fd, off_t *first, off_t *last )
521{
522    struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *) fd;
523    int rc;
524
525    BDBG_ASSERT(file->header);
526    b_lock(file); /* don't need to set busy because lock isn't released */
527
528    BDBG_MSG_IO(file, (">bounds"));
529    rc = bpvrfifo_bounds_locked(file, first, last);
530    BDBG_MSG_IO(file, ("<bounds: %lld..%lld", *first, *last));
531    b_unlock(file);
532    return rc;
533}
534
535static off_t
536bpvrfifo_trim(bfile_io_write_t fd, off_t trim_pos)
537{
538    struct bfile_io_write_fifo *file = (struct bfile_io_write_fifo *) fd;
539    off_t result;
540    off_t min_voff = 0;
541    unsigned i,j;
542
543    BDBG_ASSERT(file->header);
544    b_lock(file);
545    BDBG_MSG_IO(file, (">trim:%u %lld", file->header->busy, trim_pos));
546    result = 0;
547    if (file->header->busy) {
548        goto done;
549    }
550
551    /* trim_pos = (trim_pos) & (~(4096-1)); */
552    if (trim_pos>file->offset) {
553        trim_pos = file->offset;
554    } else if (trim_pos<0) {
555        trim_pos = 0;
556    }
557
558    for(i=0;i<BFIFO_N_ENTRYS;i++) {
559        if (B_ENTRY_IS_EMPTY(file,i)) {
560            break;
561        } else if( B_ENTRY(file,i)->voff >= trim_pos) {
562            if (min_voff==0 || min_voff > B_ENTRY(file,i)->voff)
563                min_voff = B_ENTRY(file,i)->voff;
564            continue;
565        } else if (B_ENTRY(file, i)->voff + B_ENTRY(file,i)->size > trim_pos ) {
566            B_ENTRY(file, i)->size -= trim_pos - B_ENTRY(file,i)->voff;
567            B_ENTRY(file, i)->doff += trim_pos - B_ENTRY(file,i)->voff;
568            B_ENTRY(file, i)->voff = trim_pos;
569            result = trim_pos;
570        } else {
571            if (result < B_ENTRY(file,i)->voff + B_ENTRY(file,i)->size) {
572                result = B_ENTRY(file,i)->voff + B_ENTRY(file,i)->size;
573            }
574            B_ENTRY_CLEAR(file,i); /* mark entry as unused */
575        }
576    }
577    if (!result && trim_pos <= min_voff)
578        result = min_voff;
579    /* collapse empty entries */
580    for(i=0;i<BFIFO_N_ENTRYS;i++) {
581        if (B_ENTRY_IS_EMPTY(file,i)) {
582            for(j=i+1;j<BFIFO_N_ENTRYS;j++) {
583                if (!B_ENTRY_IS_EMPTY(file,j)) {
584                    *B_ENTRY(file, i) = *B_ENTRY(file, j);
585                    B_ENTRY_CLEAR(file, j);
586                    break;
587                }
588            }
589            if (j==BFIFO_N_ENTRYS) {
590                break;
591            }
592        }
593    }
594    if (B_ENTRY_IS_EMPTY(file,0)) {
595        /* file was trimed to  bones, create new entry */
596        B_ENTRY(file, 0)->doff = file->start;
597        B_ENTRY(file, 0)->voff = result;
598        B_ENTRY(file, 0)->size = 0;
599    }
600done:
601    B_DUMP_ENTRY(file);
602    BDBG_MSG_IO(file, ("<trim:%u %lld", file->header->busy, result));
603    b_unlock(file);
604    return result;
605}
606
607static off_t
608bpvrfifo_seek(bfile_io_read_t fd, off_t offset, int whence)
609{
610    struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *) fd;
611    off_t size,begin;
612    int rc;
613
614    BDBG_MSG_IO(file,(">seek: %lld %d", offset, whence));
615    b_lock(file);
616
617    if (whence==SEEK_CUR && offset==0) {
618        /* special case, which is used to  rerrieve current position, without bound checking  */
619        offset = file->cur_pos;
620        goto done;
621    }
622    rc = bpvrfifo_bounds_locked(file, &begin, &size);
623    if (rc<0) {
624        offset = -1;
625        goto error;
626    }
627    /* locate where file begins */
628    switch(whence) {
629    case SEEK_CUR:
630        offset = file->cur_pos + offset;
631        break;
632    case SEEK_END:
633        offset = size + offset;
634        break;
635    case SEEK_SET:
636        break;
637    default:
638        BDBG_ERR(("unknown seek whence %d", whence));
639        goto error;
640    }
641    if (offset == file->cur_pos) {
642        goto done;
643    }
644    if (offset < 0 || offset >= size) {
645        BDBG_WRN(("<seek out out bounds 0..%lld..%lld", offset, size));
646        offset = -1;
647        goto error;
648    }
649    if (offset < begin) {
650        offset = begin;
651    }
652
653    /* just assign new offset */
654done:
655    file->cur_pos = offset;
656error:
657    BDBG_MSG_IO(file, ("<seek: %lld", offset));
658    b_unlock(file);
659    return offset;
660}
661
662static const struct bfile_io_write bpvrfifo_io_write = {
663    bpvrfifo_write,
664    bpvrfifo_trim,
665    BIO_DEFAULT_PRIORITY
666};
667
668static const struct bfile_io_read bpvrfifo_io_read = {
669    bpvrfifo_read,
670    bpvrfifo_seek,
671    bpvrfifo_bounds,
672    BIO_DEFAULT_PRIORITY
673};
674
675static struct bfile_io_write_fifo *
676bpvrfifo_write_open(const char *fname, bool direct, off_t start )
677{
678    struct bfile_io_write_fifo *file =  BKNI_Malloc(sizeof(*file));
679    BERR_Code rc;
680    unsigned i;
681
682    if (!file) {
683        rc = BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
684        goto err_alloc;
685    }
686    BKNI_Memset(file, 0, sizeof(*file));
687    file->header = &file->_header;
688    file->header->data.h.signature = bpvrfifo_signature;
689    file->writeSnapshotFile = NULL;
690    rc = BKNI_CreateMutex(&file->header->lock);
691    if (rc!=BERR_SUCCESS) {
692        goto err_lock;
693    }
694
695    rc = bfile_io_write_posix_open(&file->data, fname, direct);
696    if(rc!=NEXUS_SUCCESS) { rc = BERR_TRACE(rc); goto err_open_data; }
697    /* initialize data */
698    file->self = bpvrfifo_io_write;
699    file->start = start;
700    file->ref_cnt = 1;
701    file->size = 512 * 1024;
702    for(i=0;i<BFIFO_N_ENTRYS;i++) {
703        B_ENTRY_CLEAR(file, i);
704    }
705    B_ENTRY(file, 0)->doff = file->start;
706    return file;
707
708err_open_data:
709    BKNI_DestroyMutex(file->header->lock);
710err_lock:
711    BKNI_Free(file);
712err_alloc:
713    return NULL;
714}
715
716static bfile_io_write_t
717bpvrfifo_write_file(struct bfile_io_write_fifo *file)
718{
719    return &file->self;
720}
721
722/* decrement reference counter and once it reaches 0 then release memory */
723static void
724bpvrfifo_write_release(struct bfile_io_write_fifo *file)
725{
726    bool last;
727
728    b_lock(file);
729    BDBG_ASSERT(file->header);
730    BDBG_MSG_IO(file, ("release:%u:%u", file->ref_cnt, file->header->busy));
731    BDBG_ASSERT(file->ref_cnt);
732    file->ref_cnt--;
733    last = file->ref_cnt==0;
734    BDBG_ASSERT(!last || file->header->busy==0);
735    b_unlock(file);
736    if (last) {
737        BKNI_DestroyMutex(file->header->lock);
738        BKNI_Free(file);
739    }
740    return;
741}
742
743static void
744bpvrfifo_write_close(struct bfile_io_write_fifo *file)
745{
746    bfile_io_write_posix_close(&file->data);
747    bpvrfifo_write_release(file);
748    return;
749}
750
751static struct bfile_io_read_fifo *
752bpvrfifo_read_open(const char *fname, bool direct, struct bfile_io_write_fifo *writer)
753{
754    struct bfile_io_read_fifo *file =  BKNI_Malloc(sizeof(*file));
755    NEXUS_Error rc;
756
757    if (!file) {
758        rc = BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
759        goto err_alloc;
760    }
761    rc = bfile_io_read_posix_open(&file->data, fname, direct);
762    if (rc!=NEXUS_SUCCESS) { rc = BERR_TRACE(rc); goto err_open_data; }
763    file->writer = writer;
764    file->self = bpvrfifo_io_read;
765    if (writer) {
766        file->header = writer->header;
767        b_lock(file);
768        file->writer->ref_cnt++;
769        b_unlock(file);
770    } else {
771        BERR_Code rc;
772
773        file->header = BKNI_Malloc(sizeof(*file->header));
774        BKNI_Memset(file->header, 0, sizeof(*file->header));
775        file->header->data.h.signature = bpvrfifo_signature;
776        rc = BKNI_CreateMutex(&file->header->lock);
777        if (rc!=BERR_SUCCESS) {
778            goto err_lock;
779        }
780    }
781    return  file;
782
783err_lock:
784    bfile_io_read_posix_close(&file->data);
785err_open_data:
786    BKNI_Free(file);
787err_alloc:
788    return NULL;
789}
790
791static bfile_io_read_t
792bpvrfifo_read_file(struct bfile_io_read_fifo *file)
793{
794    return &file->self;
795}
796
797
798static void
799bpvrfifo_read_close(struct bfile_io_read_fifo *file)
800{
801    bfile_io_read_posix_close(&file->data);
802    if(file->writer) {
803        bpvrfifo_write_release(file->writer);
804    } else {
805        BKNI_DestroyMutex(file->header->lock);
806        BKNI_Free(file->header);
807    }
808    BKNI_Free(file);
809    return;
810}
811
812#define B_TRIM_TIMER    5000
813#define B_TRIM_TRY_TIMER    30
814
815struct bfile_out_desc {
816    struct bfile_io_write_fifo *file;
817    unsigned trim_count;
818    off_t trim_off;
819};
820
821struct NEXUS_FifoRecord {
822    struct NEXUS_FileRecord self;
823    struct bfile_out_desc data;
824    struct bfile_out_desc index;
825    struct bfile_io_read_fifo *rd_index;
826    unsigned index_entrysize;
827    BNAV_Player_Handle bcm_player;
828    NEXUS_TimerHandle timer; /* currently active timer  or NULL */
829    NEXUS_Time lastSnapshotTime;
830    NEXUS_FifoRecordSettings cfg;
831};
832
833struct bfile_in_fifo {
834    struct NEXUS_FilePlay self;
835    struct bfile_io_read_fifo *data;
836    struct bfile_io_read_fifo *index;
837    struct NEXUS_FifoRecord *writer;
838};
839
840#define GET_INDEX_FILEIO(fp) (&((NEXUS_FifoRecordHandle) fp)->rd_index->self)
841
842static long
843bp_read(void *buffer, long size, long count, void *fp )
844{
845    bfile_io_read_t f = GET_INDEX_FILEIO(fp);
846
847    return (long)f->read(f, buffer, (size_t)(count*size));
848}
849
850static long
851bp_tell( void *fp )
852{
853    bfile_io_read_t f = GET_INDEX_FILEIO(fp);
854    return (long)f->seek(f, 0, SEEK_CUR);
855}
856
857#if 0
858static int
859bp_seek( void *fp, long offset, int origin )
860{
861    bfile_io_read_t f = GET_INDEX_FILEIO(fp);
862    off_t rc;
863    rc = f->seek(f, (off_t)offset, origin);
864    if ( rc == (off_t)-1) {
865        return -1;
866    }
867    return 0;
868}
869#endif
870
871static int
872bp_bounds(BNAV_Player_Handle handle, void *fp, long *firstIndex, long *lastIndex)
873{
874    bfile_io_read_t f = GET_INDEX_FILEIO(fp);
875    off_t first, last;
876    unsigned index_entrysize =((NEXUS_FifoRecordHandle)fp)->index_entrysize;
877
878    f->bounds(f, &first, &last);
879
880    BSTD_UNUSED(handle);
881    *firstIndex = first/index_entrysize;
882    *lastIndex = (last-1)/index_entrysize;
883
884    return 0;
885}
886
887static int
888trim_bp_bounds( BNAV_Player_Handle handle, void *fp, long *firstIndex, long *lastIndex )
889{
890    bfile_io_read_t fd = GET_INDEX_FILEIO(fp);
891    off_t first, last;
892    unsigned index_entrysize =((NEXUS_FifoRecordHandle)fp)->index_entrysize;
893    int rc;
894
895    struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *)fd;
896    BDBG_ASSERT(file->header);
897    b_lock(file);
898    rc = bpvrfifo_bounds_locked(file, &first, &last );
899    if( file->header->trim_gap ) {
900        /* Untrimmed file start is first offset minus trim gap */
901        first -= (off_t)(file->header->trim_gap);
902    }
903    b_unlock(file);
904
905
906    BSTD_UNUSED(handle);
907    *firstIndex = first/index_entrysize;
908    *lastIndex = (last-1)/index_entrysize;
909
910    return 0;
911}
912
913static int
914trim_bp_seek( void *fp, long offset, int origin )
915{
916    bfile_io_read_t f = GET_INDEX_FILEIO(fp);
917    unsigned index_entrysize =((NEXUS_FifoRecordHandle)fp)->index_entrysize;
918    long saveOffset = 0;
919    struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *)f;
920    off_t rc;
921
922    if( file->header->trim_gap ) {
923        BNAV_Player_Handle dummyHandle = NULL;
924        long firstIdx, lastIdx;
925
926        /* Find beginning trimmed area */
927        trim_bp_bounds( dummyHandle, fp, &firstIdx, &lastIdx );
928        saveOffset = firstIdx*index_entrysize;
929
930        if( offset && offset < firstIdx*(int)index_entrysize ) {
931            /* But don't adjust for a tell request ( offset=0 , origin=SEEK_SET ) */
932            offset = firstIdx*index_entrysize;
933        }
934    }
935
936    rc = f->seek(f, (off_t)offset, origin);
937    if ( rc == (off_t)-1) {
938        return -1;
939    }
940
941
942    if ( offset==0 && saveOffset ) {
943        /* Fix up cur_pos to actual trim area beginning */
944        b_lock(file);
945        file->cur_pos = saveOffset;
946        b_unlock(file);
947    }
948    else if ( offset < file->cur_pos ) {
949        /* If get in here , it means trimming is happening */
950        b_lock(file);
951        file->cur_pos = offset;
952        b_unlock(file);
953    }
954
955    return 0;
956}
957
958
959static void
960bfile_fifo_close_in(NEXUS_FilePlayHandle f)
961{
962    struct bfile_in_fifo *file =  (struct bfile_in_fifo *)f;
963
964    BDBG_ASSERT(file->data);
965    BDBG_ASSERT(file->index);
966    bpvrfifo_read_close(file->data);
967    bpvrfifo_read_close(file->index);
968    BKNI_Free(file);
969    return;
970}
971
972NEXUS_FilePlayHandle
973NEXUS_FifoPlay_Open(const char *fname, const char *indexname, NEXUS_FifoRecordHandle writer)
974{
975    struct bfile_in_fifo *file;
976    NEXUS_Error rc;
977
978    if (fname==NULL) { rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; }
979    if (indexname==NULL) { rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; }
980
981    file = BKNI_Malloc(sizeof(*file));
982    if (!file) { rc = BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY); goto err_alloc; }
983    BKNI_Memset(file, 0, sizeof(*file));
984
985    file->data = bpvrfifo_read_open(fname, true, writer?writer->data.file:NULL);
986    if (!file->data) { goto err_data;}
987
988    file->index = bpvrfifo_read_open(indexname, false, writer?writer->index.file:NULL);
989    if (!file->index) { goto err_index;}
990
991    if (writer==NULL) {
992        struct bpvrfifo_header *buf;
993        ssize_t rc;
994
995        buf = file->index->header;
996        b_rseek(&file->index->data, 0, SEEK_SET);
997        rc = b_read(&file->index->data, &buf->data, sizeof(buf->data));
998        if (rc!=sizeof(buf->data) || buf->data.h.signature.signature[0]!=bpvrfifo_signature.signature[0]) {
999            rc = BERR_TRACE(NEXUS_INVALID_PARAMETER);
1000            goto err_meta;
1001        }
1002
1003        buf = file->data->header;
1004        b_rseek(&file->index->data, sizeof(buf->data), SEEK_SET);
1005        rc = b_read(&file->index->data, buf, sizeof(buf->data));
1006        if (rc!=sizeof(buf->data) || buf->data.h.signature.signature[0]!=bpvrfifo_signature.signature[0]) {
1007            rc = BERR_TRACE(NEXUS_INVALID_PARAMETER);
1008            goto err_meta;
1009        }
1010    }
1011
1012    file->self.file.index = bpvrfifo_read_file(file->index);
1013    file->self.file.data = bpvrfifo_read_file(file->data);
1014
1015    file->self.file.close = bfile_fifo_close_in;
1016
1017    return &file->self;
1018
1019err_meta:
1020    bpvrfifo_read_close(file->index);
1021err_index:
1022    bpvrfifo_read_close(file->data);
1023err_data:
1024    BKNI_Free(file);
1025err_alloc:
1026    return NULL;
1027}
1028
1029
1030static void
1031bfile_fifo_write_snapshot_locked(struct NEXUS_FifoRecord *file)
1032{
1033    const struct bpvrfifo_header *buf;
1034
1035    buf = file->index.file->header;
1036    b_wseek(&file->index.file->data, 0, SEEK_SET);
1037    b_write(&file->index.file->data, &buf->data, sizeof(buf->data));
1038
1039    buf = file->data.file->header;
1040    b_wseek(&file->index.file->data, sizeof(buf->data), SEEK_SET);
1041    b_write(&file->index.file->data, &buf->data, sizeof(buf->data));
1042    return;
1043}
1044
1045static void
1046bfile_fifo_close_out(NEXUS_FileRecordHandle f)
1047{
1048    struct NEXUS_FifoRecord *file =  (struct NEXUS_FifoRecord *)f;
1049
1050    if (file->timer) {
1051        NEXUS_CancelTimer(file->timer);
1052    }
1053    if (file->bcm_player) {
1054        BNAV_Player_Close(file->bcm_player);
1055    }
1056    b_lock(file->index.file);
1057    bfile_fifo_write_snapshot_locked(file);
1058    bfile_fifo_write_snapshot_locked(file);
1059    b_unlock(file->index.file);
1060
1061
1062    bpvrfifo_read_close(file->rd_index);
1063    bpvrfifo_write_close(file->data.file);
1064    bpvrfifo_write_close(file->index.file);
1065    BKNI_Free(file);
1066    return;
1067}
1068
1069static void
1070b_trim_try_player(NEXUS_FifoRecordHandle file)
1071{
1072    if (file->bcm_player==NULL) {
1073        BNAV_DecoderFeatures features = {1,1,1,1};
1074        BNAV_Player_Settings cfg;
1075
1076        BNAV_Player_GetDefaultSettings(&cfg);
1077
1078        cfg.videoPid = 0x1FFF; /* since BNAV_Player doesn't like 0 */
1079        cfg.filePointer = file;
1080        cfg.normalPlayBufferSize = 1024*128;
1081        cfg.decoderFeatures = features;
1082        cfg.readCb = bp_read;
1083        cfg.tellCb = bp_tell;
1084        cfg.seekCb   = trim_bp_seek;
1085        cfg.boundsCb = trim_bp_bounds;
1086        cfg.transportTimestampEnabled = false;
1087        if (BNAV_Player_Open(&file->bcm_player, &cfg)!=0) {
1088            return;
1089        }
1090        BNAV_Player_GetSettings(file->bcm_player, &cfg);
1091        file->index_entrysize = BNAV_GetEntrySize(cfg.navVersion);
1092    }
1093    return;
1094}
1095
1096/* this functions return true if trim was successfull and false otherwise */
1097static bool
1098b_try_trim_file(struct bfile_out_desc *desc)
1099{
1100    off_t rc;
1101
1102    if (desc->trim_count==0) {
1103        return true;
1104    }
1105    if (desc->trim_off>0) {
1106        BDBG_MSG((">try_trim %#x:%u %lld", (unsigned)desc->file, desc->trim_count, desc->trim_off));
1107        rc = desc->file->self.trim(&desc->file->self, desc->trim_off);
1108        BDBG_MSG(("<try_trim %#x:%u %lld:%lld", (unsigned)desc->file, desc->trim_count, desc->trim_off, rc));
1109        if (rc == 0) {
1110            desc->trim_count++;
1111            return false;
1112        }
1113        if (rc<0) {
1114            BDBG_WRN(("trim has failed"));
1115            return true;
1116        }
1117    }
1118    desc->trim_count = 0;
1119    return true;
1120}
1121
1122#define B_GET_OFF_T(p) ((p)->offsetLo|(((uint64_t)(p)->offsetHi)<<32))
1123
1124/* this function called from the timer context */
1125static void
1126b_trim_timer(void *file_)
1127{
1128    NEXUS_FifoRecordHandle file = file_;
1129    unsigned timeout = B_TRIM_TIMER;
1130    long firstIndex, lastIndex;
1131    BNAV_Player_Position first, last;
1132    int rc;
1133    unsigned long interval;
1134    NEXUS_Time start, stop;
1135
1136    NEXUS_Time_Get(&start);
1137    if(file->cfg.snapshotInterval != 0 && (NEXUS_Time_Diff(&start, &file->lastSnapshotTime)/1000)>=(long)file->cfg.snapshotInterval) {
1138        b_lock(file->index.file);
1139        file->index.file->writeSnapshotFile = file; /* we can't write data right there since it could overlap with running write operation and would corrupt the file write pointer */
1140        b_unlock(file->index.file);
1141        file->lastSnapshotTime = start;
1142    }
1143
1144    if (file->index.trim_count || file->data.trim_count) {
1145        /* trim index first */
1146        if (!b_try_trim_file(&file->index)) {
1147            timeout = B_TRIM_TRY_TIMER;
1148            goto done;
1149        }
1150        if (!b_try_trim_file(&file->data)) {
1151            timeout = B_TRIM_TRY_TIMER;
1152            goto done;
1153        }
1154        /* this effectively limits rate of succesfull trims to one each B_TRIM_TIMER */
1155        goto done;
1156    }
1157
1158    b_trim_try_player(file);
1159    if(file->bcm_player==NULL) {
1160        BDBG_WRN(("index file is empty, trim can't be activated"));
1161        goto done;
1162    }
1163    rc = trim_bp_bounds(file->bcm_player, file, &firstIndex, &lastIndex);
1164    if (rc!=0) {
1165        BDBG_WRN(("can't obtain file bounds"));
1166        goto done;
1167    }
1168    rc = BNAV_Player_GetPositionInformation(file->bcm_player, firstIndex, &first);
1169    if (rc!=0) {
1170        BDBG_WRN(("can't obtain first position "));
1171        rc = BNAV_Player_GetPositionInformation(file->bcm_player, firstIndex+1, &first);
1172        if (rc!=0) {
1173            BDBG_WRN(("..2nd Attempt also failed !"));
1174            goto done;
1175        }
1176    }
1177    rc = BNAV_Player_GetPositionInformation(file->bcm_player, lastIndex, &last);
1178    if (rc!=0) {
1179        BDBG_WRN(("can't obtain last position"));
1180        goto done;
1181    }
1182
1183    BDBG_INSTANCE_MSG(file, ("position %ld:%lu:%lld %ld:%lu:%lld ",
1184        firstIndex, first.timestamp,B_GET_OFF_T(&first), lastIndex, last.timestamp, B_GET_OFF_T(&last)));
1185
1186    interval = file->cfg.interval*1000;
1187
1188    if (last.timestamp - first.timestamp > interval) {
1189        long index;
1190        off_t off;
1191
1192        index = BNAV_Player_FindIndexFromTimestamp(file->bcm_player, last.timestamp - interval);
1193        if (index<0) {
1194            BDBG_WRN(("can't obtain new index"));
1195            goto done;
1196        }
1197        last = first; /* needed for debuging to save previous first */
1198        rc = BNAV_Player_GetPositionInformation(file->bcm_player, index, &first);
1199        if (rc!=0) {
1200            BDBG_WRN(("can't obtain new position"));
1201            goto done;
1202        }
1203        BDBG_MSG(("trimming from %d:%u:%lld to %d:%u:%lld", last.index, last.timestamp, B_GET_OFF_T(&last), index, first.timestamp, B_GET_OFF_T(&first)));
1204        off = index*file->index_entrysize;
1205        BDBG_MSG(("trimming index old %lld new %lld", (int64_t)file->index.trim_off, (int64_t)off));
1206        file->index.trim_off = off;
1207        file->index.trim_count = 1;
1208
1209        file->index.file->header->trim_gap = (index - file->index.file->header->prev_trim)*file->index_entrysize;
1210
1211        file->index.file->header->prev_trim = last.index;
1212
1213        off = B_GET_OFF_T(&first) - first.metadataOffset;
1214#ifdef DIRECT_IO_SUPPORT
1215        off -= off % B_DATA_ALIGN;
1216#endif
1217        BDBG_MSG(("trimming data old %lld new %lld", (int64_t)file->data.trim_off, (int64_t)off));
1218        file->data.trim_off = off;
1219        file->data.trim_count = 1;
1220
1221        timeout = B_TRIM_TRY_TIMER; /* do a trim on the next timer callout */
1222    }
1223done:
1224    file->timer = NEXUS_ScheduleTimer(timeout, b_trim_timer, file);  /* schedulle another heartbeat for the trim */
1225    NEXUS_Time_Get(&stop);
1226    BDBG_MSG(("trim_timer(%#x) %ldms", (unsigned)file , NEXUS_Time_Diff(&stop, &start)));
1227
1228    if (!file->timer) {
1229        BDBG_ERR(("trim hearbeat has died"));
1230        return;
1231    }
1232
1233    return;
1234}
1235
1236
1237NEXUS_FifoRecordHandle
1238NEXUS_FifoRecord_Create(const char *fname, const char *indexname)
1239{
1240    NEXUS_FifoRecordHandle file;
1241    NEXUS_Error rc;
1242
1243    if (fname==NULL) { rc=BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; }
1244    if (indexname==NULL) { rc=BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; }
1245
1246    file = BKNI_Malloc(sizeof(*file));
1247    if (!file) { rc=BERR_TRACE(NEXUS_INVALID_PARAMETER); goto err_alloc; }
1248
1249    BKNI_Memset(file, 0, sizeof *file);
1250
1251    file->cfg.interval = 30;
1252    file->cfg.snapshotInterval = 0;
1253    file->cfg.data.soft = 512*1024*1024;
1254    file->cfg.data.hard = 1024*1024*1024;
1255    file->cfg.data.soft -= file->cfg.data.soft % B_DATA_ALIGN;
1256    file->cfg.data.hard -= file->cfg.data.hard % B_DATA_ALIGN;
1257    file->cfg.index.soft = 4*1024*1024;
1258    file->cfg.index.hard = 8*1024*1024;
1259
1260    file->data.trim_count = 0;
1261
1262    NEXUS_Time_Get(&file->lastSnapshotTime);
1263
1264    file->data.file = bpvrfifo_write_open(fname, true, 0);
1265    if (!file->data.file) { goto err_data;}
1266    file->data.file->size = file->cfg.data.soft;
1267
1268    file->index.trim_count = 0;
1269    file->index.file = bpvrfifo_write_open(indexname, false, 2*sizeof(file->data.file->header->data));
1270    if (!file->index.file) { goto err_index;}
1271    file->index.file->size = file->cfg.index.soft;
1272
1273    file->rd_index = bpvrfifo_read_open(indexname, false, file->index.file);
1274    if (!file->rd_index) { goto err_rd_index;}
1275
1276
1277    file->self.index = bpvrfifo_write_file(file->index.file);
1278    file->self.data = bpvrfifo_write_file(file->data.file);
1279
1280    file->self.close = bfile_fifo_close_out;
1281
1282    file->index_entrysize = BNAV_GetEntrySize(BNAV_VersionOriginal); /* default */
1283    file->bcm_player = NULL;
1284
1285    file->index.trim_count = file->data.trim_count = 0;
1286    file->index.trim_off = file->data.trim_off = 0;
1287
1288    /* timer shall be the last call in the initialization sequence */
1289    file->timer = NEXUS_ScheduleTimer(B_TRIM_TIMER, b_trim_timer, file);  /* schedulle heartbeat for the trim */
1290    if (!file->timer) { goto err_timer; }
1291
1292    return file;
1293
1294err_timer:
1295    bpvrfifo_read_close(file->rd_index);
1296err_rd_index:
1297    bpvrfifo_write_close(file->index.file);
1298err_index:
1299    bpvrfifo_write_close(file->data.file);
1300err_data:
1301    BKNI_Free(file);
1302err_alloc:
1303    return NULL;
1304}
1305
1306NEXUS_FileRecordHandle
1307NEXUS_FifoRecord_GetFile(NEXUS_FifoRecordHandle file)
1308{
1309    return &file->self;
1310}
1311
1312NEXUS_Error
1313NEXUS_FifoRecord_GetPosition(NEXUS_FifoRecordHandle file, NEXUS_FilePosition *first, NEXUS_FilePosition *last)
1314{
1315    long firstIndex, lastIndex;
1316    BNAV_Player_Position pos;
1317    int rc;
1318
1319    b_trim_try_player(file);
1320    if(file->bcm_player==NULL) {
1321        BDBG_MSG(("index file is empty, position can't be extracted"));
1322        /* fill them with zeros */
1323        if(first) {
1324            first->mpegFileOffset = 0;
1325            first->indexOffset = NEXUS_FILE_INVALID_POSITION;
1326            first->timestamp = NEXUS_FILE_INVALID_POSITION;
1327        }
1328        if(last) { /* fill them with zeros */
1329            last->mpegFileOffset = 0;
1330            last->indexOffset = NEXUS_FILE_INVALID_POSITION;
1331            last->timestamp = NEXUS_FILE_INVALID_POSITION;
1332        }
1333        return NEXUS_SUCCESS;
1334    }
1335    rc = bp_bounds(file->bcm_player, file, &firstIndex, &lastIndex);
1336    if (rc!=0) { return BERR_TRACE(NEXUS_UNKNOWN); }
1337    if (first) {
1338        rc = BNAV_Player_GetPositionInformation(file->bcm_player, firstIndex, &pos);
1339        if (rc!=0) { return BERR_TRACE(NEXUS_UNKNOWN); }
1340        first->indexOffset = pos.index;
1341        first->timestamp = pos.timestamp;
1342        first->mpegFileOffset = B_GET_OFF_T(&pos);
1343    }
1344    if (last) {
1345        rc = BNAV_Player_GetPositionInformation(file->bcm_player, lastIndex, &pos);
1346        if (rc!=0) { return BERR_TRACE(NEXUS_UNKNOWN); }
1347        last->indexOffset = pos.index;
1348        last->timestamp = pos.timestamp;
1349        last->mpegFileOffset = B_GET_OFF_T(&pos);
1350    }
1351    return NEXUS_SUCCESS;
1352}
1353
1354void
1355NEXUS_FifoRecord_GetSettings(NEXUS_FifoRecordHandle file, NEXUS_FifoRecordSettings *settings)
1356{
1357    /* settings are read only, so wa don't need synchronization here */
1358    *settings = file->cfg;
1359    return;
1360}
1361
1362
1363NEXUS_Error
1364NEXUS_FifoRecord_SetSettings(NEXUS_FifoRecordHandle file, const NEXUS_FifoRecordSettings *settings)
1365{
1366    if (
1367        settings->index.soft <= 2*sizeof(*file->data.file->header) ||
1368        settings->index.soft >= 2*1024*1024*(off_t)1024 ||
1369        settings->index.hard <= 2*sizeof(*file->data.file->header) ||
1370        settings->index.hard >= 2*1024*1024*(off_t)1024 ||
1371        settings->index.hard < settings->index.soft ||
1372        settings->data.soft <= B_DATA_ALIGN ||
1373        settings->data.hard <= B_DATA_ALIGN ||
1374        settings->data.hard < settings->index.soft )
1375    {
1376        return BERR_TRACE(NEXUS_INVALID_PARAMETER);
1377    }
1378    /* we don't need synchronization here either */
1379    file->cfg = *settings;
1380    file->cfg.data.soft -= file->cfg.data.soft % B_DATA_ALIGN;
1381    file->cfg.data.hard -= file->cfg.data.hard % B_DATA_ALIGN;
1382    BDBG_INSTANCE_MSG(file, ("fifo_out_set: %u index(%lld:%lld) data(%lld:%lld)", file->cfg.interval, file->cfg.data.soft, file->cfg.data.hard, file->cfg.index.soft, file->cfg.index.hard));
1383    /* XXX we should truncate file somewhere, sometime */
1384    b_lock(file->index.file);
1385    file->index.file->size = file->cfg.index.soft;
1386    b_unlock(file->index.file);
1387    b_lock(file->data.file);
1388    file->data.file->size = file->cfg.data.soft;
1389    b_unlock(file->data.file);
1390    return NEXUS_SUCCESS;
1391}
1392
Note: See TracBrowser for help on using the repository browser.