summaryrefslogtreecommitdiffstats
path: root/apps/plugins/mpegplayer/disk_buf.h
blob: bc76ab6dc353c02d08f77258a88f62283478ade4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * AV disk buffer declarations
 *
 * Copyright (c) 2007 Michael Sevakis
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/
#ifndef DISK_BUF_H
#define DISK_BUF_H

#ifndef OFF_T_MAX
#define OFF_T_MAX (~((off_t)1 << (sizeof (off_t)*8 - 1)))
#endif

#ifndef OFF_T_MIN
#define OFF_T_MIN ((off_t)1 << (sizeof (off_t)*8 - 1))
#endif

#define DISK_BUF_PAGE_SHIFT 15  /* 32KB cache lines */
#define DISK_BUF_PAGE_SIZE (1 << DISK_BUF_PAGE_SHIFT)
#define DISK_BUF_PAGE_MASK (DISK_BUF_PAGE_SIZE-1)

enum
{
    DISK_BUF_NOTIFY_ERROR = -1,
    DISK_BUF_NOTIFY_NULL  =  0,
    DISK_BUF_NOTIFY_OK,
    DISK_BUF_NOTIFY_TIMEDOUT,
    DISK_BUF_NOTIFY_PROCESS_EVENT,
    DISK_BUF_NOTIFY_REGISTERED,
};

/** Macros to map file offsets to cached data **/

/* Returns a cache tag given a file offset */
#define MAP_OFFSET_TO_TAG(o) \
    ((o) >> DISK_BUF_PAGE_SHIFT)

/* Returns the cache page number given a file offset */
#define MAP_OFFSET_TO_PAGE(o) \
    (MAP_OFFSET_TO_TAG(o) % disk_buf.pgcount)

/* Returns the buffer offset given a file offset */
#define MAP_OFFSET_TO_BUFFER(o) \
    (MAP_OFFSET_TO_PAGE(o) * DISK_BUF_PAGE_SIZE)

struct dbuf_range
{
    uint32_t tag_start;
    uint32_t tag_end;
    int pg_start;
};

#define DISK_BUF_L2_CACHE_SHIFT 6
#define DISK_BUF_L2_CACHE_SIZE (1 << DISK_BUF_L2_CACHE_SHIFT)
#define DISK_BUF_L2_CACHE_MASK (DISK_BUF_L2_CACHE_SIZE-1)

struct dbuf_l2_cache
{
    off_t addr;                              /* L2 file offset */
    size_t size;                             /* Real size */
    uint8_t data[DISK_BUF_L2_CACHE_SIZE*2];  /* Local data and guard */
};

void dbuf_l2_init(struct dbuf_l2_cache *l2_p);

/* This object is an extension of the stream manager and handles some
 * playback events as well as buffering */
struct disk_buf
{
    unsigned int thread;
    struct event_queue *q;
    uint8_t *start;   /* Start pointer */
    uint8_t *end;     /* End of buffer pointer less MPEG_GUARDBUF_SIZE. The
                         guard space is used to wrap data at the buffer start to
                         pass continuous data packets */
    uint8_t *tail;    /* Location of last data + 1 filled into the buffer */
    ssize_t size;     /* The buffer length _not_ including the guard space (end-start) */
    int    pgcount;   /* Total number of available cached pages */
    uint32_t *cache;  /* Pointer to cache structure - allocated on buffer */
    int    in_file;   /* File being read */
    ssize_t filesize; /* Size of file in_file in bytes */
    int file_pages;   /* Number of pages in file (rounded up) */
    off_t offset;     /* Current position (random access) */
    off_t win_left;   /* Left edge of buffer window (streaming) */
    off_t win_right;  /* Right edge of buffer window (streaming) */
    uint32_t time_last; /* Last time watermark was checked */
    off_t pos_last;   /* Last position at watermark check time */
    ssize_t low_wm;   /* The low watermark for automatic rebuffering */
    int status;       /* Status as stream */
    int state;        /* Current thread state */
    bool need_seek;   /* Need to seek because a read was not contiguous */
};

extern struct disk_buf disk_buf SHAREDBSS_ATTR;

struct stream_hdr;
bool disk_buf_is_data_ready(struct stream_hdr *sh, ssize_t margin);

bool disk_buf_init(void);
void disk_buf_exit(void);

static inline int disk_buf_status(void)
    { return disk_buf.status; }

int disk_buf_open(const char *filename);
void disk_buf_close(void);
ssize_t _disk_buf_getbuffer(size_t size, void **pp, void **pwrap,
                            size_t *sizewrap);
#define disk_buf_getbuffer(size, pp, pwrap, sizewrap) \
        _disk_buf_getbuffer((size), PUN_PTR(void **, (pp)), \
                            PUN_PTR(void **, (pwrap)), (sizewrap))

ssize_t _disk_buf_getbuffer_l2(struct dbuf_l2_cache *l2,
                               size_t size, void **pp);
#define disk_buf_getbuffer_l2(l2, size, pp) \
        _disk_buf_getbuffer_l2((l2), (size), PUN_PTR(void **, (pp)))

ssize_t disk_buf_read(void *buffer, size_t size);
ssize_t disk_buf_lseek(off_t offset, int whence);

static inline off_t disk_buf_ftell(void)
    { return disk_buf.offset; }

static inline ssize_t disk_buf_filesize(void)
    { return disk_buf.filesize; }

ssize_t disk_buf_prepare_streaming(off_t pos, size_t len);
ssize_t disk_buf_set_streaming_window(off_t left, off_t right);
void * disk_buf_offset2ptr(off_t offset);
int disk_buf_check_streaming_window(off_t left, off_t right);

intptr_t disk_buf_send_msg(long id, intptr_t data);
void disk_buf_post_msg(long id, intptr_t data);
void disk_buf_reply_msg(intptr_t retval);

#endif /* DISK_BUF_H */