source: svn/newcon3bcm2_21bu/BSEAV/lib/utils/bsink_playback.c @ 46

Last change on this file since 46 was 46, checked in by megakiss, 11 years ago

459Mhz로 OTC 주파수 변경

  • Property svn:executable set to *
File size: 14.4 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2007 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: bsink_playback.c $
11 * $brcm_Revision: 6 $
12 * $brcm_Date: 11/24/10 2:16p $
13 *
14 * Module Description:
15 *
16 * ATOM playback data sink
17 *
18 * Revision History:
19 *
20 * $brcm_Log: /BSEAV/lib/utils/bsink_playback.c $
21 *
22 * 6   11/24/10 2:16p vsilyaev
23 * SW35230-2195: Added option to seed timing on first read (helps when
24 * playback started in paused state)
25 *
26 * 5   11/23/10 8:39p vsilyaev
27 * SW35230-2195: Added compile time option to capture and restore stream
28 * data with relative timing
29 *
30 * 4   6/24/08 5:53p erickson
31 * PR44070: added fflush for  v
32 *
33 * 3   9/24/07 5:35p gmohile
34 * PR 25109: Dump PES out
35 *
36 * 2   9/20/07 7:16p gmohile
37 * PR 25109: Fix segfaults
38 *
39 * 1   8/2/07 3:57p vsilyaev
40 * PR 33751: Playback sink (destination) in SPF framework
41 *
42 *
43 ***************************************************************************/
44#include "bstd.h"
45#include "bsink_playback.h"
46#include "bkni.h"
47
48#define BDBG_MSG_TRACE(x) /* BDBG_MSG(x) */
49BDBG_MODULE(bsink_playback);
50
51/* only one should be enabled at the time, WRITE writes data to file and READ reads this data leter on */
52/* #define WRITE_TIMED_DATA 1 */
53/* #define READ_TIMED_DATA 1 */
54
55/* #define DUMP_PES_OUT 1 */
56
57#ifdef DUMP_PES_OUT
58#include <stdio.h>
59FILE *fp;
60#endif
61
62#if WRITE_TIMED_DATA  || READ_TIMED_DATA
63#include "bsink_playback_debug.h"
64#include <stdio.h>
65#include <sys/time.h>
66
67static FILE *
68b_sink_playback_open_file(const char *mode, unsigned instance, unsigned *count)
69{
70    FILE *f;
71    char name[64];
72
73    BKNI_Snprintf(name, sizeof(name), "timed_data_%u_%u.dat",  instance, *count);
74    BDBG_WRN(("using dump file '%s'", name));
75    f = fopen(name, mode);
76    BDBG_ASSERT(f);
77    (*count)++;
78    return f;
79}
80
81static long
82b_sink_playback_dump_timediff(const struct timeval *future, const struct timeval *past)
83{
84    return 1000*(future->tv_sec - past->tv_sec) + (future->tv_usec - past->tv_usec)/1000;
85}
86#endif /* WRITE_TIMED_DATA  || READ_TIMED_DATA */
87
88#if READ_TIMED_DATA
89#include "balloc.h"
90balloc_iface_t bsink_dump_reader_allocator = NULL;
91
92typedef struct b_sink_playback_read {
93    FILE *fp;
94    bool get_time;
95    unsigned count;
96    unsigned instance;
97    struct timeval start_time;
98} b_sink_playback_read;
99
100static void 
101b_sink_playback_dump_init(b_sink_playback_read *reader)
102{
103    static int bsink_instance=0;
104
105    reader->fp = NULL;
106    reader->count = 0;
107    reader->instance = bsink_instance;
108    bsink_instance++;
109    return;
110}
111
112static void 
113b_sink_playback_dump_start(b_sink_playback_read *reader)
114{
115    reader->fp = b_sink_playback_open_file("rb", reader->instance, &reader->count);
116#if 1
117    reader->get_time = true;
118#else
119    reader->get_time = false;
120    gettimeofday(&reader->start_time, NULL);
121#endif
122    return;
123}
124
125static void 
126b_sink_playback_dump_stop(b_sink_playback_read *reader)
127{
128    fclose(reader->fp);
129    reader->fp = NULL;
130}
131
132static void
133b_sink_reader_free(batom_t atom, void *user)
134{
135    batom_t src_atom = *(batom_t *)user;
136        unsigned nvecs, i;
137    const batom_vec *vecs;
138
139    BDBG_MSG(("b_sink_reader_free: %#lx %#lx", (unsigned long)atom, (unsigned long)src_atom));
140        vecs = batom_get_vectors(atom, &nvecs);
141    for(i=0;i<nvecs;i++) {
142        bsink_dump_reader_allocator->bmem_free(bsink_dump_reader_allocator, vecs[i].base);
143    }
144    batom_release(src_atom);
145    return;
146}
147
148static const batom_user b_sink_reader = {
149        b_sink_reader_free,
150        sizeof(batom_t)
151};
152
153static batom_t
154b_sink_playback_dump_data(b_sink_playback_read *reader, batom_t atom, batom_factory_t factory)
155{
156        unsigned nvecs, i;
157    int rc;
158    batom_vec *dst_vec;
159    batom_vec dst_static_vec[4];
160    bsink_playback_packet packet;
161    struct timeval now;
162    uint32_t time_diff;
163
164    BDBG_ASSERT(bsink_dump_reader_allocator);
165    if(reader->get_time) {
166        reader->get_time = false;
167        gettimeofday(&reader->start_time, NULL);
168    }
169    gettimeofday(&now, NULL);
170    for(;;) {
171        rc = fread(&packet, sizeof(packet), 1, reader->fp);
172        if(rc==1) {
173            BDBG_ASSERT(packet.sync == BSINK_PLAYBACK_SYNC);
174            break;
175        }
176        BDBG_ASSERT(rc==0);
177        BDBG_WRN(("end of source data, loop"));
178        fseek(reader->fp, 0, SEEK_SET);
179        gettimeofday(&reader->start_time, NULL);
180    }
181    time_diff = b_sink_playback_dump_timediff(&now, &reader->start_time);
182    if(packet.timestamp > time_diff) {
183        BKNI_Sleep(packet.timestamp - time_diff);
184    }
185    nvecs = packet.sequence+1;
186
187    if(nvecs<sizeof(dst_static_vec)/sizeof(*dst_static_vec)) {
188        dst_vec = dst_static_vec;
189    } else {
190        dst_vec = BKNI_Malloc(sizeof(*dst_vec)*nvecs);
191        BDBG_ASSERT(dst_vec);
192    }
193    for(i=0;;) {
194        dst_vec[i].dirty = true;
195        dst_vec[i].unused_flags = 0;
196        dst_vec[i].len = packet.length;
197        dst_vec[i].base = bsink_dump_reader_allocator->bmem_alloc(bsink_dump_reader_allocator, packet.length);
198        BDBG_ASSERT(dst_vec[i].base);
199        rc = fread(dst_vec[i].base, packet.length, 1, reader->fp);
200        BDBG_ASSERT(rc==1);
201        i++;
202        if(i>=nvecs) {
203            break;
204        }
205        rc = fread(&packet, sizeof(packet), 1, reader->fp);
206        BDBG_ASSERT(rc==1);
207        BDBG_ASSERT(packet.sync == BSINK_PLAYBACK_SYNC);
208    }
209    atom = batom_from_vectors(factory, dst_vec, nvecs, &b_sink_reader, &atom);
210    BDBG_ASSERT(atom);
211    if(dst_vec != dst_static_vec) {
212        BKNI_Free(dst_vec);
213    }
214    return atom;
215}
216#elif WRITE_TIMED_DATA 
217typedef struct b_sink_playback_dump {
218    FILE *fp;
219    unsigned count;
220    unsigned instance;
221    struct timeval start_time;
222} b_sink_playback_dump;
223
224static void 
225b_sink_playback_dump_init(b_sink_playback_dump *writer)
226{
227    static int bsink_instance=0;
228
229    writer->fp = NULL;
230    writer->count = 0;
231    writer->instance = bsink_instance;
232    bsink_instance++;
233    return;
234}
235
236static void 
237b_sink_playback_dump_start(b_sink_playback_dump *writer)
238{
239    writer->fp = b_sink_playback_open_file("wb", writer->instance, &writer->count);
240    gettimeofday(&writer->start_time, NULL);
241    return;
242}
243
244static void 
245b_sink_playback_dump_stop(b_sink_playback_dump *writer)
246{
247    fclose(writer->fp);
248    writer->fp = NULL;
249}
250
251
252static batom_t
253b_sink_playback_dump_data(b_sink_playback_dump *writer, batom_t atom, batom_factory_t factory)
254{
255        unsigned nvecs, i;
256    const batom_vec *vecs;
257    bsink_playback_packet packet;
258    struct timeval now;
259
260    BSTD_UNUSED(factory);
261    gettimeofday(&now, NULL);
262    packet.sync = BSINK_PLAYBACK_SYNC;
263        vecs = batom_get_vectors(atom, &nvecs);
264    packet.timestamp = b_sink_playback_dump_timediff(&now, &writer->start_time);
265    for(i=0;i<nvecs;i++) {
266        packet.sequence =  nvecs - i - 1;
267        packet.length = vecs[i].len;
268        fwrite(&packet, sizeof(packet), 1, writer->fp);
269        fwrite(vecs[i].base, 1, vecs[i].len, writer->fp);
270    }
271    fflush(writer->fp);
272    return atom;
273}
274#else
275#define b_sink_playback_dump_init(writer)
276#define b_sink_playback_dump_start(writer)
277#define b_sink_playback_dump_stop(writer)
278#define b_sink_playback_dump_data(writer, atom, factory) (atom)
279#endif /* WRITE_TIMED_DATA */
280
281
282BDBG_OBJECT_ID(bsink_playback_t);
283
284
285#define B_SINK_PLAYBACK_NENTRIES        32
286struct bsink_playback {
287        BDBG_OBJECT(bsink_playback_t)
288        bsink_playback_cfg cfg;
289        struct {
290                batom_t atom;
291                unsigned vec;
292        } in, out;
293        batom_pipe_t out_pipe;
294        unsigned nfreedesc;
295        unsigned nplaydesc;
296        BPVRlib_Feed_OffsetEntry entries[B_SINK_PLAYBACK_NENTRIES];
297    batom_factory_t factory;
298#if READ_TIMED_DATA
299    struct b_sink_playback_read dumper;
300#elif WRITE_TIMED_DATA
301    struct b_sink_playback_dump dumper;
302#endif
303};
304
305
306void
307bsink_playback_default_cfg(bsink_playback_cfg *cfg)
308{
309        cfg->addr_to_offset = NULL;
310        cfg->cache_flush = NULL;
311        return;
312}
313
314static void
315b_sink_playback_reset(bsink_playback_t sink)
316{
317        sink->in.atom = NULL;
318        sink->in.vec = 0;
319        sink->out.atom = NULL;
320        sink->out.vec = 0;
321        sink->nfreedesc = 0;
322        sink->nplaydesc = 0;
323        return;
324}
325
326bsink_playback_t
327bsink_playback_create(batom_factory_t factory, const bsink_playback_cfg *cfg)
328{
329        bsink_playback_t sink;
330
331        BDBG_ASSERT(factory);
332        BDBG_ASSERT(cfg);
333        if(cfg->addr_to_offset == NULL || cfg->cache_flush==NULL) {
334                BDBG_ERR(("bsink_playback_create: cfg.addr_to_offset and cfg.cache_flush shall be specified"));
335                goto err_cfg;
336        }
337        sink = BKNI_Malloc(sizeof(*sink));
338        if(!sink) {
339                BDBG_ERR(("bsink_playback_create: can't allocate %u bytes", sizeof(*sink)));
340                goto err_alloc;
341        }
342        BDBG_OBJECT_INIT(sink, bsink_playback_t);
343        sink->cfg = *cfg;
344    sink->factory = factory;
345        sink->out_pipe = batom_pipe_create(factory);
346        if(!sink->out_pipe) {
347                goto err_out_pipe;
348        }
349    b_sink_playback_dump_init(&sink->dumper);
350        b_sink_playback_reset(sink);
351        return sink;
352
353err_out_pipe:
354        BKNI_Free(sink);
355err_alloc:
356err_cfg:
357        return NULL;
358}
359
360void
361bsink_playback_destroy(bsink_playback_t sink)
362{
363        BDBG_OBJECT_ASSERT(sink, bsink_playback_t);
364        batom_pipe_destroy(sink->out_pipe);
365        BDBG_OBJECT_DESTROY(sink, bsink_playback_t);
366        BKNI_Free(sink);
367        return;
368}
369
370BERR_Code
371bsink_playback_start(bsink_playback_t sink)
372{
373        BERR_Code rc;
374        BPVRlib_Feed_Status status;
375
376        BDBG_OBJECT_ASSERT(sink, bsink_playback_t);
377        b_sink_playback_reset(sink);
378        rc = BPVRlib_Feed_Start(sink->cfg.feed);
379        if(rc!=BERR_SUCCESS) {
380                rc = BERR_TRACE(rc);
381                goto error;
382        }
383        BPVRlib_Feed_GetStatus(sink->cfg.feed, &status);
384        sink->nfreedesc = status.freeDesc;
385        sink->nplaydesc = status.freeDesc;
386#ifdef DUMP_PES_OUT
387        fp=fopen("media_out.mpg", "wb");
388#endif
389    b_sink_playback_dump_start(&sink->dumper);
390error:
391        BDBG_MSG(("bsink_playback_start: %#lx %#x", (unsigned long)sink, (unsigned)rc));
392        return rc;
393}
394
395void
396bsink_playback_stop(bsink_playback_t sink)
397{
398        BDBG_OBJECT_ASSERT(sink, bsink_playback_t);
399        BDBG_MSG(("bsink_playback_stop: %#lx", (unsigned long)sink));
400
401#if 0
402        if(sink->in.atom) {
403                batom_release(sink->in.atom);
404                sink->in.atom = NULL;
405        }
406#endif
407        if(sink->out.atom) {
408                batom_release(sink->out.atom);
409                sink->out.atom = NULL;
410        }
411        batom_pipe_flush(sink->out_pipe);
412        BPVRlib_Feed_Stop(sink->cfg.feed);
413    b_sink_playback_dump_stop(&sink->dumper);
414#ifdef DUMP_PES_OUT
415        fclose(fp);
416#endif
417        return;
418}
419
420
421size_t
422bsink_playback_feed(bsink_playback_t sink, batom_pipe_t in_pipe)
423{
424        BERR_Code rc;
425        unsigned i;
426        unsigned nvecs, vec, last_vec;
427        size_t ncompleted;
428        size_t nentries;
429        batom_t atom;
430        size_t len=0;
431        BPVRlib_Feed_OffsetEntry *entries = sink->entries;
432
433        BDBG_OBJECT_ASSERT(sink, bsink_playback_t);
434        BDBG_ASSERT(in_pipe);
435        BDBG_MSG_TRACE(("bsink_playback_feed>: %#lx %#lx",  (unsigned long)sink, (unsigned long)in_pipe));
436
437        /* step 1. get number of recycled vectors */
438        rc = BPVRlib_Feed_GetCompleted(sink->cfg.feed, &ncompleted);
439        if(rc!=BERR_SUCCESS) {
440                rc = BERR_TRACE(rc);
441                goto error;
442        }
443        BDBG_MSG_TRACE(("bsink_playback_feed: %#lx completed:%u",  (unsigned long)sink, ncompleted));
444        /* step 2. recycle entries from out_pipe */
445        atom = sink->out.atom; /* load state */
446        vec = sink->out.vec;
447        for(i=ncompleted;i>0;) {
448                if(!atom) {
449                        vec = 0;
450                        atom = batom_pipe_pop(sink->out_pipe);
451                        if(!atom) {
452                                BDBG_ERR(("bsink_playback_feed: %#lx underflow left:%u", (unsigned long)sink, i));
453                                break;
454                        }
455                        BDBG_MSG_TRACE(("bsink_playback_feed: %#lx recycling:%#lx",  (unsigned long)sink, atom));
456                }
457                nvecs = batom_get_nvecs(atom);
458                BDBG_ASSERT(nvecs>vec);
459                last_vec = vec;
460                vec+=i;
461                if(vec < nvecs) {
462                        break;
463                }
464                /* completed entire atom */
465                BDBG_ASSERT(i>=(nvecs-last_vec));
466                i -= nvecs - last_vec;
467                vec = 0;
468                batom_release(atom);
469                atom=NULL;
470        }
471        sink->out.vec = vec; /* save state for the next step */
472        sink->out.atom = atom;
473
474        /* step 3. Update number of free descriotrs */
475        sink->nfreedesc += ncompleted;
476        BDBG_ASSERT(sink->nfreedesc<=sink->nplaydesc);
477
478        vec = sink->in.vec; /* load state */
479        atom = sink->in.atom;
480
481        /* step 4. Copy data from in_pipe into the BPVRlib_Feed entries */
482        do {
483                nentries = B_SINK_PLAYBACK_NENTRIES;
484                if(nentries>sink->nfreedesc) {
485                        nentries = sink->nfreedesc;
486                }
487                BDBG_MSG_TRACE(("bsink_playback_feed: %#lx free:%u",  (unsigned long)sink, nentries));
488                for(i=0;i<nentries;) {
489                        const batom_vec *vecs;
490                        if(!atom) {
491                                vec = 0;
492                                atom = batom_pipe_pop(in_pipe);
493                                if(!atom) {
494                                        break;
495                                }
496                atom = b_sink_playback_dump_data(&sink->dumper, atom, sink->factory);
497                                BDBG_MSG_TRACE(("bsink_playback_feed: %#lx feeding %#lx",  (unsigned long)sink, atom));
498                                batom_pipe_push(sink->out_pipe, atom);
499                        }
500                        vecs = batom_get_vectors(atom, &nvecs);
501                        BDBG_ASSERT(nvecs>vec);
502                        last_vec = vec + (nentries-i);
503                        if( last_vec > nvecs) {
504                                last_vec = nvecs;
505                        }
506                        BDBG_ASSERT(i+(last_vec-vec)<=nentries);
507                        /* copy vectors to the feed entries */
508                        for(;vec<last_vec;vec++,i++) {
509                                len += vecs[vec].len;
510                                entries[i].len = vecs[vec].len;
511                                if(vecs[vec].dirty) {
512                                        sink->cfg.cache_flush(vecs[vec].base, vecs[vec].len);
513                                }
514                                entries[i].offset = sink->cfg.addr_to_offset(vecs[vec].base);
515#ifdef DUMP_PES_OUT
516                                fwrite(vecs[vec].base, vecs[vec].len, 1, fp);
517                                fflush(fp);
518#endif
519                        }
520                        if(vec!=nvecs) { /* some vectors are left in the atom */
521                                BDBG_ASSERT(i==nentries);
522                                break;
523                        }
524                        /* copied entire vector */
525                        atom = NULL;
526                }
527                sink->in.vec = vec;
528                sink->in.atom = atom; /* save state for the next step */
529                if(i==0) {
530                        break; /* nothing to send */
531                }
532                BDBG_ASSERT(sink->nfreedesc>=i);
533                sink->nfreedesc -= i;
534                rc = BPVRlib_Feed_AddOffsetEntries(sink->cfg.feed, entries, i, &ncompleted);
535                if(rc!=BERR_SUCCESS) {
536                        rc = BERR_TRACE(rc);
537                        goto error;
538                }
539                if(i!=ncompleted) {
540                        BDBG_ERR(("bsink_playback_feed: %#lx BPVRlib_Feed haven't consumed expected number of entries %u:%u", (unsigned long)sink, i, ncompleted));
541                        goto error;
542                }
543        } while(i==B_SINK_PLAYBACK_NENTRIES); /* repeat until we send less than complete chunk, in which case it means either BPVRlib_Feed is full or in.pipe is empty */
544error:
545        BDBG_MSG_TRACE(("bsink_playback_feed<: %#lx  ->%u",  (unsigned long)sink, len));
546        return len;
547}
548
549
550void
551bsink_playback_get_status(bsink_playback_t sink, bsink_playback_status *status)
552{
553        BDBG_OBJECT_ASSERT(sink, bsink_playback_t);
554        /* sink is idle if no atom is borrowed and feed is idle (e.g. number of freedescriptors is equal to total number of descriptors */
555        status->idle = sink->in.atom==NULL && sink->nfreedesc == sink->nplaydesc;
556        BDBG_MSG_TRACE(("bsink_playback_status: %#lx %s", (unsigned long)sink, status->idle?"IDLE":""));
557        return;
558}
559
Note: See TracBrowser for help on using the repository browser.