diff options
Diffstat (limited to 'apps/plugins')
53 files changed, 0 insertions, 20747 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index f2ab4843c2..13db81f004 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES | |||
@@ -68,7 +68,6 @@ mikmod,viewers | |||
68 | minesweeper,games | 68 | minesweeper,games |
69 | mosaique,demos | 69 | mosaique,demos |
70 | mp3_encoder,apps | 70 | mp3_encoder,apps |
71 | mpegplayer,viewers | ||
72 | multiboot_select,apps | 71 | multiboot_select,apps |
73 | nim,games | 72 | nim,games |
74 | open_plugins,viewers | 73 | open_plugins,viewers |
diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS index 4cb57edb1b..23cd029ccc 100644 --- a/apps/plugins/SUBDIRS +++ b/apps/plugins/SUBDIRS | |||
@@ -78,10 +78,6 @@ mikmod | |||
78 | pdbox | 78 | pdbox |
79 | #endif | 79 | #endif |
80 | 80 | ||
81 | #if !defined(RB_PROFILE) && MEMORYSIZE > 2 /* mpegplayer allocates at least 2MB of RAM */ | ||
82 | mpegplayer | ||
83 | #endif | ||
84 | |||
85 | /* Lua needs at least 160 KB to work in */ | 81 | /* Lua needs at least 160 KB to work in */ |
86 | #if PLUGIN_BUFFER_SIZE >= 0x80000 | 82 | #if PLUGIN_BUFFER_SIZE >= 0x80000 |
87 | lua | 83 | lua |
diff --git a/apps/plugins/bitmaps/mono/SOURCES b/apps/plugins/bitmaps/mono/SOURCES index eb00bd9e8a..df8521dd0a 100644 --- a/apps/plugins/bitmaps/mono/SOURCES +++ b/apps/plugins/bitmaps/mono/SOURCES | |||
@@ -49,11 +49,6 @@ invadrox_fire.6x6x1.bmp | |||
49 | #endif | 49 | #endif |
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | /* MPEGplayer */ | ||
53 | mpegplayer_status_icons_8x8x1.bmp | ||
54 | mpegplayer_status_icons_12x12x1.bmp | ||
55 | mpegplayer_status_icons_16x16x1.bmp | ||
56 | |||
57 | #if LCD_WIDTH == 160 && LCD_HEIGHT == 128 && LCD_DEPTH < 16 | 52 | #if LCD_WIDTH == 160 && LCD_HEIGHT == 128 && LCD_DEPTH < 16 |
58 | superdom_boarditems.160x128x1.bmp | 53 | superdom_boarditems.160x128x1.bmp |
59 | #endif | 54 | #endif |
diff --git a/apps/plugins/bitmaps/mono/mpegplayer_status_icons_12x12x1.bmp b/apps/plugins/bitmaps/mono/mpegplayer_status_icons_12x12x1.bmp deleted file mode 100644 index 61f6a52fbc..0000000000 --- a/apps/plugins/bitmaps/mono/mpegplayer_status_icons_12x12x1.bmp +++ /dev/null | |||
Binary files differ | |||
diff --git a/apps/plugins/bitmaps/mono/mpegplayer_status_icons_16x16x1.bmp b/apps/plugins/bitmaps/mono/mpegplayer_status_icons_16x16x1.bmp deleted file mode 100644 index 944bd5132e..0000000000 --- a/apps/plugins/bitmaps/mono/mpegplayer_status_icons_16x16x1.bmp +++ /dev/null | |||
Binary files differ | |||
diff --git a/apps/plugins/bitmaps/mono/mpegplayer_status_icons_8x8x1.bmp b/apps/plugins/bitmaps/mono/mpegplayer_status_icons_8x8x1.bmp deleted file mode 100644 index d4b71fe1e0..0000000000 --- a/apps/plugins/bitmaps/mono/mpegplayer_status_icons_8x8x1.bmp +++ /dev/null | |||
Binary files differ | |||
diff --git a/apps/plugins/mpegplayer/SOURCES b/apps/plugins/mpegplayer/SOURCES deleted file mode 100644 index 3fc079dfbd..0000000000 --- a/apps/plugins/mpegplayer/SOURCES +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | libmpeg2/decode.c | ||
2 | libmpeg2/header.c | ||
3 | libmpeg2/idct.c | ||
4 | libmpeg2/motion_comp.c | ||
5 | libmpeg2/slice.c | ||
6 | |||
7 | #ifdef CPU_COLDFIRE | ||
8 | libmpeg2/idct_coldfire.S | ||
9 | libmpeg2/motion_comp_coldfire_c.c | ||
10 | libmpeg2/motion_comp_coldfire_s.S | ||
11 | #elif defined CPU_ARM | ||
12 | #if ARM_ARCH >= 6 | ||
13 | libmpeg2/idct_armv6.S | ||
14 | #else | ||
15 | libmpeg2/idct_arm.S | ||
16 | #endif | ||
17 | libmpeg2/motion_comp_arm_c.c | ||
18 | libmpeg2/motion_comp_arm_s.S | ||
19 | #else /* other CPU or SIM */ | ||
20 | libmpeg2/motion_comp_c.c | ||
21 | #endif /* CPU_* */ | ||
22 | |||
23 | |||
24 | |||
25 | alloc.c | ||
26 | video_out_rockbox.c | ||
27 | video_thread.c | ||
28 | pcm_output.c | ||
29 | audio_thread.c | ||
30 | disk_buf.c | ||
31 | mpeg_settings.c | ||
32 | stream_mgr.c | ||
33 | mpegplayer.c | ||
34 | mpeg_parser.c | ||
35 | mpeg_misc.c | ||
diff --git a/apps/plugins/mpegplayer/alloc.c b/apps/plugins/mpegplayer/alloc.c deleted file mode 100644 index cbf930a7eb..0000000000 --- a/apps/plugins/mpegplayer/alloc.c +++ /dev/null | |||
@@ -1,233 +0,0 @@ | |||
1 | /* | ||
2 | * alloc.c | ||
3 | * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> | ||
4 | * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> | ||
5 | * | ||
6 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
7 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
8 | * | ||
9 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * mpeg2dec is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | * $Id$ | ||
24 | * libmpeg2 sync history: | ||
25 | * 2008-07-01 - CVS revision 1.13 | ||
26 | */ | ||
27 | |||
28 | #include "plugin.h" | ||
29 | #include "mpegplayer.h" | ||
30 | #include <system.h> | ||
31 | |||
32 | /* Main allocator */ | ||
33 | static off_t mem_ptr; | ||
34 | static size_t bufsize; | ||
35 | static unsigned char* mallocbuf; | ||
36 | |||
37 | /* libmpeg2 allocator */ | ||
38 | static off_t mpeg2_mem_ptr SHAREDBSS_ATTR; | ||
39 | static size_t mpeg2_bufsize SHAREDBSS_ATTR; | ||
40 | static unsigned char *mpeg2_mallocbuf SHAREDBSS_ATTR; | ||
41 | static unsigned char *mpeg2_bufallocbuf SHAREDBSS_ATTR; | ||
42 | |||
43 | #if defined(DEBUG) || defined(SIMULATOR) | ||
44 | const char * mpeg_get_reason_str(int reason) | ||
45 | { | ||
46 | const char *str; | ||
47 | |||
48 | switch (reason) | ||
49 | { | ||
50 | case MPEG2_ALLOC_MPEG2DEC: | ||
51 | str = "MPEG2_ALLOC_MPEG2DEC"; | ||
52 | break; | ||
53 | case MPEG2_ALLOC_CHUNK: | ||
54 | str = "MPEG2_ALLOC_CHUNK"; | ||
55 | break; | ||
56 | case MPEG2_ALLOC_YUV: | ||
57 | str = "MPEG2_ALLOC_YUV"; | ||
58 | break; | ||
59 | case MPEG2_ALLOC_CONVERT_ID: | ||
60 | str = "MPEG2_ALLOC_CONVERT_ID"; | ||
61 | break; | ||
62 | case MPEG2_ALLOC_CONVERTED: | ||
63 | str = "MPEG2_ALLOC_CONVERTED"; | ||
64 | break; | ||
65 | case MPEG_ALLOC_MPEG2_BUFFER: | ||
66 | str = "MPEG_ALLOC_MPEG2_BUFFER"; | ||
67 | break; | ||
68 | case MPEG_ALLOC_AUDIOBUF: | ||
69 | str = "MPEG_ALLOC_AUDIOBUF"; | ||
70 | break; | ||
71 | case MPEG_ALLOC_PCMOUT: | ||
72 | str = "MPEG_ALLOC_PCMOUT"; | ||
73 | break; | ||
74 | case MPEG_ALLOC_DISKBUF: | ||
75 | str = "MPEG_ALLOC_DISKBUF"; | ||
76 | break; | ||
77 | case MPEG_ALLOC_CODEC_MALLOC: | ||
78 | str = "MPEG_ALLOC_CODEC_MALLOC"; | ||
79 | break; | ||
80 | case MPEG_ALLOC_CODEC_CALLOC: | ||
81 | str = "MPEG_ALLOC_CODEC_CALLOC"; | ||
82 | break; | ||
83 | default: | ||
84 | str = "Unknown"; | ||
85 | } | ||
86 | |||
87 | return str; | ||
88 | } | ||
89 | #endif | ||
90 | |||
91 | static void * mpeg_malloc_internal (unsigned char *mallocbuf, | ||
92 | off_t *mem_ptr, | ||
93 | size_t bufsize, | ||
94 | unsigned size, | ||
95 | int reason) | ||
96 | { | ||
97 | void *x; | ||
98 | |||
99 | DEBUGF("mpeg_alloc_internal: bs:%lu s:%u reason:%s (%d)\n", | ||
100 | (unsigned long)bufsize, size, mpeg_get_reason_str(reason), reason); | ||
101 | |||
102 | if ((size_t) (*mem_ptr + size) > bufsize) | ||
103 | { | ||
104 | DEBUGF("OUT OF MEMORY\n"); | ||
105 | return NULL; | ||
106 | } | ||
107 | |||
108 | x = &mallocbuf[*mem_ptr]; | ||
109 | *mem_ptr += (size + 3) & ~3; /* Keep memory 32-bit aligned */ | ||
110 | |||
111 | return x; | ||
112 | (void)reason; | ||
113 | } | ||
114 | |||
115 | void *mpeg_malloc(size_t size, mpeg2_alloc_t reason) | ||
116 | { | ||
117 | return mpeg_malloc_internal(mallocbuf, &mem_ptr, bufsize, size, | ||
118 | reason); | ||
119 | } | ||
120 | |||
121 | void *mpeg_malloc_all(size_t *size_out, mpeg2_alloc_t reason) | ||
122 | { | ||
123 | /* Can steal all but MIN_MEMMARGIN */ | ||
124 | if (bufsize - mem_ptr < MIN_MEMMARGIN) | ||
125 | return NULL; | ||
126 | |||
127 | *size_out = bufsize - mem_ptr - MIN_MEMMARGIN; | ||
128 | return mpeg_malloc(*size_out, reason); | ||
129 | } | ||
130 | |||
131 | bool mpeg_alloc_init(unsigned char *buf, size_t mallocsize) | ||
132 | { | ||
133 | mem_ptr = 0; | ||
134 | /* Cache-align buffer or 4-byte align */ | ||
135 | mallocbuf = buf; | ||
136 | bufsize = mallocsize; | ||
137 | ALIGN_BUFFER(mallocbuf, bufsize, CACHEALIGN_UP(4)); | ||
138 | |||
139 | /* Separate allocator for video */ | ||
140 | mpeg2_mem_ptr = 0; | ||
141 | mpeg2_mallocbuf = mallocbuf; | ||
142 | mpeg2_bufallocbuf = mallocbuf; | ||
143 | mpeg2_bufsize = CACHEALIGN_UP(LIBMPEG2_ALLOC_SIZE); | ||
144 | |||
145 | if (mpeg_malloc_internal(mallocbuf, &mem_ptr, | ||
146 | bufsize, mpeg2_bufsize, | ||
147 | MPEG_ALLOC_MPEG2_BUFFER) == NULL) | ||
148 | { | ||
149 | return false; | ||
150 | } | ||
151 | |||
152 | IF_COP(rb->commit_discard_dcache()); | ||
153 | return true; | ||
154 | } | ||
155 | |||
156 | /* allocate non-dedicated buffer space which mpeg2_mem_reset will free */ | ||
157 | void * mpeg2_malloc(unsigned size, mpeg2_alloc_t reason) | ||
158 | { | ||
159 | void *ptr = mpeg_malloc_internal(mpeg2_mallocbuf, &mpeg2_mem_ptr, | ||
160 | mpeg2_bufsize, size, reason); | ||
161 | /* libmpeg2 expects zero-initialized allocations */ | ||
162 | if (ptr) | ||
163 | rb->memset(ptr, 0, size); | ||
164 | |||
165 | return ptr; | ||
166 | } | ||
167 | |||
168 | /* allocate dedicated buffer - memory behind buffer pointer becomes dedicated | ||
169 | so order is important */ | ||
170 | void * mpeg2_bufalloc(unsigned size, mpeg2_alloc_t reason) | ||
171 | { | ||
172 | void *buf = mpeg2_malloc(size, reason); | ||
173 | |||
174 | if (buf == NULL) | ||
175 | return NULL; | ||
176 | |||
177 | mpeg2_bufallocbuf = &mpeg2_mallocbuf[mpeg2_mem_ptr]; | ||
178 | return buf; | ||
179 | } | ||
180 | |||
181 | /* return unused buffer portion and size */ | ||
182 | void * mpeg2_get_buf(size_t *size) | ||
183 | { | ||
184 | if ((size_t)mpeg2_mem_ptr + 32 >= mpeg2_bufsize) | ||
185 | return NULL; | ||
186 | |||
187 | *size = mpeg2_bufsize - mpeg2_mem_ptr; | ||
188 | return &mpeg2_mallocbuf[mpeg2_mem_ptr]; | ||
189 | } | ||
190 | |||
191 | /* de-allocate all non-dedicated buffer space */ | ||
192 | void mpeg2_mem_reset(void) | ||
193 | { | ||
194 | DEBUGF("mpeg2_mem_reset\n"); | ||
195 | mpeg2_mem_ptr = mpeg2_bufallocbuf - mpeg2_mallocbuf; | ||
196 | } | ||
197 | |||
198 | /* The following are expected by libmad */ | ||
199 | void * codec_malloc(size_t size) | ||
200 | { | ||
201 | void* ptr; | ||
202 | |||
203 | ptr = mpeg_malloc_internal(mallocbuf, &mem_ptr, | ||
204 | bufsize, size, MPEG_ALLOC_CODEC_MALLOC); | ||
205 | |||
206 | if (ptr) | ||
207 | rb->memset(ptr,0,size); | ||
208 | |||
209 | return ptr; | ||
210 | } | ||
211 | |||
212 | void * codec_calloc(size_t nmemb, size_t size) | ||
213 | { | ||
214 | void* ptr; | ||
215 | |||
216 | ptr = mpeg_malloc_internal(mallocbuf, &mem_ptr, | ||
217 | bufsize, nmemb*size, | ||
218 | MPEG_ALLOC_CODEC_CALLOC); | ||
219 | |||
220 | if (ptr) | ||
221 | rb->memset(ptr,0,size); | ||
222 | |||
223 | return ptr; | ||
224 | } | ||
225 | |||
226 | void codec_free(void* ptr) | ||
227 | { | ||
228 | DEBUGF("codec_free - %p\n", ptr); | ||
229 | #if 0 | ||
230 | mem_ptr = (void *)ptr - (void *)mallocbuf; | ||
231 | #endif | ||
232 | (void)ptr; | ||
233 | } | ||
diff --git a/apps/plugins/mpegplayer/audio_thread.c b/apps/plugins/mpegplayer/audio_thread.c deleted file mode 100644 index 764ad111f2..0000000000 --- a/apps/plugins/mpegplayer/audio_thread.c +++ /dev/null | |||
@@ -1,721 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * mpegplayer audio thread implementation | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #include "plugin.h" | ||
24 | #include "mpegplayer.h" | ||
25 | #include "codecs/libmad/bit.h" | ||
26 | #include "codecs/libmad/mad.h" | ||
27 | |||
28 | /** Audio stream and thread **/ | ||
29 | struct pts_queue_slot; | ||
30 | struct audio_thread_data | ||
31 | { | ||
32 | struct queue_event ev; /* Our event queue to receive commands */ | ||
33 | int state; /* Thread state */ | ||
34 | int status; /* Media status (STREAM_PLAYING, etc.) */ | ||
35 | int mad_errors; /* A count of the errors in each frame */ | ||
36 | unsigned samplerate; /* Current stream sample rate */ | ||
37 | int nchannels; /* Number of audio channels */ | ||
38 | struct dsp_config *dsp; /* The DSP we're using */ | ||
39 | struct dsp_buffer src; /* Current audio data for DSP processing */ | ||
40 | }; | ||
41 | |||
42 | /* The audio thread is stolen from the core codec thread */ | ||
43 | static struct event_queue audio_str_queue SHAREDBSS_ATTR; | ||
44 | static struct queue_sender_list audio_str_queue_send SHAREDBSS_ATTR; | ||
45 | struct stream audio_str IBSS_ATTR; | ||
46 | |||
47 | /* libmad related definitions */ | ||
48 | static struct mad_stream stream IBSS_ATTR; | ||
49 | static struct mad_frame frame IBSS_ATTR; | ||
50 | static struct mad_synth synth IBSS_ATTR; | ||
51 | |||
52 | /*sbsample buffer for mad_frame*/ | ||
53 | mad_fixed_t sbsample[2][36][32]; | ||
54 | |||
55 | /* 2567 bytes */ | ||
56 | static unsigned char mad_main_data[MAD_BUFFER_MDLEN]; | ||
57 | |||
58 | /* There isn't enough room for this in IRAM on PortalPlayer, but there | ||
59 | is for Coldfire. */ | ||
60 | |||
61 | /* 4608 bytes */ | ||
62 | #if defined(CPU_COLDFIRE) || defined(CPU_S5L870X) | ||
63 | static mad_fixed_t mad_frame_overlap[2][32][18] IBSS_ATTR; | ||
64 | #else | ||
65 | static mad_fixed_t mad_frame_overlap[2][32][18]; | ||
66 | #endif | ||
67 | |||
68 | /** A queue for saving needed information about MPEG audio packets **/ | ||
69 | #define AUDIODESC_QUEUE_LEN (1 << 5) /* 32 should be way more than sufficient - | ||
70 | if not, the case is handled */ | ||
71 | #define AUDIODESC_QUEUE_MASK (AUDIODESC_QUEUE_LEN-1) | ||
72 | struct audio_frame_desc | ||
73 | { | ||
74 | uint32_t time; /* Time stamp for packet in audio ticks */ | ||
75 | ssize_t size; /* Number of unprocessed bytes left in packet */ | ||
76 | }; | ||
77 | |||
78 | /* This starts out wr == rd but will never be emptied to zero during | ||
79 | streaming again in order to support initializing the first packet's | ||
80 | timestamp without a special case */ | ||
81 | struct | ||
82 | { | ||
83 | /* Compressed audio data */ | ||
84 | uint8_t *start; /* Start of encoded audio buffer */ | ||
85 | uint8_t *ptr; /* Pointer to next encoded audio data */ | ||
86 | ssize_t used; /* Number of bytes in MPEG audio buffer */ | ||
87 | /* Compressed audio data descriptors */ | ||
88 | unsigned read, write; | ||
89 | struct audio_frame_desc *curr; /* Current slot */ | ||
90 | struct audio_frame_desc descs[AUDIODESC_QUEUE_LEN]; | ||
91 | } audio_queue; | ||
92 | |||
93 | static inline int audiodesc_queue_count(void) | ||
94 | { | ||
95 | return audio_queue.write - audio_queue.read; | ||
96 | } | ||
97 | |||
98 | static inline bool audiodesc_queue_full(void) | ||
99 | { | ||
100 | return audio_queue.used >= MPA_MAX_FRAME_SIZE + MAD_BUFFER_GUARD || | ||
101 | audiodesc_queue_count() >= AUDIODESC_QUEUE_LEN; | ||
102 | } | ||
103 | |||
104 | /* Increments the queue tail postion - should be used to preincrement */ | ||
105 | static inline void audiodesc_queue_add_tail(void) | ||
106 | { | ||
107 | if (audiodesc_queue_full()) | ||
108 | { | ||
109 | DEBUGF("audiodesc_queue_add_tail: audiodesc queue full!\n"); | ||
110 | return; | ||
111 | } | ||
112 | |||
113 | audio_queue.write++; | ||
114 | } | ||
115 | |||
116 | /* Increments the queue head position - leaves one slot as current */ | ||
117 | static inline bool audiodesc_queue_remove_head(void) | ||
118 | { | ||
119 | if (audio_queue.write == audio_queue.read) | ||
120 | return false; | ||
121 | |||
122 | audio_queue.read++; | ||
123 | return true; | ||
124 | } | ||
125 | |||
126 | /* Returns the "tail" at the index just behind the write index */ | ||
127 | static inline struct audio_frame_desc * audiodesc_queue_tail(void) | ||
128 | { | ||
129 | return &audio_queue.descs[(audio_queue.write - 1) & AUDIODESC_QUEUE_MASK]; | ||
130 | } | ||
131 | |||
132 | /* Returns a pointer to the current head */ | ||
133 | static inline struct audio_frame_desc * audiodesc_queue_head(void) | ||
134 | { | ||
135 | return &audio_queue.descs[audio_queue.read & AUDIODESC_QUEUE_MASK]; | ||
136 | } | ||
137 | |||
138 | /* Resets the pts queue - call when starting and seeking */ | ||
139 | static void audio_queue_reset(void) | ||
140 | { | ||
141 | audio_queue.ptr = audio_queue.start; | ||
142 | audio_queue.used = 0; | ||
143 | audio_queue.read = 0; | ||
144 | audio_queue.write = 0; | ||
145 | rb->memset(audio_queue.descs, 0, sizeof (audio_queue.descs)); | ||
146 | audio_queue.curr = audiodesc_queue_head(); | ||
147 | } | ||
148 | |||
149 | static void audio_queue_advance_pos(ssize_t len) | ||
150 | { | ||
151 | audio_queue.ptr += len; | ||
152 | audio_queue.used -= len; | ||
153 | audio_queue.curr->size -= len; | ||
154 | } | ||
155 | |||
156 | static int audio_buffer(struct stream *str, enum stream_parse_mode type) | ||
157 | { | ||
158 | int ret = STREAM_OK; | ||
159 | |||
160 | /* Carry any overshoot to the next size since we're technically | ||
161 | -size bytes into it already. If size is negative an audio | ||
162 | frame was split across packets. Old has to be saved before | ||
163 | moving the head. */ | ||
164 | if (audio_queue.curr->size <= 0 && audiodesc_queue_remove_head()) | ||
165 | { | ||
166 | struct audio_frame_desc *old = audio_queue.curr; | ||
167 | audio_queue.curr = audiodesc_queue_head(); | ||
168 | audio_queue.curr->size += old->size; | ||
169 | old->size = 0; | ||
170 | } | ||
171 | |||
172 | /* Add packets to compressed audio buffer until it's full or the | ||
173 | * timestamp queue is full - whichever happens first */ | ||
174 | while (!audiodesc_queue_full()) | ||
175 | { | ||
176 | ret = parser_get_next_data(str, type); | ||
177 | struct audio_frame_desc *curr; | ||
178 | ssize_t len; | ||
179 | |||
180 | if (ret != STREAM_OK) | ||
181 | break; | ||
182 | |||
183 | /* Get data from next audio packet */ | ||
184 | len = str->curr_packet_end - str->curr_packet; | ||
185 | |||
186 | if (str->pkt_flags & PKT_HAS_TS) | ||
187 | { | ||
188 | audiodesc_queue_add_tail(); | ||
189 | curr = audiodesc_queue_tail(); | ||
190 | curr->time = TS_TO_TICKS(str->pts); | ||
191 | /* pts->size should have been zeroed when slot was | ||
192 | freed */ | ||
193 | } | ||
194 | else | ||
195 | { | ||
196 | /* Add to the one just behind the tail - this may be | ||
197 | * the head or the previouly added tail - whether or | ||
198 | * not we'll ever reach this is quite in question | ||
199 | * since audio always seems to have every packet | ||
200 | * timestamped */ | ||
201 | curr = audiodesc_queue_tail(); | ||
202 | } | ||
203 | |||
204 | curr->size += len; | ||
205 | |||
206 | /* Slide any remainder over to beginning */ | ||
207 | if (audio_queue.ptr > audio_queue.start && audio_queue.used > 0) | ||
208 | { | ||
209 | rb->memmove(audio_queue.start, audio_queue.ptr, | ||
210 | audio_queue.used); | ||
211 | } | ||
212 | |||
213 | /* Splice this packet onto any remainder */ | ||
214 | rb->memcpy(audio_queue.start + audio_queue.used, | ||
215 | str->curr_packet, len); | ||
216 | |||
217 | audio_queue.used += len; | ||
218 | audio_queue.ptr = audio_queue.start; | ||
219 | |||
220 | rb->yield(); | ||
221 | } | ||
222 | |||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | /* Initialise libmad */ | ||
227 | static void init_mad(void) | ||
228 | { | ||
229 | /* init the sbsample buffer */ | ||
230 | frame.sbsample_prev = &sbsample; | ||
231 | frame.sbsample = &sbsample; | ||
232 | |||
233 | /* We do this so libmad doesn't try to call codec_calloc(). This needs to | ||
234 | * be called before mad_stream_init(), mad_frame_inti() and | ||
235 | * mad_synth_init(). */ | ||
236 | frame.overlap = &mad_frame_overlap; | ||
237 | stream.main_data = &mad_main_data; | ||
238 | |||
239 | /* Call mad initialization. Those will zero the arrays frame.overlap, | ||
240 | * frame.sbsample and frame.sbsample_prev. Therefore there is no need to | ||
241 | * zero them here. */ | ||
242 | mad_stream_init(&stream); | ||
243 | mad_frame_init(&frame); | ||
244 | mad_synth_init(&synth); | ||
245 | } | ||
246 | |||
247 | /* Sync audio stream to a particular frame - see main decoder loop for | ||
248 | * detailed remarks */ | ||
249 | static int audio_sync(struct audio_thread_data *td, | ||
250 | struct str_sync_data *sd) | ||
251 | { | ||
252 | int retval = STREAM_MATCH; | ||
253 | uint32_t sdtime = TS_TO_TICKS(clip_time(&audio_str, sd->time)); | ||
254 | uint32_t time; | ||
255 | uint32_t duration = 0; | ||
256 | struct stream *str; | ||
257 | struct stream tmp_str; | ||
258 | struct mad_header header; | ||
259 | struct mad_stream stream; | ||
260 | |||
261 | if (td->ev.id == STREAM_SYNC) | ||
262 | { | ||
263 | /* Actually syncing for playback - use real stream */ | ||
264 | time = 0; | ||
265 | str = &audio_str; | ||
266 | } | ||
267 | else | ||
268 | { | ||
269 | /* Probing - use temp stream */ | ||
270 | time = INVALID_TIMESTAMP; | ||
271 | str = &tmp_str; | ||
272 | str->id = audio_str.id; | ||
273 | } | ||
274 | |||
275 | str->hdr.pos = sd->sk.pos; | ||
276 | str->hdr.limit = sd->sk.pos + sd->sk.len; | ||
277 | |||
278 | mad_stream_init(&stream); | ||
279 | mad_header_init(&header); | ||
280 | |||
281 | while (1) | ||
282 | { | ||
283 | if (audio_buffer(str, STREAM_PM_RANDOM_ACCESS) == STREAM_DATA_END) | ||
284 | { | ||
285 | DEBUGF("audio_sync:STR_DATA_END\n aqu:%ld swl:%ld swr:%ld\n", | ||
286 | (long)audio_queue.used, str->hdr.win_left, str->hdr.win_right); | ||
287 | if (audio_queue.used <= MAD_BUFFER_GUARD) | ||
288 | goto sync_data_end; | ||
289 | } | ||
290 | |||
291 | stream.error = 0; | ||
292 | mad_stream_buffer(&stream, audio_queue.ptr, audio_queue.used); | ||
293 | |||
294 | if (stream.sync && mad_stream_sync(&stream) < 0) | ||
295 | { | ||
296 | DEBUGF(" audio: mad_stream_sync failed\n"); | ||
297 | audio_queue_advance_pos(MAX(audio_queue.curr->size - 1, 1)); | ||
298 | continue; | ||
299 | } | ||
300 | |||
301 | stream.sync = 0; | ||
302 | |||
303 | if (mad_header_decode(&header, &stream) < 0) | ||
304 | { | ||
305 | DEBUGF(" audio: mad_header_decode failed:%s\n", | ||
306 | mad_stream_errorstr(&stream)); | ||
307 | audio_queue_advance_pos(1); | ||
308 | continue; | ||
309 | } | ||
310 | |||
311 | duration = 32*MAD_NSBSAMPLES(&header); | ||
312 | time = audio_queue.curr->time; | ||
313 | |||
314 | DEBUGF(" audio: ft:%u t:%u fe:%u nsamp:%u sampr:%u\n", | ||
315 | (unsigned)TICKS_TO_TS(time), (unsigned)sd->time, | ||
316 | (unsigned)TICKS_TO_TS(time + duration), | ||
317 | (unsigned)duration, header.samplerate); | ||
318 | |||
319 | audio_queue_advance_pos(stream.this_frame - audio_queue.ptr); | ||
320 | |||
321 | if (time <= sdtime && sdtime < time + duration) | ||
322 | { | ||
323 | DEBUGF(" audio: ft<=t<fe\n"); | ||
324 | retval = STREAM_PERFECT_MATCH; | ||
325 | break; | ||
326 | } | ||
327 | else if (time > sdtime) | ||
328 | { | ||
329 | DEBUGF(" audio: ft>t\n"); | ||
330 | break; | ||
331 | } | ||
332 | |||
333 | audio_queue_advance_pos(stream.next_frame - audio_queue.ptr); | ||
334 | audio_queue.curr->time += duration; | ||
335 | |||
336 | rb->yield(); | ||
337 | } | ||
338 | |||
339 | sync_data_end: | ||
340 | if (td->ev.id == STREAM_FIND_END_TIME) | ||
341 | { | ||
342 | if (time != INVALID_TIMESTAMP) | ||
343 | { | ||
344 | time = TICKS_TO_TS(time); | ||
345 | duration = TICKS_TO_TS(duration); | ||
346 | sd->time = time + duration; | ||
347 | retval = STREAM_PERFECT_MATCH; | ||
348 | } | ||
349 | else | ||
350 | { | ||
351 | retval = STREAM_NOT_FOUND; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | DEBUGF(" audio header: 0x%02X%02X%02X%02X\n", | ||
356 | (unsigned)audio_queue.ptr[0], (unsigned)audio_queue.ptr[1], | ||
357 | (unsigned)audio_queue.ptr[2], (unsigned)audio_queue.ptr[3]); | ||
358 | |||
359 | return retval; | ||
360 | (void)td; | ||
361 | } | ||
362 | |||
363 | static void audio_thread_msg(struct audio_thread_data *td) | ||
364 | { | ||
365 | while (1) | ||
366 | { | ||
367 | intptr_t reply = 0; | ||
368 | |||
369 | switch (td->ev.id) | ||
370 | { | ||
371 | case STREAM_PLAY: | ||
372 | td->status = STREAM_PLAYING; | ||
373 | |||
374 | switch (td->state) | ||
375 | { | ||
376 | case TSTATE_INIT: | ||
377 | td->state = TSTATE_DECODE; | ||
378 | case TSTATE_DECODE: | ||
379 | case TSTATE_RENDER_WAIT: | ||
380 | break; | ||
381 | |||
382 | case TSTATE_EOS: | ||
383 | /* At end of stream - no playback possible so fire the | ||
384 | * completion event */ | ||
385 | stream_generate_event(&audio_str, STREAM_EV_COMPLETE, 0); | ||
386 | break; | ||
387 | } | ||
388 | |||
389 | break; | ||
390 | |||
391 | case STREAM_PAUSE: | ||
392 | td->status = STREAM_PAUSED; | ||
393 | reply = td->state != TSTATE_EOS; | ||
394 | break; | ||
395 | |||
396 | case STREAM_STOP: | ||
397 | if (td->state == TSTATE_DATA) | ||
398 | stream_clear_notify(&audio_str, DISK_BUF_DATA_NOTIFY); | ||
399 | |||
400 | td->status = STREAM_STOPPED; | ||
401 | td->state = TSTATE_EOS; | ||
402 | |||
403 | reply = true; | ||
404 | break; | ||
405 | |||
406 | case STREAM_RESET: | ||
407 | if (td->state == TSTATE_DATA) | ||
408 | stream_clear_notify(&audio_str, DISK_BUF_DATA_NOTIFY); | ||
409 | |||
410 | td->status = STREAM_STOPPED; | ||
411 | td->state = TSTATE_INIT; | ||
412 | td->samplerate = 0; | ||
413 | td->nchannels = 0; | ||
414 | |||
415 | init_mad(); | ||
416 | td->mad_errors = 0; | ||
417 | |||
418 | audio_queue_reset(); | ||
419 | |||
420 | reply = true; | ||
421 | break; | ||
422 | |||
423 | case STREAM_NEEDS_SYNC: | ||
424 | reply = true; /* Audio always needs to */ | ||
425 | break; | ||
426 | |||
427 | case STREAM_SYNC: | ||
428 | case STREAM_FIND_END_TIME: | ||
429 | if (td->state != TSTATE_INIT) | ||
430 | break; | ||
431 | |||
432 | reply = audio_sync(td, (struct str_sync_data *)td->ev.data); | ||
433 | break; | ||
434 | |||
435 | case DISK_BUF_DATA_NOTIFY: | ||
436 | /* Our bun is done */ | ||
437 | if (td->state != TSTATE_DATA) | ||
438 | break; | ||
439 | |||
440 | td->state = TSTATE_DECODE; | ||
441 | str_data_notify_received(&audio_str); | ||
442 | break; | ||
443 | |||
444 | case STREAM_QUIT: | ||
445 | /* Time to go - make thread exit */ | ||
446 | td->state = TSTATE_EOS; | ||
447 | return; | ||
448 | } | ||
449 | |||
450 | str_reply_msg(&audio_str, reply); | ||
451 | |||
452 | if (td->status == STREAM_PLAYING) | ||
453 | { | ||
454 | switch (td->state) | ||
455 | { | ||
456 | case TSTATE_DECODE: | ||
457 | case TSTATE_RENDER_WAIT: | ||
458 | /* These return when in playing state */ | ||
459 | return; | ||
460 | } | ||
461 | } | ||
462 | |||
463 | str_get_msg(&audio_str, &td->ev); | ||
464 | } | ||
465 | } | ||
466 | |||
467 | static void audio_thread(void) | ||
468 | { | ||
469 | struct audio_thread_data td; | ||
470 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
471 | /* Up the priority since the core DSP over-yields internally */ | ||
472 | int old_priority = rb->thread_set_priority(rb->thread_self(), | ||
473 | PRIORITY_PLAYBACK-4); | ||
474 | #endif | ||
475 | |||
476 | rb->memset(&td, 0, sizeof (td)); | ||
477 | td.status = STREAM_STOPPED; | ||
478 | td.state = TSTATE_EOS; | ||
479 | |||
480 | /* We need this here to init the EMAC for Coldfire targets */ | ||
481 | init_mad(); | ||
482 | |||
483 | td.dsp = rb->dsp_get_config(CODEC_IDX_AUDIO); | ||
484 | rb->dsp_configure(td.dsp, DSP_SET_OUT_FREQUENCY, CLOCK_RATE); | ||
485 | #ifdef HAVE_PITCHCONTROL | ||
486 | rb->sound_set_pitch(PITCH_SPEED_100); | ||
487 | rb->dsp_set_timestretch(PITCH_SPEED_100); | ||
488 | #endif | ||
489 | rb->dsp_configure(td.dsp, DSP_RESET, 0); | ||
490 | rb->dsp_configure(td.dsp, DSP_FLUSH, 0); | ||
491 | rb->dsp_configure(td.dsp, DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS); | ||
492 | |||
493 | goto message_wait; | ||
494 | |||
495 | /* This is the decoding loop. */ | ||
496 | while (1) | ||
497 | { | ||
498 | td.state = TSTATE_DECODE; | ||
499 | |||
500 | /* Check for any pending messages and process them */ | ||
501 | if (str_have_msg(&audio_str)) | ||
502 | { | ||
503 | message_wait: | ||
504 | /* Wait for a message to be queued */ | ||
505 | str_get_msg(&audio_str, &td.ev); | ||
506 | |||
507 | message_process: | ||
508 | /* Process a message already dequeued */ | ||
509 | audio_thread_msg(&td); | ||
510 | |||
511 | switch (td.state) | ||
512 | { | ||
513 | /* These states are the only ones that should return */ | ||
514 | case TSTATE_DECODE: goto audio_decode; | ||
515 | case TSTATE_RENDER_WAIT: goto render_wait; | ||
516 | /* Anything else is interpreted as an exit */ | ||
517 | default: | ||
518 | { | ||
519 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
520 | rb->thread_set_priority(rb->thread_self(), old_priority); | ||
521 | #endif | ||
522 | return; | ||
523 | } | ||
524 | } | ||
525 | } | ||
526 | |||
527 | audio_decode: | ||
528 | |||
529 | /** Buffering **/ | ||
530 | switch (audio_buffer(&audio_str, STREAM_PM_STREAMING)) | ||
531 | { | ||
532 | case STREAM_DATA_NOT_READY: | ||
533 | { | ||
534 | td.state = TSTATE_DATA; | ||
535 | goto message_wait; | ||
536 | } /* STREAM_DATA_NOT_READY: */ | ||
537 | |||
538 | case STREAM_DATA_END: | ||
539 | { | ||
540 | if (audio_queue.used > MAD_BUFFER_GUARD) | ||
541 | break; /* Still have frames to decode */ | ||
542 | |||
543 | /* Used up remainder of compressed audio buffer. Wait for | ||
544 | * samples on PCM buffer to finish playing. */ | ||
545 | audio_queue_reset(); | ||
546 | |||
547 | while (1) | ||
548 | { | ||
549 | if (pcm_output_empty()) | ||
550 | { | ||
551 | td.state = TSTATE_EOS; | ||
552 | stream_generate_event(&audio_str, STREAM_EV_COMPLETE, 0); | ||
553 | break; | ||
554 | } | ||
555 | |||
556 | pcm_output_drain(); | ||
557 | str_get_msg_w_tmo(&audio_str, &td.ev, 1); | ||
558 | |||
559 | if (td.ev.id != SYS_TIMEOUT) | ||
560 | break; | ||
561 | } | ||
562 | |||
563 | goto message_wait; | ||
564 | } /* STREAM_DATA_END: */ | ||
565 | } | ||
566 | |||
567 | /** Decoding **/ | ||
568 | mad_stream_buffer(&stream, audio_queue.ptr, audio_queue.used); | ||
569 | |||
570 | int mad_stat = mad_frame_decode(&frame, &stream); | ||
571 | |||
572 | ssize_t len = stream.next_frame - audio_queue.ptr; | ||
573 | |||
574 | if (mad_stat != 0) | ||
575 | { | ||
576 | DEBUGF("audio: Stream error: %s\n", | ||
577 | mad_stream_errorstr(&stream)); | ||
578 | |||
579 | /* If something's goofed - try to perform resync by moving | ||
580 | * at least one byte at a time */ | ||
581 | audio_queue_advance_pos(MAX(len, 1)); | ||
582 | |||
583 | if (stream.error == MAD_ERROR_BUFLEN) | ||
584 | { | ||
585 | /* This makes the codec support partially corrupted files */ | ||
586 | if (++td.mad_errors <= MPA_MAX_FRAME_SIZE) | ||
587 | { | ||
588 | stream.error = 0; | ||
589 | rb->yield(); | ||
590 | continue; | ||
591 | } | ||
592 | DEBUGF("audio: Too many errors\n"); | ||
593 | } | ||
594 | else if (MAD_RECOVERABLE(stream.error)) | ||
595 | { | ||
596 | /* libmad says it can recover - just keep on decoding */ | ||
597 | rb->yield(); | ||
598 | continue; | ||
599 | } | ||
600 | else | ||
601 | { | ||
602 | /* Some other unrecoverable error */ | ||
603 | DEBUGF("audio: Unrecoverable error\n"); | ||
604 | } | ||
605 | |||
606 | /* This is too hard - bail out */ | ||
607 | td.state = TSTATE_EOS; | ||
608 | td.status = STREAM_ERROR; | ||
609 | stream_generate_event(&audio_str, STREAM_EV_COMPLETE, 0); | ||
610 | |||
611 | goto message_wait; | ||
612 | } | ||
613 | |||
614 | /* Adjust sizes by the frame size */ | ||
615 | audio_queue_advance_pos(len); | ||
616 | td.mad_errors = 0; /* Clear errors */ | ||
617 | |||
618 | /* Generate the pcm samples */ | ||
619 | mad_synth_frame(&synth, &frame); | ||
620 | |||
621 | /** Output **/ | ||
622 | if (frame.header.samplerate != td.samplerate) | ||
623 | { | ||
624 | td.samplerate = frame.header.samplerate; | ||
625 | rb->dsp_configure(td.dsp, DSP_SET_FREQUENCY, | ||
626 | td.samplerate); | ||
627 | } | ||
628 | |||
629 | if (MAD_NCHANNELS(&frame.header) != td.nchannels) | ||
630 | { | ||
631 | td.nchannels = MAD_NCHANNELS(&frame.header); | ||
632 | rb->dsp_configure(td.dsp, DSP_SET_STEREO_MODE, | ||
633 | td.nchannels == 1 ? | ||
634 | STEREO_MONO : STEREO_NONINTERLEAVED); | ||
635 | } | ||
636 | |||
637 | td.src.remcount = synth.pcm.length; | ||
638 | td.src.pin[0] = synth.pcm.samples[0]; | ||
639 | td.src.pin[1] = synth.pcm.samples[1]; | ||
640 | td.src.proc_mask = 0; | ||
641 | |||
642 | td.state = TSTATE_RENDER_WAIT; | ||
643 | |||
644 | /* Add a frame of audio to the pcm buffer. Maximum is 1152 samples. */ | ||
645 | render_wait: | ||
646 | rb->yield(); | ||
647 | |||
648 | while (1) | ||
649 | { | ||
650 | struct dsp_buffer dst; | ||
651 | dst.remcount = 0; | ||
652 | dst.bufcount = MAX(td.src.remcount, 1024); | ||
653 | |||
654 | ssize_t size = dst.bufcount * 2 * sizeof(int16_t); | ||
655 | |||
656 | /* Wait for required amount of free buffer space */ | ||
657 | while ((dst.p16out = pcm_output_get_buffer(&size)) == NULL) | ||
658 | { | ||
659 | /* Wait one frame */ | ||
660 | int timeout = dst.bufcount*HZ / td.samplerate; | ||
661 | str_get_msg_w_tmo(&audio_str, &td.ev, MAX(timeout, 1)); | ||
662 | if (td.ev.id != SYS_TIMEOUT) | ||
663 | goto message_process; | ||
664 | } | ||
665 | |||
666 | dst.bufcount = size / (2 * sizeof (int16_t)); | ||
667 | rb->dsp_process(td.dsp, &td.src, &dst); | ||
668 | |||
669 | if (dst.remcount > 0) | ||
670 | { | ||
671 | /* Make this data available to DMA */ | ||
672 | pcm_output_commit_data(dst.remcount * 2 * sizeof(int16_t), | ||
673 | audio_queue.curr->time); | ||
674 | |||
675 | /* As long as we're on this timestamp, the time is just | ||
676 | incremented by the number of samples */ | ||
677 | audio_queue.curr->time += dst.remcount; | ||
678 | } | ||
679 | else if (td.src.remcount <= 0) | ||
680 | { | ||
681 | break; | ||
682 | } | ||
683 | } | ||
684 | } /* end decoding loop */ | ||
685 | } | ||
686 | |||
687 | /* Initializes the audio thread resources and starts the thread */ | ||
688 | bool audio_thread_init(void) | ||
689 | { | ||
690 | /* Initialise the encoded audio buffer and its descriptors */ | ||
691 | audio_queue.start = mpeg_malloc(AUDIOBUF_ALLOC_SIZE, | ||
692 | MPEG_ALLOC_AUDIOBUF); | ||
693 | if (audio_queue.start == NULL) | ||
694 | return false; | ||
695 | |||
696 | /* Start the audio thread */ | ||
697 | audio_str.hdr.q = &audio_str_queue; | ||
698 | rb->queue_init(audio_str.hdr.q, false); | ||
699 | |||
700 | /* We steal the codec thread for audio */ | ||
701 | rb->codec_thread_do_callback(audio_thread, &audio_str.thread); | ||
702 | |||
703 | rb->queue_enable_queue_send(audio_str.hdr.q, &audio_str_queue_send, | ||
704 | audio_str.thread); | ||
705 | |||
706 | /* Wait for thread to initialize */ | ||
707 | str_send_msg(&audio_str, STREAM_NULL, 0); | ||
708 | |||
709 | return true; | ||
710 | } | ||
711 | |||
712 | /* Stops the audio thread */ | ||
713 | void audio_thread_exit(void) | ||
714 | { | ||
715 | if (audio_str.thread != 0) | ||
716 | { | ||
717 | str_post_msg(&audio_str, STREAM_QUIT, 0); | ||
718 | rb->codec_thread_do_callback(NULL, NULL); | ||
719 | audio_str.thread = 0; | ||
720 | } | ||
721 | } | ||
diff --git a/apps/plugins/mpegplayer/disk_buf.c b/apps/plugins/mpegplayer/disk_buf.c deleted file mode 100644 index 50c4222192..0000000000 --- a/apps/plugins/mpegplayer/disk_buf.c +++ /dev/null | |||
@@ -1,989 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * mpegplayer buffering routines | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #include "plugin.h" | ||
24 | #include "mpegplayer.h" | ||
25 | #include <system.h> | ||
26 | |||
27 | static struct mutex disk_buf_mtx SHAREDBSS_ATTR; | ||
28 | static struct event_queue disk_buf_queue SHAREDBSS_ATTR; | ||
29 | static struct queue_sender_list disk_buf_queue_send SHAREDBSS_ATTR; | ||
30 | static uint32_t disk_buf_stack[DEFAULT_STACK_SIZE*2/sizeof(uint32_t)]; | ||
31 | |||
32 | struct disk_buf disk_buf SHAREDBSS_ATTR; | ||
33 | static void *nf_list[MPEGPLAYER_MAX_STREAMS+1]; | ||
34 | |||
35 | static inline void disk_buf_lock(void) | ||
36 | { | ||
37 | rb->mutex_lock(&disk_buf_mtx); | ||
38 | } | ||
39 | |||
40 | static inline void disk_buf_unlock(void) | ||
41 | { | ||
42 | rb->mutex_unlock(&disk_buf_mtx); | ||
43 | } | ||
44 | |||
45 | static inline void disk_buf_on_clear_data_notify(struct stream_hdr *sh) | ||
46 | { | ||
47 | DEBUGF("DISK_BUF_CLEAR_DATA_NOTIFY: 0x%02X (cleared)\n", | ||
48 | STR_FROM_HDR(sh)->id); | ||
49 | list_remove_item(nf_list, sh); | ||
50 | } | ||
51 | |||
52 | inline bool disk_buf_is_data_ready(struct stream_hdr *sh, | ||
53 | ssize_t margin) | ||
54 | { | ||
55 | /* Data window available? */ | ||
56 | off_t right = sh->win_right; | ||
57 | |||
58 | /* Margins past end-of-file can still return true */ | ||
59 | if (right > disk_buf.filesize - margin) | ||
60 | right = disk_buf.filesize - margin; | ||
61 | |||
62 | return sh->win_left >= disk_buf.win_left && | ||
63 | right + margin <= disk_buf.win_right; | ||
64 | } | ||
65 | |||
66 | void dbuf_l2_init(struct dbuf_l2_cache *l2_p) | ||
67 | { | ||
68 | l2_p->addr = OFF_T_MAX; /* Mark as invalid */ | ||
69 | } | ||
70 | |||
71 | static int disk_buf_on_data_notify(struct stream_hdr *sh) | ||
72 | { | ||
73 | DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X ", STR_FROM_HDR(sh)->id); | ||
74 | |||
75 | if (sh->win_left <= sh->win_right) | ||
76 | { | ||
77 | /* Check if the data is already ready already */ | ||
78 | if (disk_buf_is_data_ready(sh, 0)) | ||
79 | { | ||
80 | /* It was - don't register */ | ||
81 | DEBUGF("(was ready)\n" | ||
82 | " swl:%lu swr:%lu\n" | ||
83 | " dwl:%lu dwr:%lu\n", | ||
84 | sh->win_left, sh->win_right, | ||
85 | disk_buf.win_left, disk_buf.win_right); | ||
86 | /* Be sure it's not listed though if multiple requests were made */ | ||
87 | list_remove_item(nf_list, sh); | ||
88 | return DISK_BUF_NOTIFY_OK; | ||
89 | } | ||
90 | |||
91 | switch (disk_buf.state) | ||
92 | { | ||
93 | case TSTATE_DATA: | ||
94 | case TSTATE_BUFFERING: | ||
95 | case TSTATE_INIT: | ||
96 | disk_buf.state = TSTATE_BUFFERING; | ||
97 | list_add_item(nf_list, sh); | ||
98 | DEBUGF("(registered)\n" | ||
99 | " swl:%lu swr:%lu\n" | ||
100 | " dwl:%lu dwr:%lu\n", | ||
101 | sh->win_left, sh->win_right, | ||
102 | disk_buf.win_left, disk_buf.win_right); | ||
103 | return DISK_BUF_NOTIFY_REGISTERED; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | DEBUGF("(error)\n"); | ||
108 | return DISK_BUF_NOTIFY_ERROR; | ||
109 | } | ||
110 | |||
111 | static bool check_data_notifies_callback(struct stream_hdr *sh, void *data) | ||
112 | { | ||
113 | if (disk_buf_is_data_ready(sh, 0)) | ||
114 | { | ||
115 | /* Remove from list then post notification - post because send | ||
116 | * could result in a wait for each thread to finish resulting | ||
117 | * in deadlock */ | ||
118 | list_remove_item(nf_list, sh); | ||
119 | str_post_msg(STR_FROM_HDR(sh), DISK_BUF_DATA_NOTIFY, 0); | ||
120 | DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X (notified)\n", | ||
121 | STR_FROM_HDR(sh)->id); | ||
122 | } | ||
123 | |||
124 | return true; | ||
125 | (void)data; | ||
126 | } | ||
127 | |||
128 | /* Check registered streams and notify them if their data is available */ | ||
129 | static inline void check_data_notifies(void) | ||
130 | { | ||
131 | list_enum_items(nf_list, | ||
132 | (list_enum_callback_t)check_data_notifies_callback, | ||
133 | NULL); | ||
134 | } | ||
135 | |||
136 | /* Clear all registered notifications - do not post them */ | ||
137 | static inline void clear_data_notifies(void) | ||
138 | { | ||
139 | list_clear_all(nf_list); | ||
140 | } | ||
141 | |||
142 | /* Background buffering when streaming */ | ||
143 | static inline void disk_buf_buffer(void) | ||
144 | { | ||
145 | struct stream_window sw; | ||
146 | |||
147 | switch (disk_buf.state) | ||
148 | { | ||
149 | default: | ||
150 | { | ||
151 | size_t wm; | ||
152 | uint32_t time; | ||
153 | |||
154 | /* Get remaining minimum data based upon the stream closest to the | ||
155 | * right edge of the window */ | ||
156 | if (!stream_get_window(&sw)) | ||
157 | break; | ||
158 | |||
159 | time = stream_get_ticks(NULL); | ||
160 | wm = muldiv_uint32(5*CLOCK_RATE, sw.right - disk_buf.pos_last, | ||
161 | time - disk_buf.time_last); | ||
162 | wm = MIN(wm, (size_t)disk_buf.size); | ||
163 | wm = MAX(wm, DISK_BUF_LOW_WATERMARK); | ||
164 | |||
165 | disk_buf.time_last = time; | ||
166 | disk_buf.pos_last = sw.right; | ||
167 | |||
168 | /* Fast attack, slow decay */ | ||
169 | disk_buf.low_wm = (wm > (size_t)disk_buf.low_wm) ? | ||
170 | wm : AVERAGE(disk_buf.low_wm, wm, 16); | ||
171 | |||
172 | #if 0 | ||
173 | rb->splashf(0, "*%10ld %10ld", disk_buf.low_wm, | ||
174 | disk_buf.win_right - sw.right); | ||
175 | #endif | ||
176 | |||
177 | if (disk_buf.win_right - sw.right > disk_buf.low_wm) | ||
178 | break; | ||
179 | |||
180 | disk_buf.state = TSTATE_BUFFERING; | ||
181 | } /* default: */ | ||
182 | |||
183 | /* Fall-through */ | ||
184 | case TSTATE_BUFFERING: | ||
185 | { | ||
186 | ssize_t len, n; | ||
187 | uint32_t tag, *tag_p; | ||
188 | |||
189 | /* Limit buffering up to the stream with the least progress */ | ||
190 | if (!stream_get_window(&sw)) | ||
191 | { | ||
192 | disk_buf.state = TSTATE_DATA; | ||
193 | rb->storage_sleep(); | ||
194 | break; | ||
195 | } | ||
196 | |||
197 | /* Wrap pointer */ | ||
198 | if (disk_buf.tail >= disk_buf.end) | ||
199 | disk_buf.tail = disk_buf.start; | ||
200 | |||
201 | len = disk_buf.size - disk_buf.win_right + sw.left; | ||
202 | |||
203 | if (len < DISK_BUF_PAGE_SIZE) | ||
204 | { | ||
205 | /* Free space is less than one page */ | ||
206 | disk_buf.state = TSTATE_DATA; | ||
207 | disk_buf.low_wm = DISK_BUF_LOW_WATERMARK; | ||
208 | rb->storage_sleep(); | ||
209 | break; | ||
210 | } | ||
211 | |||
212 | len = disk_buf.tail - disk_buf.start; | ||
213 | tag = MAP_OFFSET_TO_TAG(disk_buf.win_right); | ||
214 | tag_p = &disk_buf.cache[len >> DISK_BUF_PAGE_SHIFT]; | ||
215 | |||
216 | if (*tag_p != tag) | ||
217 | { | ||
218 | if (disk_buf.need_seek) | ||
219 | { | ||
220 | rb->lseek(disk_buf.in_file, disk_buf.win_right, SEEK_SET); | ||
221 | disk_buf.need_seek = false; | ||
222 | } | ||
223 | |||
224 | n = rb->read(disk_buf.in_file, disk_buf.tail, DISK_BUF_PAGE_SIZE); | ||
225 | |||
226 | if (n <= 0) | ||
227 | { | ||
228 | /* Error or end of stream */ | ||
229 | disk_buf.state = TSTATE_EOS; | ||
230 | rb->storage_sleep(); | ||
231 | break; | ||
232 | } | ||
233 | |||
234 | if (len < DISK_GUARDBUF_SIZE) | ||
235 | { | ||
236 | /* Autoguard guard-o-rama - maintain guardbuffer coherency */ | ||
237 | rb->memcpy(disk_buf.end + len, disk_buf.tail, | ||
238 | MIN(DISK_GUARDBUF_SIZE - len, n)); | ||
239 | } | ||
240 | |||
241 | /* Update the cache entry for this page */ | ||
242 | *tag_p = tag; | ||
243 | } | ||
244 | else | ||
245 | { | ||
246 | /* Skipping a read */ | ||
247 | n = MIN(DISK_BUF_PAGE_SIZE, | ||
248 | disk_buf.filesize - disk_buf.win_right); | ||
249 | disk_buf.need_seek = true; | ||
250 | } | ||
251 | |||
252 | disk_buf.tail += DISK_BUF_PAGE_SIZE; | ||
253 | |||
254 | /* Keep left edge moving forward */ | ||
255 | |||
256 | /* Advance right edge in temp variable first, then move | ||
257 | * left edge if overflow would occur. This avoids a stream | ||
258 | * thinking its data might be available when it actually | ||
259 | * may not end up that way after a slide of the window. */ | ||
260 | len = disk_buf.win_right + n; | ||
261 | |||
262 | if (len - disk_buf.win_left > disk_buf.size) | ||
263 | disk_buf.win_left += n; | ||
264 | |||
265 | disk_buf.win_right = len; | ||
266 | |||
267 | /* Continue buffering until filled or file end */ | ||
268 | rb->yield(); | ||
269 | } /* TSTATE_BUFFERING: */ | ||
270 | |||
271 | case TSTATE_EOS: | ||
272 | break; | ||
273 | } /* end switch */ | ||
274 | } | ||
275 | |||
276 | static void disk_buf_on_reset(ssize_t pos) | ||
277 | { | ||
278 | int page; | ||
279 | uint32_t tag; | ||
280 | off_t anchor; | ||
281 | |||
282 | disk_buf.state = TSTATE_INIT; | ||
283 | disk_buf.status = STREAM_STOPPED; | ||
284 | clear_data_notifies(); | ||
285 | |||
286 | if (pos >= disk_buf.filesize) | ||
287 | { | ||
288 | /* Anchor on page immediately following the one containing final | ||
289 | * data */ | ||
290 | anchor = disk_buf.file_pages * DISK_BUF_PAGE_SIZE; | ||
291 | disk_buf.win_left = disk_buf.filesize; | ||
292 | } | ||
293 | else | ||
294 | { | ||
295 | anchor = pos & ~DISK_BUF_PAGE_MASK; | ||
296 | disk_buf.win_left = anchor; | ||
297 | } | ||
298 | |||
299 | /* Collect all valid data already buffered that is contiguous with the | ||
300 | * current position - probe to left, then to right */ | ||
301 | if (anchor > 0) | ||
302 | { | ||
303 | page = MAP_OFFSET_TO_PAGE(anchor); | ||
304 | tag = MAP_OFFSET_TO_TAG(anchor); | ||
305 | |||
306 | do | ||
307 | { | ||
308 | if (--tag, --page < 0) | ||
309 | page = disk_buf.pgcount - 1; | ||
310 | |||
311 | if (disk_buf.cache[page] != tag) | ||
312 | break; | ||
313 | |||
314 | disk_buf.win_left = tag << DISK_BUF_PAGE_SHIFT; | ||
315 | } | ||
316 | while (tag > 0); | ||
317 | } | ||
318 | |||
319 | if (anchor < disk_buf.filesize) | ||
320 | { | ||
321 | page = MAP_OFFSET_TO_PAGE(anchor); | ||
322 | tag = MAP_OFFSET_TO_TAG(anchor); | ||
323 | |||
324 | do | ||
325 | { | ||
326 | if (disk_buf.cache[page] != tag) | ||
327 | break; | ||
328 | |||
329 | if (++tag, ++page >= disk_buf.pgcount) | ||
330 | page = 0; | ||
331 | |||
332 | anchor += DISK_BUF_PAGE_SIZE; | ||
333 | } | ||
334 | while (anchor < disk_buf.filesize); | ||
335 | } | ||
336 | |||
337 | if (anchor >= disk_buf.filesize) | ||
338 | { | ||
339 | disk_buf.win_right = disk_buf.filesize; | ||
340 | disk_buf.state = TSTATE_EOS; | ||
341 | } | ||
342 | else | ||
343 | { | ||
344 | disk_buf.win_right = anchor; | ||
345 | } | ||
346 | |||
347 | disk_buf.tail = disk_buf.start + MAP_OFFSET_TO_BUFFER(anchor); | ||
348 | |||
349 | DEBUGF("disk buf reset\n" | ||
350 | " dwl:%ld dwr:%ld\n", | ||
351 | disk_buf.win_left, disk_buf.win_right); | ||
352 | |||
353 | /* Next read position is at right edge */ | ||
354 | rb->lseek(disk_buf.in_file, disk_buf.win_right, SEEK_SET); | ||
355 | disk_buf.need_seek = false; | ||
356 | |||
357 | disk_buf_reply_msg(disk_buf.win_right - disk_buf.win_left); | ||
358 | } | ||
359 | |||
360 | static void disk_buf_on_stop(void) | ||
361 | { | ||
362 | bool was_buffering = disk_buf.state == TSTATE_BUFFERING; | ||
363 | |||
364 | disk_buf.state = TSTATE_EOS; | ||
365 | disk_buf.status = STREAM_STOPPED; | ||
366 | clear_data_notifies(); | ||
367 | |||
368 | disk_buf_reply_msg(was_buffering); | ||
369 | } | ||
370 | |||
371 | static void disk_buf_on_play_pause(bool play, bool forcefill) | ||
372 | { | ||
373 | struct stream_window sw; | ||
374 | |||
375 | if (disk_buf.state != TSTATE_EOS) | ||
376 | { | ||
377 | if (forcefill) | ||
378 | { | ||
379 | /* Force buffer filling to top */ | ||
380 | disk_buf.state = TSTATE_BUFFERING; | ||
381 | } | ||
382 | else if (disk_buf.state != TSTATE_BUFFERING) | ||
383 | { | ||
384 | /* If not filling already, simply monitor */ | ||
385 | disk_buf.state = TSTATE_DATA; | ||
386 | } | ||
387 | } | ||
388 | /* else end of stream - no buffering to do */ | ||
389 | |||
390 | disk_buf.pos_last = stream_get_window(&sw) ? sw.right : 0; | ||
391 | disk_buf.time_last = stream_get_ticks(NULL); | ||
392 | |||
393 | disk_buf.status = play ? STREAM_PLAYING : STREAM_PAUSED; | ||
394 | } | ||
395 | |||
396 | static int disk_buf_on_load_range(struct dbuf_range *rng) | ||
397 | { | ||
398 | uint32_t tag = rng->tag_start; | ||
399 | uint32_t tag_end = rng->tag_end; | ||
400 | int page = rng->pg_start; | ||
401 | |||
402 | /* Check if a seek is required */ | ||
403 | bool need_seek = rb->lseek(disk_buf.in_file, 0, SEEK_CUR) | ||
404 | != (off_t)(tag << DISK_BUF_PAGE_SHIFT); | ||
405 | |||
406 | do | ||
407 | { | ||
408 | uint32_t *tag_p = &disk_buf.cache[page]; | ||
409 | |||
410 | if (*tag_p != tag) | ||
411 | { | ||
412 | /* Page not cached - load it */ | ||
413 | ssize_t o, n; | ||
414 | |||
415 | if (need_seek) | ||
416 | { | ||
417 | rb->lseek(disk_buf.in_file, tag << DISK_BUF_PAGE_SHIFT, | ||
418 | SEEK_SET); | ||
419 | need_seek = false; | ||
420 | } | ||
421 | |||
422 | o = page << DISK_BUF_PAGE_SHIFT; | ||
423 | n = rb->read(disk_buf.in_file, disk_buf.start + o, | ||
424 | DISK_BUF_PAGE_SIZE); | ||
425 | |||
426 | if (n < 0) | ||
427 | { | ||
428 | /* Read error */ | ||
429 | return DISK_BUF_NOTIFY_ERROR; | ||
430 | } | ||
431 | |||
432 | if (n == 0) | ||
433 | { | ||
434 | /* End of file */ | ||
435 | break; | ||
436 | } | ||
437 | |||
438 | if (o < DISK_GUARDBUF_SIZE) | ||
439 | { | ||
440 | /* Autoguard guard-o-rama - maintain guardbuffer coherency */ | ||
441 | rb->memcpy(disk_buf.end + o, disk_buf.start + o, | ||
442 | MIN(DISK_GUARDBUF_SIZE - o, n)); | ||
443 | } | ||
444 | |||
445 | /* Update the cache entry */ | ||
446 | *tag_p = tag; | ||
447 | } | ||
448 | else | ||
449 | { | ||
450 | /* Skipping a disk read - must seek on next one */ | ||
451 | need_seek = true; | ||
452 | } | ||
453 | |||
454 | if (++page >= disk_buf.pgcount) | ||
455 | page = 0; | ||
456 | } | ||
457 | while (++tag <= tag_end); | ||
458 | |||
459 | return DISK_BUF_NOTIFY_OK; | ||
460 | } | ||
461 | |||
462 | static void disk_buf_thread(void) | ||
463 | { | ||
464 | struct queue_event ev; | ||
465 | |||
466 | disk_buf.state = TSTATE_EOS; | ||
467 | disk_buf.status = STREAM_STOPPED; | ||
468 | |||
469 | while (1) | ||
470 | { | ||
471 | if (disk_buf.state != TSTATE_EOS) | ||
472 | { | ||
473 | /* Poll buffer status and messages */ | ||
474 | rb->queue_wait_w_tmo(disk_buf.q, &ev, | ||
475 | disk_buf.state == TSTATE_BUFFERING ? | ||
476 | 0 : HZ/5); | ||
477 | } | ||
478 | else | ||
479 | { | ||
480 | /* Sit idle and wait for commands */ | ||
481 | rb->queue_wait(disk_buf.q, &ev); | ||
482 | } | ||
483 | |||
484 | switch (ev.id) | ||
485 | { | ||
486 | case SYS_TIMEOUT: | ||
487 | if (disk_buf.state == TSTATE_EOS) | ||
488 | break; | ||
489 | |||
490 | disk_buf_buffer(); | ||
491 | |||
492 | /* Check for any due notifications if any are pending */ | ||
493 | if (*nf_list != NULL) | ||
494 | check_data_notifies(); | ||
495 | |||
496 | /* Still more data left? */ | ||
497 | if (disk_buf.state != TSTATE_EOS) | ||
498 | continue; | ||
499 | |||
500 | /* Nope - end of stream */ | ||
501 | break; | ||
502 | |||
503 | case DISK_BUF_CACHE_RANGE: | ||
504 | disk_buf_reply_msg(disk_buf_on_load_range( | ||
505 | (struct dbuf_range *)ev.data)); | ||
506 | break; | ||
507 | |||
508 | case STREAM_RESET: | ||
509 | disk_buf_on_reset(ev.data); | ||
510 | break; | ||
511 | |||
512 | case STREAM_STOP: | ||
513 | disk_buf_on_stop(); | ||
514 | break; | ||
515 | |||
516 | case STREAM_PAUSE: | ||
517 | case STREAM_PLAY: | ||
518 | disk_buf_on_play_pause(ev.id == STREAM_PLAY, ev.data != 0); | ||
519 | disk_buf_reply_msg(1); | ||
520 | break; | ||
521 | |||
522 | case STREAM_QUIT: | ||
523 | disk_buf.state = TSTATE_EOS; | ||
524 | return; | ||
525 | |||
526 | case DISK_BUF_DATA_NOTIFY: | ||
527 | disk_buf_reply_msg(disk_buf_on_data_notify( | ||
528 | (struct stream_hdr *)ev.data)); | ||
529 | break; | ||
530 | |||
531 | case DISK_BUF_CLEAR_DATA_NOTIFY: | ||
532 | disk_buf_on_clear_data_notify((struct stream_hdr *)ev.data); | ||
533 | disk_buf_reply_msg(1); | ||
534 | break; | ||
535 | } | ||
536 | } | ||
537 | } | ||
538 | |||
539 | /* Caches some data from the current file */ | ||
540 | static ssize_t disk_buf_probe(off_t start, size_t length, void **p) | ||
541 | { | ||
542 | off_t end; | ||
543 | uint32_t tag, tag_end; | ||
544 | int page; | ||
545 | |||
546 | /* Can't read past end of file */ | ||
547 | if (length > (size_t)(disk_buf.filesize - start)) | ||
548 | { | ||
549 | length = disk_buf.filesize - start; | ||
550 | } | ||
551 | |||
552 | /* Can't cache more than the whole buffer size */ | ||
553 | if (length > (size_t)disk_buf.size) | ||
554 | { | ||
555 | length = disk_buf.size; | ||
556 | } | ||
557 | /* Zero-length probes permitted */ | ||
558 | |||
559 | end = start + length; | ||
560 | |||
561 | /* Prepare the range probe */ | ||
562 | tag = MAP_OFFSET_TO_TAG(start); | ||
563 | tag_end = MAP_OFFSET_TO_TAG(end); | ||
564 | page = MAP_OFFSET_TO_PAGE(start); | ||
565 | |||
566 | /* If the end is on a page boundary, check one less or an extra | ||
567 | * one will be probed */ | ||
568 | if (tag_end > tag && (end & DISK_BUF_PAGE_MASK) == 0) | ||
569 | { | ||
570 | tag_end--; | ||
571 | } | ||
572 | |||
573 | if (p != NULL) | ||
574 | { | ||
575 | *p = disk_buf.start + (page << DISK_BUF_PAGE_SHIFT) | ||
576 | + (start & DISK_BUF_PAGE_MASK); | ||
577 | } | ||
578 | |||
579 | /* Obtain initial load point. If all data was cached, no message is sent | ||
580 | * otherwise begin on the first page that is not cached. Since we have to | ||
581 | * send the message anyway, the buffering thread will determine what else | ||
582 | * requires loading on its end in order to cache the specified range. */ | ||
583 | do | ||
584 | { | ||
585 | if (disk_buf.cache[page] != tag) | ||
586 | { | ||
587 | static struct dbuf_range rng IBSS_ATTR; | ||
588 | intptr_t result; | ||
589 | |||
590 | DEBUGF("disk_buf: cache miss\n"); | ||
591 | rng.tag_start = tag; | ||
592 | rng.tag_end = tag_end; | ||
593 | rng.pg_start = page; | ||
594 | |||
595 | result = rb->queue_send(disk_buf.q, DISK_BUF_CACHE_RANGE, | ||
596 | (intptr_t)&rng); | ||
597 | |||
598 | return result == DISK_BUF_NOTIFY_OK ? (ssize_t)length : -1; | ||
599 | } | ||
600 | |||
601 | if (++page >= disk_buf.pgcount) | ||
602 | page = 0; | ||
603 | } | ||
604 | while (++tag <= tag_end); | ||
605 | |||
606 | return length; | ||
607 | } | ||
608 | |||
609 | /* Attempt to get a pointer to size bytes on the buffer. Returns real amount of | ||
610 | * data available as well as the size of non-wrapped data after *p. */ | ||
611 | ssize_t _disk_buf_getbuffer(size_t size, void **pp, void **pwrap, | ||
612 | size_t *sizewrap) | ||
613 | { | ||
614 | disk_buf_lock(); | ||
615 | |||
616 | size = disk_buf_probe(disk_buf.offset, size, pp); | ||
617 | |||
618 | if (size != (size_t)-1 && pwrap && sizewrap) | ||
619 | { | ||
620 | uint8_t *p = (uint8_t *)*pp; | ||
621 | |||
622 | if (p + size > disk_buf.end + DISK_GUARDBUF_SIZE) | ||
623 | { | ||
624 | /* Return pointer to wraparound and the size of same */ | ||
625 | size_t nowrap = (disk_buf.end + DISK_GUARDBUF_SIZE) - p; | ||
626 | *pwrap = disk_buf.start + DISK_GUARDBUF_SIZE; | ||
627 | *sizewrap = size - nowrap; | ||
628 | } | ||
629 | else | ||
630 | { | ||
631 | *pwrap = NULL; | ||
632 | *sizewrap = 0; | ||
633 | } | ||
634 | } | ||
635 | |||
636 | disk_buf_unlock(); | ||
637 | |||
638 | return size; | ||
639 | } | ||
640 | |||
641 | ssize_t _disk_buf_getbuffer_l2(struct dbuf_l2_cache *l2, | ||
642 | size_t size, void **pp) | ||
643 | { | ||
644 | off_t offs; | ||
645 | off_t l2_addr; | ||
646 | size_t l2_size; | ||
647 | void *l2_p; | ||
648 | |||
649 | if (l2 == NULL) | ||
650 | { | ||
651 | /* Shouldn't have to check this normally */ | ||
652 | DEBUGF("disk_buf_getbuffer_l2: l2 = NULL!\n"); | ||
653 | } | ||
654 | |||
655 | if (size > DISK_BUF_L2_CACHE_SIZE) | ||
656 | { | ||
657 | /* Asking for too much; just go through L1 */ | ||
658 | return disk_buf_getbuffer(size, pp, NULL, NULL); | ||
659 | } | ||
660 | |||
661 | offs = disk_buf.offset; /* Other calls keep this within bounds */ | ||
662 | l2_addr = l2->addr; | ||
663 | |||
664 | if (offs >= l2_addr && offs < l2_addr + DISK_BUF_L2_CACHE_SIZE) | ||
665 | { | ||
666 | /* Data is in the local buffer */ | ||
667 | offs &= DISK_BUF_L2_CACHE_MASK; | ||
668 | |||
669 | *pp = l2->data + offs; | ||
670 | if (offs + size > l2->size) | ||
671 | size = l2->size - offs; /* Keep size within file limits */ | ||
672 | |||
673 | return size; | ||
674 | } | ||
675 | |||
676 | /* Have to probe main buffer */ | ||
677 | l2_addr = offs & ~DISK_BUF_L2_CACHE_MASK; | ||
678 | l2_size = DISK_BUF_L2_CACHE_SIZE*2; /* 2nd half is a guard buffer */ | ||
679 | |||
680 | disk_buf_lock(); | ||
681 | |||
682 | l2_size = disk_buf_probe(l2_addr, l2_size, &l2_p); | ||
683 | |||
684 | if (l2_size != (size_t)-1) | ||
685 | { | ||
686 | rb->memcpy(l2->data, l2_p, l2_size); | ||
687 | |||
688 | l2->addr = l2_addr; | ||
689 | l2->size = l2_size; | ||
690 | offs -= l2_addr; | ||
691 | |||
692 | *pp = l2->data + offs; | ||
693 | if (offs + size > l2->size) | ||
694 | size = l2->size - offs; /* Keep size within file limits */ | ||
695 | } | ||
696 | else | ||
697 | { | ||
698 | size = -1; | ||
699 | } | ||
700 | |||
701 | disk_buf_unlock(); | ||
702 | |||
703 | return size; | ||
704 | } | ||
705 | |||
706 | |||
707 | /* Read size bytes of data into a buffer - advances the buffer pointer | ||
708 | * and returns the real size read. */ | ||
709 | ssize_t disk_buf_read(void *buffer, size_t size) | ||
710 | { | ||
711 | uint8_t *p; | ||
712 | |||
713 | disk_buf_lock(); | ||
714 | |||
715 | size = disk_buf_probe(disk_buf.offset, size, PUN_PTR(void **, &p)); | ||
716 | |||
717 | if (size != (size_t)-1) | ||
718 | { | ||
719 | if (p + size > disk_buf.end + DISK_GUARDBUF_SIZE) | ||
720 | { | ||
721 | /* Read wraps */ | ||
722 | size_t nowrap = (disk_buf.end + DISK_GUARDBUF_SIZE) - p; | ||
723 | rb->memcpy(buffer, p, nowrap); | ||
724 | rb->memcpy(buffer + nowrap, disk_buf.start + DISK_GUARDBUF_SIZE, | ||
725 | size - nowrap); | ||
726 | } | ||
727 | else | ||
728 | { | ||
729 | /* Read wasn't wrapped or guardbuffer holds it */ | ||
730 | rb->memcpy(buffer, p, size); | ||
731 | } | ||
732 | |||
733 | disk_buf.offset += size; | ||
734 | } | ||
735 | |||
736 | disk_buf_unlock(); | ||
737 | |||
738 | return size; | ||
739 | } | ||
740 | |||
741 | ssize_t disk_buf_lseek(off_t offset, int whence) | ||
742 | { | ||
743 | disk_buf_lock(); | ||
744 | |||
745 | /* The offset returned is the result of the current thread's action and | ||
746 | * may be invalidated so a local result is returned and not the value | ||
747 | * of disk_buf.offset directly */ | ||
748 | switch (whence) | ||
749 | { | ||
750 | case SEEK_SET: | ||
751 | /* offset is just the offset */ | ||
752 | break; | ||
753 | case SEEK_CUR: | ||
754 | offset += disk_buf.offset; | ||
755 | break; | ||
756 | case SEEK_END: | ||
757 | offset = disk_buf.filesize + offset; | ||
758 | break; | ||
759 | default: | ||
760 | disk_buf_unlock(); | ||
761 | return -2; /* Invalid request */ | ||
762 | } | ||
763 | |||
764 | if (offset < 0 || offset > disk_buf.filesize) | ||
765 | { | ||
766 | offset = -3; | ||
767 | } | ||
768 | else | ||
769 | { | ||
770 | disk_buf.offset = offset; | ||
771 | } | ||
772 | |||
773 | disk_buf_unlock(); | ||
774 | |||
775 | return offset; | ||
776 | } | ||
777 | |||
778 | /* Prepare the buffer to enter the streaming state. Evaluates the available | ||
779 | * streaming window. */ | ||
780 | ssize_t disk_buf_prepare_streaming(off_t pos, size_t len) | ||
781 | { | ||
782 | disk_buf_lock(); | ||
783 | |||
784 | if (pos < 0) | ||
785 | pos = 0; | ||
786 | else if (pos > disk_buf.filesize) | ||
787 | pos = disk_buf.filesize; | ||
788 | |||
789 | DEBUGF("prepare streaming:\n pos:%ld len:%lu\n", pos, (unsigned long)len); | ||
790 | |||
791 | pos = disk_buf_lseek(pos, SEEK_SET); | ||
792 | len = disk_buf_probe(pos, len, NULL); | ||
793 | |||
794 | DEBUGF(" probe done: pos:%ld len:%lu\n", pos, (unsigned long)len); | ||
795 | |||
796 | len = disk_buf_send_msg(STREAM_RESET, pos); | ||
797 | |||
798 | disk_buf_unlock(); | ||
799 | |||
800 | return len; | ||
801 | } | ||
802 | |||
803 | /* Set the streaming window to an arbitrary position within the file. Makes no | ||
804 | * probes to validate data. Use after calling another function to cause data | ||
805 | * to be cached and correct values are known. */ | ||
806 | ssize_t disk_buf_set_streaming_window(off_t left, off_t right) | ||
807 | { | ||
808 | ssize_t len; | ||
809 | |||
810 | disk_buf_lock(); | ||
811 | |||
812 | if (left < 0) | ||
813 | left = 0; | ||
814 | else if (left > disk_buf.filesize) | ||
815 | left = disk_buf.filesize; | ||
816 | |||
817 | if (left > right) | ||
818 | right = left; | ||
819 | |||
820 | if (right > disk_buf.filesize) | ||
821 | right = disk_buf.filesize; | ||
822 | |||
823 | disk_buf.win_left = left; | ||
824 | disk_buf.win_right = right; | ||
825 | disk_buf.tail = disk_buf.start + ((right + DISK_BUF_PAGE_SIZE-1) & | ||
826 | ~DISK_BUF_PAGE_MASK) % disk_buf.size; | ||
827 | |||
828 | len = disk_buf.win_right - disk_buf.win_left; | ||
829 | |||
830 | disk_buf_unlock(); | ||
831 | |||
832 | return len; | ||
833 | } | ||
834 | |||
835 | void * disk_buf_offset2ptr(off_t offset) | ||
836 | { | ||
837 | if (offset < 0) | ||
838 | offset = 0; | ||
839 | else if (offset > disk_buf.filesize) | ||
840 | offset = disk_buf.filesize; | ||
841 | |||
842 | return disk_buf.start + (offset % disk_buf.size); | ||
843 | } | ||
844 | |||
845 | void disk_buf_close(void) | ||
846 | { | ||
847 | disk_buf_lock(); | ||
848 | |||
849 | if (disk_buf.in_file >= 0) | ||
850 | { | ||
851 | rb->close(disk_buf.in_file); | ||
852 | disk_buf.in_file = -1; | ||
853 | |||
854 | /* Invalidate entire cache */ | ||
855 | rb->memset(disk_buf.cache, 0xff, | ||
856 | disk_buf.pgcount*sizeof (*disk_buf.cache)); | ||
857 | disk_buf.file_pages = 0; | ||
858 | disk_buf.filesize = 0; | ||
859 | disk_buf.offset = 0; | ||
860 | } | ||
861 | |||
862 | disk_buf_unlock(); | ||
863 | } | ||
864 | |||
865 | int disk_buf_open(const char *filename) | ||
866 | { | ||
867 | int fd; | ||
868 | |||
869 | disk_buf_lock(); | ||
870 | |||
871 | disk_buf_close(); | ||
872 | |||
873 | fd = rb->open(filename, O_RDONLY); | ||
874 | |||
875 | if (fd >= 0) | ||
876 | { | ||
877 | ssize_t filesize = rb->filesize(fd); | ||
878 | |||
879 | if (filesize <= 0) | ||
880 | { | ||
881 | rb->close(disk_buf.in_file); | ||
882 | } | ||
883 | else | ||
884 | { | ||
885 | disk_buf.filesize = filesize; | ||
886 | /* Number of file pages rounded up toward +inf */ | ||
887 | disk_buf.file_pages = ((size_t)filesize + DISK_BUF_PAGE_SIZE-1) | ||
888 | / DISK_BUF_PAGE_SIZE; | ||
889 | disk_buf.in_file = fd; | ||
890 | } | ||
891 | } | ||
892 | |||
893 | disk_buf_unlock(); | ||
894 | |||
895 | return fd; | ||
896 | } | ||
897 | |||
898 | intptr_t disk_buf_send_msg(long id, intptr_t data) | ||
899 | { | ||
900 | return rb->queue_send(disk_buf.q, id, data); | ||
901 | } | ||
902 | |||
903 | void disk_buf_post_msg(long id, intptr_t data) | ||
904 | { | ||
905 | rb->queue_post(disk_buf.q, id, data); | ||
906 | } | ||
907 | |||
908 | void disk_buf_reply_msg(intptr_t retval) | ||
909 | { | ||
910 | rb->queue_reply(disk_buf.q, retval); | ||
911 | } | ||
912 | |||
913 | bool disk_buf_init(void) | ||
914 | { | ||
915 | disk_buf.thread = 0; | ||
916 | |||
917 | rb->mutex_init(&disk_buf_mtx); | ||
918 | |||
919 | disk_buf.q = &disk_buf_queue; | ||
920 | rb->queue_init(disk_buf.q, false); | ||
921 | |||
922 | disk_buf.state = TSTATE_EOS; | ||
923 | disk_buf.status = STREAM_STOPPED; | ||
924 | |||
925 | disk_buf.in_file = -1; | ||
926 | disk_buf.filesize = 0; | ||
927 | disk_buf.win_left = 0; | ||
928 | disk_buf.win_right = 0; | ||
929 | disk_buf.time_last = 0; | ||
930 | disk_buf.pos_last = 0; | ||
931 | disk_buf.low_wm = DISK_BUF_LOW_WATERMARK; | ||
932 | |||
933 | disk_buf.start = mpeg_malloc_all((size_t*)&disk_buf.size, MPEG_ALLOC_DISKBUF); | ||
934 | if (disk_buf.start == NULL) | ||
935 | return false; | ||
936 | |||
937 | #if NUM_CORES > 1 | ||
938 | CACHEALIGN_BUFFER(disk_buf.start, disk_buf.size); | ||
939 | disk_buf.start = UNCACHED_ADDR(disk_buf.start); | ||
940 | #endif | ||
941 | disk_buf.size -= DISK_GUARDBUF_SIZE; | ||
942 | disk_buf.pgcount = disk_buf.size / DISK_BUF_PAGE_SIZE; | ||
943 | |||
944 | /* Fit it as tightly as possible */ | ||
945 | while (disk_buf.pgcount*(sizeof (*disk_buf.cache) + DISK_BUF_PAGE_SIZE) | ||
946 | > (size_t)disk_buf.size) | ||
947 | { | ||
948 | disk_buf.pgcount--; | ||
949 | } | ||
950 | |||
951 | disk_buf.cache = (typeof (disk_buf.cache))disk_buf.start; | ||
952 | disk_buf.start += sizeof (*disk_buf.cache)*disk_buf.pgcount; | ||
953 | disk_buf.size = disk_buf.pgcount*DISK_BUF_PAGE_SIZE; | ||
954 | disk_buf.end = disk_buf.start + disk_buf.size; | ||
955 | disk_buf.tail = disk_buf.start; | ||
956 | |||
957 | DEBUGF("disk_buf info:\n" | ||
958 | " page count: %d\n" | ||
959 | " size: %ld\n", | ||
960 | disk_buf.pgcount, (long)disk_buf.size); | ||
961 | |||
962 | rb->memset(disk_buf.cache, 0xff, | ||
963 | disk_buf.pgcount*sizeof (*disk_buf.cache)); | ||
964 | |||
965 | disk_buf.thread = rb->create_thread( | ||
966 | disk_buf_thread, disk_buf_stack, sizeof(disk_buf_stack), 0, | ||
967 | "mpgbuffer" IF_PRIO(, PRIORITY_BUFFERING) IF_COP(, CPU)); | ||
968 | |||
969 | rb->queue_enable_queue_send(disk_buf.q, &disk_buf_queue_send, | ||
970 | disk_buf.thread); | ||
971 | |||
972 | if (disk_buf.thread == 0) | ||
973 | return false; | ||
974 | |||
975 | /* Wait for thread to initialize */ | ||
976 | disk_buf_send_msg(STREAM_NULL, 0); | ||
977 | |||
978 | return true; | ||
979 | } | ||
980 | |||
981 | void disk_buf_exit(void) | ||
982 | { | ||
983 | if (disk_buf.thread != 0) | ||
984 | { | ||
985 | rb->queue_post(disk_buf.q, STREAM_QUIT, 0); | ||
986 | rb->thread_wait(disk_buf.thread); | ||
987 | disk_buf.thread = 0; | ||
988 | } | ||
989 | } | ||
diff --git a/apps/plugins/mpegplayer/disk_buf.h b/apps/plugins/mpegplayer/disk_buf.h deleted file mode 100644 index bc76ab6dc3..0000000000 --- a/apps/plugins/mpegplayer/disk_buf.h +++ /dev/null | |||
@@ -1,152 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * AV disk buffer declarations | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #ifndef DISK_BUF_H | ||
24 | #define DISK_BUF_H | ||
25 | |||
26 | #ifndef OFF_T_MAX | ||
27 | #define OFF_T_MAX (~((off_t)1 << (sizeof (off_t)*8 - 1))) | ||
28 | #endif | ||
29 | |||
30 | #ifndef OFF_T_MIN | ||
31 | #define OFF_T_MIN ((off_t)1 << (sizeof (off_t)*8 - 1)) | ||
32 | #endif | ||
33 | |||
34 | #define DISK_BUF_PAGE_SHIFT 15 /* 32KB cache lines */ | ||
35 | #define DISK_BUF_PAGE_SIZE (1 << DISK_BUF_PAGE_SHIFT) | ||
36 | #define DISK_BUF_PAGE_MASK (DISK_BUF_PAGE_SIZE-1) | ||
37 | |||
38 | enum | ||
39 | { | ||
40 | DISK_BUF_NOTIFY_ERROR = -1, | ||
41 | DISK_BUF_NOTIFY_NULL = 0, | ||
42 | DISK_BUF_NOTIFY_OK, | ||
43 | DISK_BUF_NOTIFY_TIMEDOUT, | ||
44 | DISK_BUF_NOTIFY_PROCESS_EVENT, | ||
45 | DISK_BUF_NOTIFY_REGISTERED, | ||
46 | }; | ||
47 | |||
48 | /** Macros to map file offsets to cached data **/ | ||
49 | |||
50 | /* Returns a cache tag given a file offset */ | ||
51 | #define MAP_OFFSET_TO_TAG(o) \ | ||
52 | ((o) >> DISK_BUF_PAGE_SHIFT) | ||
53 | |||
54 | /* Returns the cache page number given a file offset */ | ||
55 | #define MAP_OFFSET_TO_PAGE(o) \ | ||
56 | (MAP_OFFSET_TO_TAG(o) % disk_buf.pgcount) | ||
57 | |||
58 | /* Returns the buffer offset given a file offset */ | ||
59 | #define MAP_OFFSET_TO_BUFFER(o) \ | ||
60 | (MAP_OFFSET_TO_PAGE(o) * DISK_BUF_PAGE_SIZE) | ||
61 | |||
62 | struct dbuf_range | ||
63 | { | ||
64 | uint32_t tag_start; | ||
65 | uint32_t tag_end; | ||
66 | int pg_start; | ||
67 | }; | ||
68 | |||
69 | #define DISK_BUF_L2_CACHE_SHIFT 6 | ||
70 | #define DISK_BUF_L2_CACHE_SIZE (1 << DISK_BUF_L2_CACHE_SHIFT) | ||
71 | #define DISK_BUF_L2_CACHE_MASK (DISK_BUF_L2_CACHE_SIZE-1) | ||
72 | |||
73 | struct dbuf_l2_cache | ||
74 | { | ||
75 | off_t addr; /* L2 file offset */ | ||
76 | size_t size; /* Real size */ | ||
77 | uint8_t data[DISK_BUF_L2_CACHE_SIZE*2]; /* Local data and guard */ | ||
78 | }; | ||
79 | |||
80 | void dbuf_l2_init(struct dbuf_l2_cache *l2_p); | ||
81 | |||
82 | /* This object is an extension of the stream manager and handles some | ||
83 | * playback events as well as buffering */ | ||
84 | struct disk_buf | ||
85 | { | ||
86 | unsigned int thread; | ||
87 | struct event_queue *q; | ||
88 | uint8_t *start; /* Start pointer */ | ||
89 | uint8_t *end; /* End of buffer pointer less MPEG_GUARDBUF_SIZE. The | ||
90 | guard space is used to wrap data at the buffer start to | ||
91 | pass continuous data packets */ | ||
92 | uint8_t *tail; /* Location of last data + 1 filled into the buffer */ | ||
93 | ssize_t size; /* The buffer length _not_ including the guard space (end-start) */ | ||
94 | int pgcount; /* Total number of available cached pages */ | ||
95 | uint32_t *cache; /* Pointer to cache structure - allocated on buffer */ | ||
96 | int in_file; /* File being read */ | ||
97 | ssize_t filesize; /* Size of file in_file in bytes */ | ||
98 | int file_pages; /* Number of pages in file (rounded up) */ | ||
99 | off_t offset; /* Current position (random access) */ | ||
100 | off_t win_left; /* Left edge of buffer window (streaming) */ | ||
101 | off_t win_right; /* Right edge of buffer window (streaming) */ | ||
102 | uint32_t time_last; /* Last time watermark was checked */ | ||
103 | off_t pos_last; /* Last position at watermark check time */ | ||
104 | ssize_t low_wm; /* The low watermark for automatic rebuffering */ | ||
105 | int status; /* Status as stream */ | ||
106 | int state; /* Current thread state */ | ||
107 | bool need_seek; /* Need to seek because a read was not contiguous */ | ||
108 | }; | ||
109 | |||
110 | extern struct disk_buf disk_buf SHAREDBSS_ATTR; | ||
111 | |||
112 | struct stream_hdr; | ||
113 | bool disk_buf_is_data_ready(struct stream_hdr *sh, ssize_t margin); | ||
114 | |||
115 | bool disk_buf_init(void); | ||
116 | void disk_buf_exit(void); | ||
117 | |||
118 | static inline int disk_buf_status(void) | ||
119 | { return disk_buf.status; } | ||
120 | |||
121 | int disk_buf_open(const char *filename); | ||
122 | void disk_buf_close(void); | ||
123 | ssize_t _disk_buf_getbuffer(size_t size, void **pp, void **pwrap, | ||
124 | size_t *sizewrap); | ||
125 | #define disk_buf_getbuffer(size, pp, pwrap, sizewrap) \ | ||
126 | _disk_buf_getbuffer((size), PUN_PTR(void **, (pp)), \ | ||
127 | PUN_PTR(void **, (pwrap)), (sizewrap)) | ||
128 | |||
129 | ssize_t _disk_buf_getbuffer_l2(struct dbuf_l2_cache *l2, | ||
130 | size_t size, void **pp); | ||
131 | #define disk_buf_getbuffer_l2(l2, size, pp) \ | ||
132 | _disk_buf_getbuffer_l2((l2), (size), PUN_PTR(void **, (pp))) | ||
133 | |||
134 | ssize_t disk_buf_read(void *buffer, size_t size); | ||
135 | ssize_t disk_buf_lseek(off_t offset, int whence); | ||
136 | |||
137 | static inline off_t disk_buf_ftell(void) | ||
138 | { return disk_buf.offset; } | ||
139 | |||
140 | static inline ssize_t disk_buf_filesize(void) | ||
141 | { return disk_buf.filesize; } | ||
142 | |||
143 | ssize_t disk_buf_prepare_streaming(off_t pos, size_t len); | ||
144 | ssize_t disk_buf_set_streaming_window(off_t left, off_t right); | ||
145 | void * disk_buf_offset2ptr(off_t offset); | ||
146 | int disk_buf_check_streaming_window(off_t left, off_t right); | ||
147 | |||
148 | intptr_t disk_buf_send_msg(long id, intptr_t data); | ||
149 | void disk_buf_post_msg(long id, intptr_t data); | ||
150 | void disk_buf_reply_msg(intptr_t retval); | ||
151 | |||
152 | #endif /* DISK_BUF_H */ | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/AUTHORS b/apps/plugins/mpegplayer/libmpeg2/AUTHORS deleted file mode 100644 index 4722897c97..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/AUTHORS +++ /dev/null | |||
@@ -1,33 +0,0 @@ | |||
1 | Aaron Holtzman <aholtzma@ess.engr.uvic.ca> started the project and | ||
2 | made the initial working implementation. | ||
3 | |||
4 | Michel Lespinasse <walken@zoy.org> did major changes for speed and | ||
5 | mpeg conformance and is the current maintainer. Most of the current | ||
6 | code was (re)written by him. | ||
7 | |||
8 | Other contributors include: | ||
9 | Bruno Barreyra <barreyra@ufl.edu> - build fixes | ||
10 | Gildas Bazin <gbazin@netcourrier.com> - mingw32 port | ||
11 | Alexander W. Chin <alexc@newt.phys.unsw.edu.au> - progressive_seq fix | ||
12 | Stephen Crowley <stephenc@dns2.digitalpassage.com> - build fixes | ||
13 | Didier Gautheron <dgautheron@magic.fr> - bug fixes | ||
14 | Ryan C. Gordon <icculus@lokigames.com> - SDL support | ||
15 | Peter Gubanov <peter@elecard.net.ru> - MMX IDCT scheduling | ||
16 | HÃ¥kan Hjort <d95hjort@dtek.chalmers.se> - Solaris fixes, mlib code | ||
17 | Nicolas Joly <njoly@pasteur.fr> - assorted bug fixes | ||
18 | Gerd Knorr <kraxel@goldbach.in-berlin.de> - Xv support | ||
19 | David I. Lehn <dlehn@vt.edu> - motion_comp mmx code | ||
20 | Olie Lho <ollie@sis.com.tw> - MMX yuv2rgb routine | ||
21 | David S. Miller <davem@redhat.com> - sparc VIS optimizations | ||
22 | Rick Niles <niles@scyld.com> - build fixes | ||
23 | Real Ouellet <realo@sympatico.ca> - g200 fixes | ||
24 | Bajusz Peter <hyp-x@inf.bme.hu> - motion comp fixes | ||
25 | Franck Sicard <Franck.Sicard@miniruth.solsoft.fr> - x11 fixes | ||
26 | Brion Vibber <brion@gizmo.usc.edu> - x11 fixes | ||
27 | Martin Vogt <mvogt@rhrk.uni-kl.de> - reentrancy fixes | ||
28 | Fredrik Vraalsen <vraalsen@cs.uiuc.edu> - general hackage and stuff | ||
29 | |||
30 | (let me know if I forgot anyone) | ||
31 | |||
32 | Thanks to David Schleef for creating me an account on his ppc g4 | ||
33 | machine and making it possible for me to work on the altivec code. | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/README b/apps/plugins/mpegplayer/libmpeg2/README deleted file mode 100644 index 2a58846772..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/README +++ /dev/null | |||
@@ -1,204 +0,0 @@ | |||
1 | |||
2 | |||
3 | ABOUT LIBMPEG2 | ||
4 | |||
5 | libmpeg2 is a free library for decoding mpeg-2 and mpeg-1 video | ||
6 | streams. It is released under the terms of the GPL license. | ||
7 | |||
8 | The main goals in libmpeg2 development are: | ||
9 | |||
10 | * Conformance - libmpeg2 is able to decode all mpeg streams that | ||
11 | conform to certain restrictions: "constrained parameters" for | ||
12 | mpeg-1, and "main profile" for mpeg-2. In practice, this is | ||
13 | what most people are using. For streams that follow these | ||
14 | restrictions, we believe libmpeg2 is 100% conformant to the | ||
15 | mpeg standards - and we have a pretty extensive test suite to | ||
16 | check this. | ||
17 | |||
18 | * Speed - there has been huge efforts there, and we believe | ||
19 | libmpeg2 is the fastest library around for what it | ||
20 | does. Please tell us if you find a faster one ! With typical | ||
21 | video streams as found on DVD's, and doing only decoding with | ||
22 | no display, you should be able to get about 110 fps on a | ||
23 | PIII/666, or 150 fps on an Athlon/950. This is less than 20 | ||
24 | cycles per output pixel. In a real player program, the display | ||
25 | routines will probably take as much time as the actual | ||
26 | decoding ! | ||
27 | |||
28 | * Portability - most of the code is written in C, and when we | ||
29 | use platform-specific optimizations (typically assembly | ||
30 | routines, currently used for the motion compensation and the | ||
31 | inverse cosine transform stages) we always have a generic C | ||
32 | routine to fall back on. This should be portable to all | ||
33 | architectures - at least we have heard reports from people | ||
34 | running this code on x86, ppc, sparc, arm and | ||
35 | sh4. Assembly-optimized implementations are available on x86 | ||
36 | (MMX) and ppc (altivec) architectures. Ultrasparc (VIS) is | ||
37 | probably the next on the list - we'll see. | ||
38 | |||
39 | * Reuseability - we do not want libmpeg2 to include any | ||
40 | project-specific code, but it should still include enough | ||
41 | features to be used by very diverse projects. We are only | ||
42 | starting to get there - the best way to help here is to give | ||
43 | us some feedback ! | ||
44 | |||
45 | The project homepage is at http://libmpeg2.sourceforge.net/ | ||
46 | |||
47 | |||
48 | MPEG2DEC | ||
49 | |||
50 | mpeg2dec is a test program for libmpeg2. It decodes mpeg-1 and mpeg-2 | ||
51 | video streams, and also includes a demultiplexer for mpeg-1 and mpeg-2 | ||
52 | program streams. It is purposely kept simple : it does not include | ||
53 | features like reading files from a DVD, CSS, fullscreen output, | ||
54 | navigation, etc... The main purpose of mpeg2dec is to have a simple | ||
55 | test bed for libmpeg2. | ||
56 | |||
57 | The libmpeg2 source code is always distributed in the mpeg2dec | ||
58 | package, to make it easier for people to test it. | ||
59 | |||
60 | The basic usage is to just type "mpeg2dec file" where file is a | ||
61 | demultiplexed mpeg video file. | ||
62 | |||
63 | The "-s" option must be used for multiplexed (audio and video) mpeg | ||
64 | files using the "program stream" format. These files are usualy found | ||
65 | on the internet or on unencrypted DVDs. | ||
66 | |||
67 | The "-t" option must be used for multiplexed (audio and video) mpeg | ||
68 | files using the "transport stream" format. These files are usualy | ||
69 | found in digital TV applications. | ||
70 | |||
71 | The "-o" option is used to select a given output module - for example | ||
72 | to redirect the output to a file. This is also used for performance | ||
73 | testing and conformance testing. | ||
74 | |||
75 | The "-c" option is used to disable all optimizations. | ||
76 | |||
77 | |||
78 | OTHER PROJECTS USING LIBMPEG2 | ||
79 | |||
80 | libmpeg2 is being used by various other projects, including: | ||
81 | |||
82 | * xine (http://xine.sourceforge.net/) - started as a simple | ||
83 | mpeg-2 audio and video decoder, but it since became a | ||
84 | full-featured DVD and video media player. | ||
85 | |||
86 | * VideoLAN (http://www.videolan.org/) - video streaming over an | ||
87 | ethernet network, can also be used as a standalone player. | ||
88 | |||
89 | * MPlayer (http://www.MPlayerHQ.hu) - another good player, it is | ||
90 | also very robust against damaged streams. | ||
91 | |||
92 | * movietime (http://movietime.sourceforge.net/) - still quite | ||
93 | young, but it looks very promising ! | ||
94 | |||
95 | * mpeg2decX (http://homepage1.nifty.com/~toku/software_en.html) - | ||
96 | a graphical interface for mpeg2dec for macintosh osX. | ||
97 | |||
98 | * TCVP (http://tcvp.sf.net) - video and music player for unix. | ||
99 | |||
100 | * drip (http://drip.sourceforge.net/) - a DVD to DIVX transcoder. | ||
101 | |||
102 | * PoMP | ||
103 | (http://www.dmclab.hanyang.ac.kr/research/project/PoDS/PoDS_sw.htm) - | ||
104 | a research player optimized to minimize disk power consumption. | ||
105 | |||
106 | * OMS (http://www.linuxvideo.org/oms/) | ||
107 | |||
108 | * XMPS (http://xmps.sourceforge.net/) | ||
109 | |||
110 | * GStreamer (http://www.gstreamer.net/) - a framework for | ||
111 | streaming media; it has an mpeg2 decoding plugin based on | ||
112 | libmpeg2. | ||
113 | |||
114 | * mpeglib (http://mpeglib.sourceforge.net/) - a video decoding | ||
115 | library that usess libmpeg2 when decoding mpeg streams. | ||
116 | |||
117 | * daphne (http://daphne.rulecity.com/) - a laserdisc arcade game | ||
118 | simulator. | ||
119 | |||
120 | * GOPchop (http://outflux.net/unix/software/GOPchop/) - a | ||
121 | GOP-accurate editor for MPEG2 streams. | ||
122 | |||
123 | If you use libmpeg2 in another project, let us know ! | ||
124 | |||
125 | |||
126 | TASKS | ||
127 | |||
128 | There are several places where we could easily use some help: | ||
129 | |||
130 | * Documentation: libmpeg2 still has no documentation. Every | ||
131 | project using it has had to figure things out by looking at | ||
132 | the header files, at the mpeg2dec sample application, and by | ||
133 | asking questions. Writing down a nice documentation would make | ||
134 | the code more easily reuseable. | ||
135 | |||
136 | * Testing: If you find any stream that does not decode right | ||
137 | with libmpeg2, let us know ! The best thing would be to mail | ||
138 | to the libmpeg2-devel mailing list. Also, it would be nice to | ||
139 | build a stress test so we can make sure libmpeg2 never crashes | ||
140 | on bad streams. | ||
141 | |||
142 | * Coding: There is a small TODO list in the mpeg2dec package, | ||
143 | you can have a look there ! Most items are pretty terse | ||
144 | though. | ||
145 | |||
146 | * Porting: If you're porting to a new architecture, you might | ||
147 | want to experiment with the compile flags defined in | ||
148 | configure.in . When you figure out whats fastest on your | ||
149 | platform, send us a patch ! | ||
150 | |||
151 | * Assembly optimizations: We only have x86 and altivec | ||
152 | optimizations yet, it would be worthwhile writing routines for | ||
153 | other architectures, especially those that have SIMD | ||
154 | instruction set extensions ! Also the yuv2rgb x86 routines | ||
155 | could probably be optimized a lot. | ||
156 | |||
157 | |||
158 | CVS SNAPSHOTS | ||
159 | |||
160 | A daily snapshot is created using "make distcheck" every night and | ||
161 | uploaded to http://libmpeg2.sourceforge.net/files/mpeg2dec-snapshot.tar.gz . | ||
162 | It is easier to use than the CVS repository, because you do not need | ||
163 | to have the right versions of automake, autoconf and libtool | ||
164 | installed. It might be convenient when working on a libmpeg2 port for | ||
165 | example. | ||
166 | |||
167 | |||
168 | CVS REPOSITORY | ||
169 | |||
170 | The latest libmpeg2 and mpeg2dec source code can always be found by | ||
171 | anonymous CVS: | ||
172 | |||
173 | # export CVSROOT=:pserver:anonymous@cvs.libmpeg2.sourceforge.net:/cvsroot/libmpeg2 | ||
174 | # cvs login (Just press Return when prompted for a password) | ||
175 | # cvs checkout mpeg2dec | ||
176 | |||
177 | You can also browse the latest changes online at | ||
178 | http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/libmpeg2/mpeg2dec/ | ||
179 | |||
180 | The other CVS modules are mpeg2dec-streams for the test suite, and | ||
181 | mpeg2dec-livid for the CVS history of the project while it was still | ||
182 | hosted on the linuxvideo.org servers. | ||
183 | |||
184 | |||
185 | MAILING LISTS | ||
186 | |||
187 | See the subscription information at http://libmpeg2.sourceforge.net/lists.html | ||
188 | |||
189 | libmpeg2-devel | ||
190 | |||
191 | This is the main mailing list for technical discussion about | ||
192 | libmpeg2. Anyone wanting to work on libmpeg2, or maybe just stay | ||
193 | informed about the development process, should probably subscribe to | ||
194 | this list. | ||
195 | |||
196 | libmpeg2-checkins | ||
197 | |||
198 | All libmpeg2 checkins are announced there. This is a good way to keep | ||
199 | track of what goes into CVS. | ||
200 | |||
201 | libmpeg2-announce | ||
202 | |||
203 | This is a very low traffic mailing list, only for announcements of new | ||
204 | versions of libmpeg2. Only project administrators can post there. | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/README.rockbox b/apps/plugins/mpegplayer/libmpeg2/README.rockbox deleted file mode 100644 index 95f5a3d4b5..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/README.rockbox +++ /dev/null | |||
@@ -1,44 +0,0 @@ | |||
1 | Library: libmpeg2 from mpeg2dec-0.4.0b (Released 2004-01-21) | ||
2 | Imported: 2006-08-06 by Dave Chapman | ||
3 | |||
4 | |||
5 | This directory contains a local version of libmpeg2 imported into | ||
6 | Rockbox for MPEG video decoding. | ||
7 | |||
8 | |||
9 | LICENSING INFORMATION | ||
10 | |||
11 | mpeg2dec and libmpeg2 are licensed under Version 2 of the GNU General | ||
12 | Public License. | ||
13 | |||
14 | |||
15 | IMPORT DETAILS | ||
16 | |||
17 | The following files were imported from the mpeg2dec-0.4.0b | ||
18 | distribution. Minor changes were made to enable compilation in | ||
19 | Rockbox and TABs were replaced by spaces to comply with the Rockbox | ||
20 | coding guidelines. | ||
21 | |||
22 | AUTHORS | ||
23 | README | ||
24 | SOURCES | ||
25 | attributes.h | ||
26 | cpu_accel.c | ||
27 | cpu_state.c | ||
28 | decode.c | ||
29 | header.c | ||
30 | idct.c | ||
31 | motion_comp.c | ||
32 | mpeg2.h | ||
33 | mpeg2_internal.h | ||
34 | slice.c | ||
35 | video_out.h | ||
36 | vlc.h | ||
37 | |||
38 | The following files are new, but based on code in mpeg2dec. | ||
39 | |||
40 | Makefile | ||
41 | mpegplayer.c | ||
42 | video_out_rockbox.c | ||
43 | mpeg2dec_config.h | ||
44 | alloc.c | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/attributes.h b/apps/plugins/mpegplayer/libmpeg2/attributes.h deleted file mode 100644 index 24b069223b..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/attributes.h +++ /dev/null | |||
@@ -1,42 +0,0 @@ | |||
1 | /* | ||
2 | * attributes.h | ||
3 | * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> | ||
4 | * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> | ||
5 | * | ||
6 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
7 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
8 | * | ||
9 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * mpeg2dec is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | * $Id$ | ||
24 | * libmpeg2 sync history: | ||
25 | * 2008-07-01 - CVS revision 1.5 | ||
26 | */ | ||
27 | |||
28 | /* use gcc attribs to align critical data structures */ | ||
29 | #ifdef ATTRIBUTE_ALIGNED_MAX | ||
30 | #define ATTR_ALIGN(align) __attribute__ ((__aligned__ ((ATTRIBUTE_ALIGNED_MAX < align) ? ATTRIBUTE_ALIGNED_MAX : align))) | ||
31 | #else | ||
32 | #define ATTR_ALIGN(align) | ||
33 | #endif | ||
34 | |||
35 | #if defined(LIKELY) && defined (UNLIKELY) | ||
36 | #define likely(x) LIKELY(x) | ||
37 | #define unlikely(x) UNLIKELY(x) | ||
38 | #else | ||
39 | #define likely(x) (x) | ||
40 | #define unlikely(x) (x) | ||
41 | #endif | ||
42 | |||
diff --git a/apps/plugins/mpegplayer/libmpeg2/decode.c b/apps/plugins/mpegplayer/libmpeg2/decode.c deleted file mode 100644 index 9c8081efbe..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/decode.c +++ /dev/null | |||
@@ -1,527 +0,0 @@ | |||
1 | /* | ||
2 | * decode.c | ||
3 | * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> | ||
4 | * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> | ||
5 | * | ||
6 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
7 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
8 | * | ||
9 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * mpeg2dec is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | * $Id$ | ||
24 | * libmpeg2 sync history: | ||
25 | * 2008-07-01 - CVS revision 1.114 | ||
26 | */ | ||
27 | |||
28 | #include "plugin.h" | ||
29 | |||
30 | #include "mpeg2dec_config.h" | ||
31 | |||
32 | #include "mpeg2.h" | ||
33 | #include "attributes.h" | ||
34 | #include "mpeg2_internal.h" | ||
35 | |||
36 | #define BUFFER_SIZE (1194 * 1024) | ||
37 | |||
38 | #if defined(CPU_COLDFIRE) || (defined(CPU_ARM) && ARM_ARCH >= 6) | ||
39 | /* twice as large as on other targets because coldfire uses | ||
40 | * a secondary, transposed buffer for optimisation */ | ||
41 | static int16_t static_dct_block[128] IBSS_ATTR ATTR_ALIGN(16); | ||
42 | #define DCT_BLOCKSIZE (128 * sizeof (int16_t)) | ||
43 | #else | ||
44 | static int16_t static_dct_block[64] IBSS_ATTR ATTR_ALIGN(16); | ||
45 | #define DCT_BLOCKSIZE (64 * sizeof (int16_t)) | ||
46 | #endif | ||
47 | |||
48 | const mpeg2_info_t * mpeg2_info (mpeg2dec_t * mpeg2dec) | ||
49 | { | ||
50 | return &mpeg2dec->info; | ||
51 | } | ||
52 | |||
53 | static inline int skip_chunk (mpeg2dec_t * mpeg2dec, int bytes) | ||
54 | { | ||
55 | uint8_t * current; | ||
56 | uint32_t shift; | ||
57 | uint8_t * limit; | ||
58 | uint8_t byte; | ||
59 | |||
60 | if (!bytes) | ||
61 | return 0; | ||
62 | |||
63 | current = mpeg2dec->buf_start; | ||
64 | shift = mpeg2dec->shift; | ||
65 | limit = current + bytes; | ||
66 | |||
67 | do | ||
68 | { | ||
69 | byte = *current++; | ||
70 | |||
71 | if (shift == 0x00000100) | ||
72 | { | ||
73 | int skipped; | ||
74 | |||
75 | mpeg2dec->shift = 0xffffff00; | ||
76 | skipped = current - mpeg2dec->buf_start; | ||
77 | mpeg2dec->buf_start = current; | ||
78 | |||
79 | return skipped; | ||
80 | } | ||
81 | |||
82 | shift = (shift | byte) << 8; | ||
83 | } | ||
84 | while (current < limit); | ||
85 | |||
86 | mpeg2dec->shift = shift; | ||
87 | mpeg2dec->buf_start = current; | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static inline int copy_chunk (mpeg2dec_t * mpeg2dec, int bytes) | ||
93 | { | ||
94 | uint8_t * current; | ||
95 | uint32_t shift; | ||
96 | uint8_t * chunk_ptr; | ||
97 | uint8_t * limit; | ||
98 | uint8_t byte; | ||
99 | |||
100 | if (!bytes) | ||
101 | return 0; | ||
102 | |||
103 | current = mpeg2dec->buf_start; | ||
104 | shift = mpeg2dec->shift; | ||
105 | chunk_ptr = mpeg2dec->chunk_ptr; | ||
106 | limit = current + bytes; | ||
107 | |||
108 | do | ||
109 | { | ||
110 | byte = *current++; | ||
111 | |||
112 | if (shift == 0x00000100) | ||
113 | { | ||
114 | int copied; | ||
115 | |||
116 | mpeg2dec->shift = 0xffffff00; | ||
117 | mpeg2dec->chunk_ptr = chunk_ptr + 1; | ||
118 | copied = current - mpeg2dec->buf_start; | ||
119 | mpeg2dec->buf_start = current; | ||
120 | return copied; | ||
121 | } | ||
122 | |||
123 | shift = (shift | byte) << 8; | ||
124 | *chunk_ptr++ = byte; | ||
125 | } | ||
126 | while (current < limit); | ||
127 | |||
128 | mpeg2dec->shift = shift; | ||
129 | mpeg2dec->buf_start = current; | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | void mpeg2_buffer (mpeg2dec_t * mpeg2dec, uint8_t * start, uint8_t * end) | ||
134 | { | ||
135 | mpeg2dec->buf_start = start; | ||
136 | mpeg2dec->buf_end = end; | ||
137 | } | ||
138 | |||
139 | int mpeg2_getpos (mpeg2dec_t * mpeg2dec) | ||
140 | { | ||
141 | return mpeg2dec->buf_end - mpeg2dec->buf_start; | ||
142 | } | ||
143 | |||
144 | static inline mpeg2_state_t seek_chunk (mpeg2dec_t * mpeg2dec) | ||
145 | { | ||
146 | int size, skipped; | ||
147 | |||
148 | size = mpeg2dec->buf_end - mpeg2dec->buf_start; | ||
149 | skipped = skip_chunk (mpeg2dec, size); | ||
150 | |||
151 | if (!skipped) | ||
152 | { | ||
153 | mpeg2dec->bytes_since_tag += size; | ||
154 | return STATE_BUFFER; | ||
155 | } | ||
156 | |||
157 | mpeg2dec->bytes_since_tag += skipped; | ||
158 | mpeg2dec->code = mpeg2dec->buf_start[-1]; | ||
159 | |||
160 | return STATE_INTERNAL_NORETURN; | ||
161 | } | ||
162 | |||
163 | mpeg2_state_t mpeg2_seek_header (mpeg2dec_t * mpeg2dec) | ||
164 | { | ||
165 | while (!(mpeg2dec->code == 0xb3 || | ||
166 | ((mpeg2dec->code == 0xb7 || mpeg2dec->code == 0xb8 || | ||
167 | !mpeg2dec->code) && mpeg2dec->sequence.width != (unsigned)-1))) | ||
168 | { | ||
169 | if (seek_chunk (mpeg2dec) == STATE_BUFFER) | ||
170 | return STATE_BUFFER; | ||
171 | } | ||
172 | |||
173 | mpeg2dec->chunk_start = | ||
174 | mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer; | ||
175 | |||
176 | mpeg2dec->user_data_len = 0; | ||
177 | |||
178 | return ((mpeg2dec->code == 0xb7) ? | ||
179 | mpeg2_header_end(mpeg2dec) : mpeg2_parse_header(mpeg2dec)); | ||
180 | } | ||
181 | |||
182 | #define RECEIVED(code,state) (((state) << 8) + (code)) | ||
183 | |||
184 | mpeg2_state_t mpeg2_parse (mpeg2dec_t * mpeg2dec) | ||
185 | { | ||
186 | int size_buffer, size_chunk, copied; | ||
187 | |||
188 | if (mpeg2dec->action) | ||
189 | { | ||
190 | mpeg2_state_t state; | ||
191 | |||
192 | state = mpeg2dec->action (mpeg2dec); | ||
193 | |||
194 | if (state > STATE_INTERNAL_NORETURN) | ||
195 | return state; | ||
196 | } | ||
197 | |||
198 | while (1) | ||
199 | { | ||
200 | while ((unsigned) (mpeg2dec->code - mpeg2dec->first_decode_slice) < | ||
201 | mpeg2dec->nb_decode_slices) | ||
202 | { | ||
203 | size_buffer = mpeg2dec->buf_end - mpeg2dec->buf_start; | ||
204 | size_chunk = mpeg2dec->chunk_buffer + BUFFER_SIZE - | ||
205 | mpeg2dec->chunk_ptr; | ||
206 | |||
207 | if (size_buffer <= size_chunk) | ||
208 | { | ||
209 | copied = copy_chunk (mpeg2dec, size_buffer); | ||
210 | |||
211 | if (!copied) | ||
212 | { | ||
213 | mpeg2dec->bytes_since_tag += size_buffer; | ||
214 | mpeg2dec->chunk_ptr += size_buffer; | ||
215 | return STATE_BUFFER; | ||
216 | } | ||
217 | } | ||
218 | else | ||
219 | { | ||
220 | copied = copy_chunk (mpeg2dec, size_chunk); | ||
221 | |||
222 | if (!copied) | ||
223 | { | ||
224 | /* filled the chunk buffer without finding a start code */ | ||
225 | mpeg2dec->bytes_since_tag += size_chunk; | ||
226 | mpeg2dec->action = seek_chunk; | ||
227 | return STATE_INVALID; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | mpeg2dec->bytes_since_tag += copied; | ||
232 | |||
233 | mpeg2_slice (&mpeg2dec->decoder, mpeg2dec->code, | ||
234 | mpeg2dec->chunk_start); | ||
235 | mpeg2dec->code = mpeg2dec->buf_start[-1]; | ||
236 | mpeg2dec->chunk_ptr = mpeg2dec->chunk_start; | ||
237 | } | ||
238 | |||
239 | if ((unsigned) (mpeg2dec->code - 1) >= 0xb0 - 1) | ||
240 | break; | ||
241 | |||
242 | if (seek_chunk (mpeg2dec) == STATE_BUFFER) | ||
243 | return STATE_BUFFER; | ||
244 | } | ||
245 | |||
246 | mpeg2dec->action = mpeg2_seek_header; | ||
247 | |||
248 | switch (mpeg2dec->code) | ||
249 | { | ||
250 | case 0x00: | ||
251 | return mpeg2dec->state; | ||
252 | case 0xb3: | ||
253 | case 0xb7: | ||
254 | case 0xb8: | ||
255 | return (mpeg2dec->state == STATE_SLICE) ? STATE_SLICE : STATE_INVALID; | ||
256 | default: | ||
257 | mpeg2dec->action = seek_chunk; | ||
258 | return STATE_INVALID; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | mpeg2_state_t mpeg2_parse_header (mpeg2dec_t * mpeg2dec) | ||
263 | { | ||
264 | static int (* const process_header[9]) (mpeg2dec_t *) = | ||
265 | { | ||
266 | mpeg2_header_picture, | ||
267 | mpeg2_header_extension, | ||
268 | mpeg2_header_user_data, | ||
269 | mpeg2_header_sequence, | ||
270 | NULL, | ||
271 | NULL, | ||
272 | NULL, | ||
273 | NULL, | ||
274 | mpeg2_header_gop | ||
275 | }; | ||
276 | |||
277 | int size_buffer, size_chunk, copied; | ||
278 | |||
279 | mpeg2dec->action = mpeg2_parse_header; | ||
280 | mpeg2dec->info.user_data = NULL; | ||
281 | mpeg2dec->info.user_data_len = 0; | ||
282 | |||
283 | while (1) | ||
284 | { | ||
285 | size_buffer = mpeg2dec->buf_end - mpeg2dec->buf_start; | ||
286 | size_chunk = mpeg2dec->chunk_buffer + BUFFER_SIZE - | ||
287 | mpeg2dec->chunk_ptr; | ||
288 | |||
289 | if (size_buffer <= size_chunk) | ||
290 | { | ||
291 | copied = copy_chunk (mpeg2dec, size_buffer); | ||
292 | |||
293 | if (!copied) | ||
294 | { | ||
295 | mpeg2dec->bytes_since_tag += size_buffer; | ||
296 | mpeg2dec->chunk_ptr += size_buffer; | ||
297 | return STATE_BUFFER; | ||
298 | } | ||
299 | } | ||
300 | else | ||
301 | { | ||
302 | copied = copy_chunk (mpeg2dec, size_chunk); | ||
303 | |||
304 | if (!copied) | ||
305 | { | ||
306 | /* filled the chunk buffer without finding a start code */ | ||
307 | mpeg2dec->bytes_since_tag += size_chunk; | ||
308 | mpeg2dec->code = 0xb4; | ||
309 | mpeg2dec->action = mpeg2_seek_header; | ||
310 | return STATE_INVALID; | ||
311 | } | ||
312 | } | ||
313 | |||
314 | mpeg2dec->bytes_since_tag += copied; | ||
315 | |||
316 | if (process_header[mpeg2dec->code & 0x0b] (mpeg2dec)) | ||
317 | { | ||
318 | mpeg2dec->code = mpeg2dec->buf_start[-1]; | ||
319 | mpeg2dec->action = mpeg2_seek_header; | ||
320 | return STATE_INVALID; | ||
321 | } | ||
322 | |||
323 | mpeg2dec->code = mpeg2dec->buf_start[-1]; | ||
324 | |||
325 | switch (RECEIVED (mpeg2dec->code, mpeg2dec->state)) | ||
326 | { | ||
327 | /* state transition after a sequence header */ | ||
328 | case RECEIVED (0x00, STATE_SEQUENCE): | ||
329 | case RECEIVED (0xb8, STATE_SEQUENCE): | ||
330 | mpeg2_header_sequence_finalize (mpeg2dec); | ||
331 | break; | ||
332 | |||
333 | /* other legal state transitions */ | ||
334 | case RECEIVED (0x00, STATE_GOP): | ||
335 | mpeg2_header_gop_finalize (mpeg2dec); | ||
336 | break; | ||
337 | case RECEIVED (0x01, STATE_PICTURE): | ||
338 | case RECEIVED (0x01, STATE_PICTURE_2ND): | ||
339 | mpeg2_header_picture_finalize (mpeg2dec); | ||
340 | mpeg2dec->action = mpeg2_header_slice_start; | ||
341 | break; | ||
342 | |||
343 | /* legal headers within a given state */ | ||
344 | case RECEIVED (0xb2, STATE_SEQUENCE): | ||
345 | case RECEIVED (0xb2, STATE_GOP): | ||
346 | case RECEIVED (0xb2, STATE_PICTURE): | ||
347 | case RECEIVED (0xb2, STATE_PICTURE_2ND): | ||
348 | case RECEIVED (0xb5, STATE_SEQUENCE): | ||
349 | case RECEIVED (0xb5, STATE_PICTURE): | ||
350 | case RECEIVED (0xb5, STATE_PICTURE_2ND): | ||
351 | mpeg2dec->chunk_ptr = mpeg2dec->chunk_start; | ||
352 | continue; | ||
353 | |||
354 | default: | ||
355 | mpeg2dec->action = mpeg2_seek_header; | ||
356 | return STATE_INVALID; | ||
357 | } | ||
358 | |||
359 | mpeg2dec->chunk_start = mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer; | ||
360 | mpeg2dec->user_data_len = 0; | ||
361 | |||
362 | return mpeg2dec->state; | ||
363 | } | ||
364 | } | ||
365 | |||
366 | int mpeg2_convert (mpeg2dec_t * mpeg2dec, mpeg2_convert_t convert, void * arg) | ||
367 | { | ||
368 | mpeg2_convert_init_t convert_init; | ||
369 | int error; | ||
370 | |||
371 | error = convert (MPEG2_CONVERT_SET, NULL, &mpeg2dec->sequence, 0, | ||
372 | arg, &convert_init); | ||
373 | |||
374 | if (!error) | ||
375 | { | ||
376 | mpeg2dec->convert = convert; | ||
377 | mpeg2dec->convert_arg = arg; | ||
378 | mpeg2dec->convert_id_size = convert_init.id_size; | ||
379 | mpeg2dec->convert_stride = 0; | ||
380 | } | ||
381 | |||
382 | return error; | ||
383 | } | ||
384 | |||
385 | int mpeg2_stride (mpeg2dec_t * mpeg2dec, int stride) | ||
386 | { | ||
387 | if (!mpeg2dec->convert) | ||
388 | { | ||
389 | if (stride < (int) mpeg2dec->sequence.width) | ||
390 | stride = mpeg2dec->sequence.width; | ||
391 | |||
392 | mpeg2dec->decoder.stride_frame = stride; | ||
393 | } | ||
394 | else | ||
395 | { | ||
396 | mpeg2_convert_init_t convert_init; | ||
397 | |||
398 | stride = mpeg2dec->convert(MPEG2_CONVERT_STRIDE, NULL, | ||
399 | &mpeg2dec->sequence, stride, | ||
400 | mpeg2dec->convert_arg, | ||
401 | &convert_init); | ||
402 | |||
403 | mpeg2dec->convert_id_size = convert_init.id_size; | ||
404 | mpeg2dec->convert_stride = stride; | ||
405 | } | ||
406 | |||
407 | return stride; | ||
408 | } | ||
409 | |||
410 | void mpeg2_set_buf (mpeg2dec_t * mpeg2dec, uint8_t * buf[MPEG2_COMPONENTS], void * id) | ||
411 | { | ||
412 | mpeg2_fbuf_t * fbuf; | ||
413 | |||
414 | if (mpeg2dec->custom_fbuf) | ||
415 | { | ||
416 | if (mpeg2dec->state == STATE_SEQUENCE) | ||
417 | { | ||
418 | mpeg2dec->fbuf[2] = mpeg2dec->fbuf[1]; | ||
419 | mpeg2dec->fbuf[1] = mpeg2dec->fbuf[0]; | ||
420 | } | ||
421 | |||
422 | mpeg2_set_fbuf (mpeg2dec, (mpeg2dec->decoder.coding_type == | ||
423 | PIC_FLAG_CODING_TYPE_B)); | ||
424 | |||
425 | fbuf = mpeg2dec->fbuf[0]; | ||
426 | } | ||
427 | else | ||
428 | { | ||
429 | fbuf = &mpeg2dec->fbuf_alloc[mpeg2dec->alloc_index].fbuf; | ||
430 | mpeg2dec->alloc_index_user = ++mpeg2dec->alloc_index; | ||
431 | } | ||
432 | |||
433 | fbuf->buf[0] = buf[0]; | ||
434 | #if MPEG2_COLOR | ||
435 | fbuf->buf[1] = buf[1]; | ||
436 | fbuf->buf[2] = buf[2]; | ||
437 | #endif | ||
438 | |||
439 | fbuf->id = id; | ||
440 | } | ||
441 | |||
442 | void mpeg2_custom_fbuf (mpeg2dec_t * mpeg2dec, int custom_fbuf) | ||
443 | { | ||
444 | mpeg2dec->custom_fbuf = custom_fbuf; | ||
445 | } | ||
446 | |||
447 | void mpeg2_skip (mpeg2dec_t * mpeg2dec, int skip) | ||
448 | { | ||
449 | mpeg2dec->first_decode_slice = 1; | ||
450 | mpeg2dec->nb_decode_slices = skip ? 0 : (0xb0 - 1); | ||
451 | } | ||
452 | |||
453 | void mpeg2_slice_region (mpeg2dec_t * mpeg2dec, int start, int end) | ||
454 | { | ||
455 | start = (start < 1) ? 1 : (start > 0xb0) ? 0xb0 : start; | ||
456 | end = (end < start) ? start : (end > 0xb0) ? 0xb0 : end; | ||
457 | mpeg2dec->first_decode_slice = start; | ||
458 | mpeg2dec->nb_decode_slices = end - start; | ||
459 | } | ||
460 | |||
461 | void mpeg2_tag_picture (mpeg2dec_t * mpeg2dec, uint32_t tag, uint32_t tag2) | ||
462 | { | ||
463 | mpeg2dec->tag_previous = mpeg2dec->tag_current; | ||
464 | mpeg2dec->tag2_previous = mpeg2dec->tag2_current; | ||
465 | mpeg2dec->tag_current = tag; | ||
466 | mpeg2dec->tag2_current = tag2; | ||
467 | mpeg2dec->num_tags++; | ||
468 | mpeg2dec->bytes_since_tag = 0; | ||
469 | } | ||
470 | |||
471 | void mpeg2_reset (mpeg2dec_t * mpeg2dec, int full_reset) | ||
472 | { | ||
473 | mpeg2dec->buf_start = mpeg2dec->buf_end = NULL; | ||
474 | mpeg2dec->num_tags = 0; | ||
475 | mpeg2dec->shift = 0xffffff00; | ||
476 | mpeg2dec->code = 0xb4; | ||
477 | mpeg2dec->action = mpeg2_seek_header; | ||
478 | mpeg2dec->state = STATE_INVALID; | ||
479 | mpeg2dec->first = 1; | ||
480 | |||
481 | mpeg2_reset_info(&mpeg2dec->info); | ||
482 | mpeg2dec->info.gop = NULL; | ||
483 | mpeg2dec->info.user_data = NULL; | ||
484 | mpeg2dec->info.user_data_len = 0; | ||
485 | |||
486 | if (full_reset) | ||
487 | { | ||
488 | mpeg2dec->info.sequence = NULL; | ||
489 | mpeg2_header_state_init (mpeg2dec); | ||
490 | } | ||
491 | } | ||
492 | |||
493 | mpeg2dec_t * mpeg2_init (void) | ||
494 | { | ||
495 | mpeg2dec_t * mpeg2dec; | ||
496 | |||
497 | mpeg2_idct_init (); | ||
498 | |||
499 | mpeg2dec = (mpeg2dec_t *)mpeg2_bufalloc(sizeof (mpeg2dec_t), | ||
500 | MPEG2_ALLOC_MPEG2DEC); | ||
501 | if (mpeg2dec == NULL) | ||
502 | return NULL; | ||
503 | |||
504 | mpeg2dec->decoder.DCTblock = static_dct_block; | ||
505 | |||
506 | rb->memset (mpeg2dec->decoder.DCTblock, 0, DCT_BLOCKSIZE); | ||
507 | |||
508 | DEBUGF("DCTblock: %p\n", mpeg2dec->decoder.DCTblock); | ||
509 | |||
510 | mpeg2dec->chunk_buffer = (uint8_t *)mpeg2_bufalloc(BUFFER_SIZE + 4, | ||
511 | MPEG2_ALLOC_CHUNK); | ||
512 | |||
513 | mpeg2dec->sequence.width = (unsigned)-1; | ||
514 | mpeg2_reset (mpeg2dec, 1); | ||
515 | |||
516 | return mpeg2dec; | ||
517 | } | ||
518 | |||
519 | void mpeg2_close (mpeg2dec_t * mpeg2dec) | ||
520 | { | ||
521 | mpeg2_header_state_init (mpeg2dec); | ||
522 | #if 0 | ||
523 | /* These are dedicated buffers in rockbox */ | ||
524 | mpeg2_free (mpeg2dec->chunk_buffer); | ||
525 | mpeg2_free (mpeg2dec); | ||
526 | #endif | ||
527 | } | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/header.c b/apps/plugins/mpegplayer/libmpeg2/header.c deleted file mode 100644 index b40193a338..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/header.c +++ /dev/null | |||
@@ -1,1287 +0,0 @@ | |||
1 | /* | ||
2 | * header.c | ||
3 | * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> | ||
4 | * Copyright (C) 2003 Regis Duchesne <hpreg@zoy.org> | ||
5 | * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> | ||
6 | * | ||
7 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
8 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
9 | * | ||
10 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * mpeg2dec is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * $Id$ | ||
25 | * libmpeg2 sync history: | ||
26 | * 2008-07-01 - CVS revision 1.101 | ||
27 | */ | ||
28 | |||
29 | #include "plugin.h" | ||
30 | |||
31 | #include "mpeg2dec_config.h" | ||
32 | |||
33 | #include "mpeg2.h" | ||
34 | #include "attributes.h" | ||
35 | #include "mpeg2_internal.h" | ||
36 | |||
37 | #define SEQ_EXT 2 | ||
38 | #define SEQ_DISPLAY_EXT 4 | ||
39 | #define QUANT_MATRIX_EXT 8 | ||
40 | #define COPYRIGHT_EXT 0x10 | ||
41 | #define PIC_DISPLAY_EXT 0x80 | ||
42 | #define PIC_CODING_EXT 0x100 | ||
43 | |||
44 | /* default intra quant matrix, in zig-zag order */ | ||
45 | static const uint8_t default_intra_quantizer_matrix[64] = | ||
46 | { | ||
47 | 8, | ||
48 | 16, 16, | ||
49 | 19, 16, 19, | ||
50 | 22, 22, 22, 22, | ||
51 | 22, 22, 26, 24, 26, | ||
52 | 27, 27, 27, 26, 26, 26, | ||
53 | 26, 27, 27, 27, 29, 29, 29, | ||
54 | 34, 34, 34, 29, 29, 29, 27, 27, | ||
55 | 29, 29, 32, 32, 34, 34, 37, | ||
56 | 38, 37, 35, 35, 34, 35, | ||
57 | 38, 38, 40, 40, 40, | ||
58 | 48, 48, 46, 46, | ||
59 | 56, 56, 58, | ||
60 | 69, 69, | ||
61 | 83 | ||
62 | }; | ||
63 | |||
64 | const uint8_t default_mpeg2_scan_norm[64] = | ||
65 | { | ||
66 | /* Zig-Zag scan pattern */ | ||
67 | 0, 1, 8, 16, 9, 2, 3, 10, | ||
68 | 17, 24, 32, 25, 18, 11, 4, 5, | ||
69 | 12, 19, 26, 33, 40, 48, 41, 34, | ||
70 | 27, 20, 13, 6, 7, 14, 21, 28, | ||
71 | 35, 42, 49, 56, 57, 50, 43, 36, | ||
72 | 29, 22, 15, 23, 30, 37, 44, 51, | ||
73 | 58, 59, 52, 45, 38, 31, 39, 46, | ||
74 | 53, 60, 61, 54, 47, 55, 62, 63 | ||
75 | }; | ||
76 | |||
77 | const uint8_t default_mpeg2_scan_alt[64] = | ||
78 | { | ||
79 | /* Alternate scan pattern */ | ||
80 | 0, 8, 16, 24, 1, 9, 2, 10, | ||
81 | 17, 25, 32, 40, 48, 56, 57, 49, | ||
82 | 41, 33, 26, 18, 3, 11, 4, 12, | ||
83 | 19, 27, 34, 42, 50, 58, 35, 43, | ||
84 | 51, 59, 20, 28, 5, 13, 6, 14, | ||
85 | 21, 29, 36, 44, 52, 60, 37, 45, | ||
86 | 53, 61, 22, 30, 7, 15, 23, 31, | ||
87 | 38, 46, 54, 62, 39, 47, 55, 63 | ||
88 | }; | ||
89 | |||
90 | uint8_t mpeg2_scan_norm[64] IDATA_ATTR; | ||
91 | uint8_t mpeg2_scan_alt[64] IDATA_ATTR; | ||
92 | |||
93 | void mpeg2_header_state_init (mpeg2dec_t * mpeg2dec) | ||
94 | { | ||
95 | if (mpeg2dec->sequence.width != (unsigned)-1) | ||
96 | { | ||
97 | mpeg2dec->sequence.width = (unsigned)-1; | ||
98 | mpeg2_mem_reset(); /* Clean the memory slate */ | ||
99 | #if 0 | ||
100 | if (!mpeg2dec->custom_fbuf) | ||
101 | { | ||
102 | int i; | ||
103 | for (i = mpeg2dec->alloc_index_user; | ||
104 | i < mpeg2dec->alloc_index; i++) | ||
105 | { | ||
106 | mpeg2_free(mpeg2dec->fbuf_alloc[i].fbuf.buf[0]); | ||
107 | #if MPEG2_COLOR | ||
108 | mpeg2_free(mpeg2dec->fbuf_alloc[i].fbuf.buf[1]); | ||
109 | mpeg2_free(mpeg2dec->fbuf_alloc[i].fbuf.buf[2]); | ||
110 | #endif | ||
111 | } | ||
112 | } | ||
113 | |||
114 | if (mpeg2dec->convert_start) | ||
115 | { | ||
116 | int i; | ||
117 | for (i = 0; i < 3; i++) | ||
118 | { | ||
119 | mpeg2_free(mpeg2dec->yuv_buf[i][0]); | ||
120 | #if MPEG2_COLOR | ||
121 | mpeg2_free(mpeg2dec->yuv_buf[i][1]); | ||
122 | mpeg2_free(mpeg2dec->yuv_buf[i][2]); | ||
123 | #endif | ||
124 | } | ||
125 | } | ||
126 | |||
127 | if (mpeg2dec->decoder.convert_id) | ||
128 | { | ||
129 | mpeg2_free(mpeg2dec->decoder.convert_id); | ||
130 | } | ||
131 | #endif | ||
132 | } | ||
133 | |||
134 | mpeg2dec->decoder.coding_type = I_TYPE; | ||
135 | mpeg2dec->decoder.convert = NULL; | ||
136 | mpeg2dec->decoder.convert_id = NULL; | ||
137 | |||
138 | mpeg2dec->picture = mpeg2dec->pictures; | ||
139 | |||
140 | mpeg2dec->fbuf[0] = &mpeg2dec->fbuf_alloc[0].fbuf; | ||
141 | mpeg2dec->fbuf[1] = &mpeg2dec->fbuf_alloc[1].fbuf; | ||
142 | mpeg2dec->fbuf[2] = &mpeg2dec->fbuf_alloc[2].fbuf; | ||
143 | |||
144 | mpeg2dec->first = 1; | ||
145 | mpeg2dec->alloc_index = 0; | ||
146 | mpeg2dec->alloc_index_user = 0; | ||
147 | mpeg2dec->first_decode_slice = 1; | ||
148 | mpeg2dec->nb_decode_slices = 0xb0 - 1; | ||
149 | mpeg2dec->convert = NULL; | ||
150 | mpeg2dec->convert_start = NULL; | ||
151 | mpeg2dec->custom_fbuf = 0; | ||
152 | mpeg2dec->yuv_index = 0; | ||
153 | } | ||
154 | |||
155 | void mpeg2_reset_info (mpeg2_info_t * info) | ||
156 | { | ||
157 | info->current_picture = | ||
158 | info->current_picture_2nd = NULL; | ||
159 | |||
160 | info->display_picture = | ||
161 | info->display_picture_2nd = NULL; | ||
162 | |||
163 | info->current_fbuf = | ||
164 | info->display_fbuf = | ||
165 | info->discard_fbuf = NULL; | ||
166 | } | ||
167 | |||
168 | static void info_user_data (mpeg2dec_t * mpeg2dec) | ||
169 | { | ||
170 | if (mpeg2dec->user_data_len) | ||
171 | { | ||
172 | mpeg2dec->info.user_data = mpeg2dec->chunk_buffer; | ||
173 | mpeg2dec->info.user_data_len = mpeg2dec->user_data_len - 3; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | int mpeg2_header_sequence (mpeg2dec_t * mpeg2dec) | ||
178 | { | ||
179 | static const unsigned int frame_period[16] = | ||
180 | { | ||
181 | 0, 1126125, 1125000, 1080000, 900900, 900000, 540000, 450450, 450000, | ||
182 | /* unofficial: xing 15 fps */ | ||
183 | 1800000, | ||
184 | /* unofficial: libmpeg3 "Unofficial economy rates" 5/10/12/15 fps */ | ||
185 | 5400000, 2700000, 2250000, 1800000, 0, 0 | ||
186 | }; | ||
187 | |||
188 | uint8_t * buffer = mpeg2dec->chunk_start; | ||
189 | mpeg2_sequence_t * sequence = &mpeg2dec->new_sequence; | ||
190 | int i; | ||
191 | |||
192 | if ((buffer[6] & 0x20) != 0x20) /* missing marker_bit */ | ||
193 | return 1; | ||
194 | |||
195 | i = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2]; | ||
196 | |||
197 | if (!(sequence->display_width = sequence->picture_width = i >> 12)) | ||
198 | return 1; | ||
199 | |||
200 | if (!(sequence->display_height = sequence->picture_height = i & 0xfff)) | ||
201 | return 1; | ||
202 | |||
203 | sequence->width = (sequence->picture_width + 15) & ~15; | ||
204 | sequence->height = (sequence->picture_height + 15) & ~15; | ||
205 | sequence->chroma_width = sequence->width >> 1; | ||
206 | sequence->chroma_height = sequence->height >> 1; | ||
207 | |||
208 | sequence->flags = SEQ_FLAG_PROGRESSIVE_SEQUENCE | | ||
209 | SEQ_VIDEO_FORMAT_UNSPECIFIED; | ||
210 | |||
211 | sequence->pixel_width = buffer[3] >> 4; /* aspect ratio */ | ||
212 | sequence->frame_period = frame_period[buffer[3] & 15]; | ||
213 | |||
214 | sequence->byte_rate = (buffer[4]<<10) | (buffer[5]<<2) | (buffer[6]>>6); | ||
215 | |||
216 | sequence->vbv_buffer_size = ((buffer[6]<<16) | (buffer[7]<<8)) & 0x1ff800; | ||
217 | |||
218 | if (buffer[7] & 4) | ||
219 | sequence->flags |= SEQ_FLAG_CONSTRAINED_PARAMETERS; | ||
220 | |||
221 | mpeg2dec->copy_matrix = 3; | ||
222 | |||
223 | if (buffer[7] & 2) | ||
224 | { | ||
225 | for (i = 0; i < 64; i++) | ||
226 | { | ||
227 | mpeg2dec->new_quantizer_matrix[0][mpeg2_scan_norm[i]] = | ||
228 | (buffer[i+7] << 7) | (buffer[i+8] >> 1); | ||
229 | } | ||
230 | |||
231 | buffer += 64; | ||
232 | } | ||
233 | else | ||
234 | { | ||
235 | for (i = 0; i < 64; i++) | ||
236 | { | ||
237 | mpeg2dec->new_quantizer_matrix[0][mpeg2_scan_norm[i]] = | ||
238 | default_intra_quantizer_matrix[i]; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | if (buffer[7] & 1) | ||
243 | { | ||
244 | for (i = 0; i < 64; i++) | ||
245 | { | ||
246 | mpeg2dec->new_quantizer_matrix[1][mpeg2_scan_norm[i]] = | ||
247 | buffer[i+8]; | ||
248 | } | ||
249 | } | ||
250 | else | ||
251 | { | ||
252 | rb->memset (mpeg2dec->new_quantizer_matrix[1], 16, 64); | ||
253 | } | ||
254 | |||
255 | sequence->profile_level_id = 0x80; | ||
256 | sequence->colour_primaries = 0; | ||
257 | sequence->transfer_characteristics = 0; | ||
258 | sequence->matrix_coefficients = 0; | ||
259 | |||
260 | mpeg2dec->ext_state = SEQ_EXT; | ||
261 | mpeg2dec->state = STATE_SEQUENCE; | ||
262 | |||
263 | mpeg2dec->display_offset_x = | ||
264 | mpeg2dec->display_offset_y = 0; | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int sequence_ext (mpeg2dec_t * mpeg2dec) | ||
270 | { | ||
271 | uint8_t * buffer = mpeg2dec->chunk_start; | ||
272 | mpeg2_sequence_t * sequence = &mpeg2dec->new_sequence; | ||
273 | uint32_t flags; | ||
274 | |||
275 | if (!(buffer[3] & 1)) | ||
276 | return 1; | ||
277 | |||
278 | sequence->profile_level_id = (buffer[0] << 4) | (buffer[1] >> 4); | ||
279 | |||
280 | sequence->picture_width += ((buffer[1] << 13) | (buffer[2] << 5)) & 0x3000; | ||
281 | sequence->display_width = sequence->picture_width; | ||
282 | |||
283 | sequence->picture_height += (buffer[2] << 7) & 0x3000; | ||
284 | sequence->display_height = sequence->picture_height; | ||
285 | |||
286 | sequence->width = (sequence->picture_width + 15) & ~15; | ||
287 | sequence->height = (sequence->picture_height + 15) & ~15; | ||
288 | |||
289 | flags = sequence->flags | SEQ_FLAG_MPEG2; | ||
290 | |||
291 | if (!(buffer[1] & 8)) | ||
292 | { | ||
293 | flags &= ~SEQ_FLAG_PROGRESSIVE_SEQUENCE; | ||
294 | sequence->height = (sequence->height + 31) & ~31; | ||
295 | } | ||
296 | |||
297 | if (buffer[5] & 0x80) | ||
298 | flags |= SEQ_FLAG_LOW_DELAY; | ||
299 | |||
300 | sequence->flags = flags; | ||
301 | sequence->chroma_width = sequence->width; | ||
302 | sequence->chroma_height = sequence->height; | ||
303 | |||
304 | switch (buffer[1] & 6) | ||
305 | { | ||
306 | case 0: /* invalid */ | ||
307 | return 1; | ||
308 | case 2: /* 4:2:0 */ | ||
309 | sequence->chroma_height >>= 1; | ||
310 | /* fallthrough */ | ||
311 | case 4: /* 4:2:2 */ | ||
312 | sequence->chroma_width >>= 1; | ||
313 | } | ||
314 | |||
315 | sequence->byte_rate += ((buffer[2]<<25) | (buffer[3]<<17)) & 0x3ffc0000; | ||
316 | |||
317 | sequence->vbv_buffer_size |= buffer[4] << 21; | ||
318 | |||
319 | sequence->frame_period = | ||
320 | sequence->frame_period * ((buffer[5]&31)+1) / (((buffer[5]>>2)&3)+1); | ||
321 | |||
322 | mpeg2dec->ext_state = SEQ_DISPLAY_EXT; | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static int sequence_display_ext (mpeg2dec_t * mpeg2dec) | ||
328 | { | ||
329 | uint8_t * buffer = mpeg2dec->chunk_start; | ||
330 | mpeg2_sequence_t * sequence = &mpeg2dec->new_sequence; | ||
331 | int x; | ||
332 | |||
333 | sequence->flags = (sequence->flags & ~SEQ_MASK_VIDEO_FORMAT) | | ||
334 | ((buffer[0] << 4) & SEQ_MASK_VIDEO_FORMAT); | ||
335 | |||
336 | if (buffer[0] & 1) | ||
337 | { | ||
338 | sequence->flags |= SEQ_FLAG_COLOUR_DESCRIPTION; | ||
339 | sequence->colour_primaries = buffer[1]; | ||
340 | sequence->transfer_characteristics = buffer[2]; | ||
341 | sequence->matrix_coefficients = buffer[3]; | ||
342 | buffer += 3; | ||
343 | } | ||
344 | |||
345 | if (!(buffer[2] & 2)) /* missing marker_bit */ | ||
346 | return 1; | ||
347 | |||
348 | x = (buffer[1] << 6) | (buffer[2] >> 2); | ||
349 | if (x) | ||
350 | sequence->display_width = x; | ||
351 | |||
352 | x = ((buffer[2] & 1) << 13) | (buffer[3] << 5) | (buffer[4] >> 3); | ||
353 | if (x) | ||
354 | sequence->display_height = x; | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static inline void simplify (unsigned int * u, unsigned int * v) | ||
360 | { | ||
361 | unsigned int a, b, tmp; | ||
362 | |||
363 | a = *u; | ||
364 | b = *v; | ||
365 | |||
366 | /* find greatest common divisor */ | ||
367 | while (a) | ||
368 | { | ||
369 | tmp = a; | ||
370 | a = b % tmp; | ||
371 | b = tmp; | ||
372 | } | ||
373 | |||
374 | *u /= b; | ||
375 | *v /= b; | ||
376 | } | ||
377 | |||
378 | static inline void finalize_sequence (mpeg2_sequence_t * sequence) | ||
379 | { | ||
380 | int width; | ||
381 | int height; | ||
382 | |||
383 | sequence->byte_rate *= 50; | ||
384 | |||
385 | if (sequence->flags & SEQ_FLAG_MPEG2) | ||
386 | { | ||
387 | switch (sequence->pixel_width) | ||
388 | { | ||
389 | case 1: /* square pixels */ | ||
390 | sequence->pixel_width = | ||
391 | sequence->pixel_height = 1; | ||
392 | return; | ||
393 | case 2: /* 4:3 aspect ratio */ | ||
394 | width = 4; | ||
395 | height = 3; | ||
396 | break; | ||
397 | case 3: /* 16:9 aspect ratio */ | ||
398 | width = 16; | ||
399 | height = 9; | ||
400 | break; | ||
401 | case 4: /* 2.21:1 aspect ratio */ | ||
402 | width = 221; | ||
403 | height = 100; | ||
404 | break; | ||
405 | default: /* illegal */ | ||
406 | sequence->pixel_width = | ||
407 | sequence->pixel_height = 0; | ||
408 | return; | ||
409 | } | ||
410 | |||
411 | width *= sequence->display_height; | ||
412 | height *= sequence->display_width; | ||
413 | } | ||
414 | else | ||
415 | { | ||
416 | if (sequence->byte_rate == 50 * 0x3ffff) | ||
417 | sequence->byte_rate = 0; /* mpeg-1 VBR */ | ||
418 | |||
419 | switch (sequence->pixel_width) | ||
420 | { | ||
421 | case 0: | ||
422 | case 15: /* illegal */ | ||
423 | sequence->pixel_width = | ||
424 | sequence->pixel_height = 0; | ||
425 | return; | ||
426 | case 1: /* square pixels */ | ||
427 | sequence->pixel_width = | ||
428 | sequence->pixel_height = 1; | ||
429 | return; | ||
430 | case 3: /* 720x576 16:9 */ | ||
431 | sequence->pixel_width = 64; | ||
432 | sequence->pixel_height = 45; | ||
433 | return; | ||
434 | case 6: /* 720x480 16:9 */ | ||
435 | sequence->pixel_width = 32; | ||
436 | sequence->pixel_height = 27; | ||
437 | return; | ||
438 | case 8: /* BT.601 625 lines 4:3 */ | ||
439 | sequence->pixel_width = 59; | ||
440 | sequence->pixel_height = 54; | ||
441 | return; | ||
442 | case 12: /* BT.601 525 lines 4:3 */ | ||
443 | sequence->pixel_width = 10; | ||
444 | sequence->pixel_height = 11; | ||
445 | return; | ||
446 | default: | ||
447 | height = 88 * sequence->pixel_width + 1171; | ||
448 | width = 2000; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | sequence->pixel_width = width; | ||
453 | sequence->pixel_height = height; | ||
454 | |||
455 | simplify(&sequence->pixel_width, &sequence->pixel_height); | ||
456 | } | ||
457 | |||
458 | int mpeg2_guess_aspect (const mpeg2_sequence_t * sequence, | ||
459 | unsigned int * pixel_width, | ||
460 | unsigned int * pixel_height) | ||
461 | { | ||
462 | static const struct | ||
463 | { | ||
464 | unsigned int width, height; | ||
465 | } video_modes[] = | ||
466 | { | ||
467 | {720, 576}, /* 625 lines, 13.5 MHz (D1, DV, DVB, DVD) */ | ||
468 | {704, 576}, /* 625 lines, 13.5 MHz (1/1 D1, DVB, DVD, 4CIF) */ | ||
469 | {544, 576}, /* 625 lines, 10.125 MHz (DVB, laserdisc) */ | ||
470 | {528, 576}, /* 625 lines, 10.125 MHz (3/4 D1, DVB, laserdisc) */ | ||
471 | {480, 576}, /* 625 lines, 9 MHz (2/3 D1, DVB, SVCD) */ | ||
472 | {352, 576}, /* 625 lines, 6.75 MHz (D2, 1/2 D1, CVD, DVB, DVD) */ | ||
473 | {352, 288}, /* 625 lines, 6.75 MHz, 1 field (D4, VCD, DVB, DVD, CIF) */ | ||
474 | {176, 144}, /* 625 lines, 3.375 MHz, half field (QCIF) */ | ||
475 | {720, 486}, /* 525 lines, 13.5 MHz (D1) */ | ||
476 | {704, 486}, /* 525 lines, 13.5 MHz */ | ||
477 | {720, 480}, /* 525 lines, 13.5 MHz (DV, DSS, DVD) */ | ||
478 | {704, 480}, /* 525 lines, 13.5 MHz (1/1 D1, ATSC, DVD) */ | ||
479 | {544, 480}, /* 525 lines. 10.125 MHz (DSS, laserdisc) */ | ||
480 | {528, 480}, /* 525 lines. 10.125 MHz (3/4 D1, laserdisc) */ | ||
481 | {480, 480}, /* 525 lines, 9 MHz (2/3 D1, SVCD) */ | ||
482 | {352, 480}, /* 525 lines, 6.75 MHz (D2, 1/2 D1, CVD, DVD) */ | ||
483 | {352, 240} /* 525 lines. 6.75 MHz, 1 field (D4, VCD, DSS, DVD) */ | ||
484 | }; | ||
485 | unsigned int width, height, pix_width, pix_height, i, DAR_16_9; | ||
486 | |||
487 | *pixel_width = sequence->pixel_width; | ||
488 | *pixel_height = sequence->pixel_height; | ||
489 | width = sequence->picture_width; | ||
490 | height = sequence->picture_height; | ||
491 | |||
492 | for (i = 0; i < sizeof (video_modes) / sizeof (video_modes[0]); i++) | ||
493 | { | ||
494 | if (width == video_modes[i].width && height == video_modes[i].height) | ||
495 | break; | ||
496 | } | ||
497 | |||
498 | if (i == ARRAYLEN(video_modes) || | ||
499 | (sequence->pixel_width == 1 && sequence->pixel_height == 1) || | ||
500 | width != sequence->display_width || height != sequence->display_height) | ||
501 | { | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | for (pix_height = 1; height * pix_height < 480; pix_height <<= 1); | ||
506 | height *= pix_height; | ||
507 | |||
508 | for (pix_width = 1; width * pix_width <= 352; pix_width <<= 1); | ||
509 | width *= pix_width; | ||
510 | |||
511 | if (!(sequence->flags & SEQ_FLAG_MPEG2)) | ||
512 | { | ||
513 | static unsigned int mpeg1_check[2][2] = {{11, 54}, {27, 45}}; | ||
514 | DAR_16_9 = (sequence->pixel_height == 27 || | ||
515 | sequence->pixel_height == 45); | ||
516 | if (width < 704 || | ||
517 | sequence->pixel_height != mpeg1_check[DAR_16_9][height == 576]) | ||
518 | return 0; | ||
519 | } | ||
520 | else | ||
521 | { | ||
522 | DAR_16_9 = (3 * sequence->picture_width * sequence->pixel_width > | ||
523 | 4 * sequence->picture_height * sequence->pixel_height); | ||
524 | switch (width) | ||
525 | { | ||
526 | case 528: | ||
527 | case 544: | ||
528 | pix_width *= 4; | ||
529 | pix_height *= 3; | ||
530 | break; | ||
531 | case 480: | ||
532 | pix_width *= 3; | ||
533 | pix_height *= 2; | ||
534 | break; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | if (DAR_16_9) | ||
539 | { | ||
540 | pix_width *= 4; | ||
541 | pix_height *= 3; | ||
542 | } | ||
543 | |||
544 | if (height == 576) | ||
545 | { | ||
546 | pix_width *= 59; | ||
547 | pix_height *= 54; | ||
548 | } | ||
549 | else | ||
550 | { | ||
551 | pix_width *= 10; | ||
552 | pix_height *= 11; | ||
553 | } | ||
554 | |||
555 | *pixel_width = pix_width; | ||
556 | *pixel_height = pix_height; | ||
557 | |||
558 | simplify (pixel_width, pixel_height); | ||
559 | |||
560 | return (height == 576) ? 1 : 2; | ||
561 | } | ||
562 | |||
563 | static void copy_matrix (mpeg2dec_t * mpeg2dec, int index) | ||
564 | { | ||
565 | if (rb->memcmp (mpeg2dec->quantizer_matrix[index], | ||
566 | mpeg2dec->new_quantizer_matrix[index], 64)) | ||
567 | { | ||
568 | rb->memcpy (mpeg2dec->quantizer_matrix[index], | ||
569 | mpeg2dec->new_quantizer_matrix[index], 64); | ||
570 | |||
571 | mpeg2dec->scaled[index] = -1; | ||
572 | } | ||
573 | } | ||
574 | |||
575 | static void finalize_matrix (mpeg2dec_t * mpeg2dec) | ||
576 | { | ||
577 | mpeg2_decoder_t *decoder = &mpeg2dec->decoder; | ||
578 | int i; | ||
579 | |||
580 | for (i = 0; i < 2; i++) | ||
581 | { | ||
582 | if (mpeg2dec->copy_matrix & (1 << i)) | ||
583 | copy_matrix (mpeg2dec, i); | ||
584 | |||
585 | if ((mpeg2dec->copy_matrix & (4 << i)) && | ||
586 | rb->memcmp(mpeg2dec->quantizer_matrix[i], | ||
587 | mpeg2dec->new_quantizer_matrix[i+2], 64)) | ||
588 | { | ||
589 | copy_matrix (mpeg2dec, i + 2); | ||
590 | decoder->chroma_quantizer[i] = decoder->quantizer_prescale[i+2]; | ||
591 | } | ||
592 | else if (mpeg2dec->copy_matrix & (5 << i)) | ||
593 | { | ||
594 | decoder->chroma_quantizer[i] = decoder->quantizer_prescale[i]; | ||
595 | } | ||
596 | } | ||
597 | } | ||
598 | |||
599 | static mpeg2_state_t invalid_end_action (mpeg2dec_t * mpeg2dec) | ||
600 | { | ||
601 | mpeg2_reset_info (&mpeg2dec->info); | ||
602 | |||
603 | mpeg2dec->info.gop = NULL; | ||
604 | |||
605 | info_user_data (mpeg2dec); | ||
606 | |||
607 | mpeg2_header_state_init (mpeg2dec); | ||
608 | |||
609 | mpeg2dec->sequence = mpeg2dec->new_sequence; | ||
610 | mpeg2dec->action = mpeg2_seek_header; | ||
611 | mpeg2dec->state = STATE_SEQUENCE; | ||
612 | |||
613 | return STATE_SEQUENCE; | ||
614 | } | ||
615 | |||
616 | void mpeg2_header_sequence_finalize (mpeg2dec_t * mpeg2dec) | ||
617 | { | ||
618 | mpeg2_sequence_t * sequence = &mpeg2dec->new_sequence; | ||
619 | mpeg2_decoder_t * decoder = &mpeg2dec->decoder; | ||
620 | |||
621 | finalize_sequence(sequence); | ||
622 | finalize_matrix(mpeg2dec); | ||
623 | |||
624 | decoder->mpeg1 = !(sequence->flags & SEQ_FLAG_MPEG2); | ||
625 | decoder->width = sequence->width; | ||
626 | decoder->height = sequence->height; | ||
627 | decoder->vertical_position_extension = sequence->picture_height > 2800; | ||
628 | decoder->chroma_format = (sequence->chroma_width == sequence->width) + | ||
629 | (sequence->chroma_height == sequence->height); | ||
630 | |||
631 | if (mpeg2dec->sequence.width != (unsigned)-1) | ||
632 | { | ||
633 | /* | ||
634 | * According to 6.1.1.6, repeat sequence headers should be | ||
635 | * identical to the original. However some encoders don't | ||
636 | * respect that and change various fields (including bitrate | ||
637 | * and aspect ratio) in the repeat sequence headers. So we | ||
638 | * choose to be as conservative as possible and only restart | ||
639 | * the decoder if the width, height, chroma_width, | ||
640 | * chroma_height or low_delay flag are modified. | ||
641 | */ | ||
642 | if (sequence->width != mpeg2dec->sequence.width || | ||
643 | sequence->height != mpeg2dec->sequence.height || | ||
644 | sequence->chroma_width != mpeg2dec->sequence.chroma_width || | ||
645 | sequence->chroma_height != mpeg2dec->sequence.chroma_height || | ||
646 | ((sequence->flags ^ mpeg2dec->sequence.flags) & | ||
647 | SEQ_FLAG_LOW_DELAY)) | ||
648 | { | ||
649 | decoder->stride_frame = sequence->width; | ||
650 | mpeg2_header_end (mpeg2dec); | ||
651 | mpeg2dec->action = invalid_end_action; | ||
652 | mpeg2dec->state = STATE_INVALID_END; | ||
653 | return; | ||
654 | } | ||
655 | |||
656 | mpeg2dec->state = rb->memcmp(&mpeg2dec->sequence, sequence, | ||
657 | sizeof (mpeg2_sequence_t)) ? | ||
658 | STATE_SEQUENCE_MODIFIED : | ||
659 | STATE_SEQUENCE_REPEATED; | ||
660 | } | ||
661 | else | ||
662 | { | ||
663 | decoder->stride_frame = sequence->width; | ||
664 | } | ||
665 | |||
666 | mpeg2dec->sequence = *sequence; | ||
667 | mpeg2_reset_info(&mpeg2dec->info); | ||
668 | mpeg2dec->info.sequence = &mpeg2dec->sequence; | ||
669 | mpeg2dec->info.gop = NULL; | ||
670 | |||
671 | info_user_data (mpeg2dec); | ||
672 | } | ||
673 | |||
674 | int mpeg2_header_gop (mpeg2dec_t * mpeg2dec) | ||
675 | { | ||
676 | uint8_t * buffer = mpeg2dec->chunk_start; | ||
677 | mpeg2_gop_t * gop = &mpeg2dec->new_gop; | ||
678 | |||
679 | if (!(buffer[1] & 8)) | ||
680 | return 1; | ||
681 | |||
682 | gop->hours = (buffer[0] >> 2) & 31; | ||
683 | gop->minutes = ((buffer[0] << 4) | (buffer[1] >> 4)) & 63; | ||
684 | gop->seconds = ((buffer[1] << 3) | (buffer[2] >> 5)) & 63; | ||
685 | gop->pictures = ((buffer[2] << 1) | (buffer[3] >> 7)) & 63; | ||
686 | gop->flags = (buffer[0] >> 7) | ((buffer[3] >> 4) & 6); | ||
687 | |||
688 | mpeg2dec->state = STATE_GOP; | ||
689 | return 0; | ||
690 | } | ||
691 | |||
692 | void mpeg2_header_gop_finalize (mpeg2dec_t * mpeg2dec) | ||
693 | { | ||
694 | mpeg2dec->gop = mpeg2dec->new_gop; | ||
695 | mpeg2_reset_info (&mpeg2dec->info); | ||
696 | mpeg2dec->info.gop = &mpeg2dec->gop; | ||
697 | info_user_data (mpeg2dec); | ||
698 | } | ||
699 | |||
700 | void mpeg2_set_fbuf (mpeg2dec_t * mpeg2dec, int b_type) | ||
701 | { | ||
702 | int i; | ||
703 | |||
704 | for (i = 0; i < 3; i++) | ||
705 | { | ||
706 | if (mpeg2dec->fbuf[1] != &mpeg2dec->fbuf_alloc[i].fbuf && | ||
707 | mpeg2dec->fbuf[2] != &mpeg2dec->fbuf_alloc[i].fbuf) | ||
708 | { | ||
709 | mpeg2dec->fbuf[0] = &mpeg2dec->fbuf_alloc[i].fbuf; | ||
710 | mpeg2dec->info.current_fbuf = mpeg2dec->fbuf[0]; | ||
711 | |||
712 | if (b_type || (mpeg2dec->sequence.flags & SEQ_FLAG_LOW_DELAY)) | ||
713 | { | ||
714 | if (b_type || mpeg2dec->convert) | ||
715 | mpeg2dec->info.discard_fbuf = mpeg2dec->fbuf[0]; | ||
716 | |||
717 | mpeg2dec->info.display_fbuf = mpeg2dec->fbuf[0]; | ||
718 | } | ||
719 | |||
720 | break; | ||
721 | } | ||
722 | } | ||
723 | } | ||
724 | |||
725 | int mpeg2_header_picture (mpeg2dec_t * mpeg2dec) | ||
726 | { | ||
727 | uint8_t * buffer = mpeg2dec->chunk_start; | ||
728 | mpeg2_picture_t * picture = &mpeg2dec->new_picture; | ||
729 | mpeg2_decoder_t * decoder = &mpeg2dec->decoder; | ||
730 | int type; | ||
731 | |||
732 | mpeg2dec->state = (mpeg2dec->state != STATE_SLICE_1ST) ? | ||
733 | STATE_PICTURE : STATE_PICTURE_2ND; | ||
734 | mpeg2dec->ext_state = PIC_CODING_EXT; | ||
735 | |||
736 | picture->temporal_reference = (buffer[0] << 2) | (buffer[1] >> 6); | ||
737 | |||
738 | type = (buffer [1] >> 3) & 7; | ||
739 | |||
740 | if (type == PIC_FLAG_CODING_TYPE_P || type == PIC_FLAG_CODING_TYPE_B) | ||
741 | { | ||
742 | /* forward_f_code and backward_f_code - used in mpeg1 only */ | ||
743 | decoder->f_motion.f_code[1] = (buffer[3] >> 2) & 1; | ||
744 | decoder->f_motion.f_code[0] = | ||
745 | (((buffer[3] << 1) | (buffer[4] >> 7)) & 7) - 1; | ||
746 | decoder->b_motion.f_code[1] = (buffer[4] >> 6) & 1; | ||
747 | decoder->b_motion.f_code[0] = ((buffer[4] >> 3) & 7) - 1; | ||
748 | } | ||
749 | |||
750 | picture->flags = PIC_FLAG_PROGRESSIVE_FRAME | type; | ||
751 | picture->tag = picture->tag2 = 0; | ||
752 | |||
753 | if (mpeg2dec->num_tags) | ||
754 | { | ||
755 | if (mpeg2dec->bytes_since_tag >= mpeg2dec->chunk_ptr - buffer + 4) | ||
756 | { | ||
757 | mpeg2dec->num_tags = 0; | ||
758 | picture->tag = mpeg2dec->tag_current; | ||
759 | picture->tag2 = mpeg2dec->tag2_current; | ||
760 | picture->flags |= PIC_FLAG_TAGS; | ||
761 | } | ||
762 | else if (mpeg2dec->num_tags > 1) | ||
763 | { | ||
764 | mpeg2dec->num_tags = 1; | ||
765 | picture->tag = mpeg2dec->tag_previous; | ||
766 | picture->tag2 = mpeg2dec->tag2_previous; | ||
767 | picture->flags |= PIC_FLAG_TAGS; | ||
768 | } | ||
769 | } | ||
770 | |||
771 | picture->nb_fields = 2; | ||
772 | picture->display_offset[0].x = picture->display_offset[1].x = | ||
773 | picture->display_offset[2].x = mpeg2dec->display_offset_x; | ||
774 | |||
775 | picture->display_offset[0].y = picture->display_offset[1].y = | ||
776 | picture->display_offset[2].y = mpeg2dec->display_offset_y; | ||
777 | |||
778 | /* XXXXXX decode extra_information_picture as well */ | ||
779 | |||
780 | mpeg2dec->q_scale_type = 0; | ||
781 | decoder->intra_dc_precision = 7; | ||
782 | decoder->frame_pred_frame_dct = 1; | ||
783 | decoder->concealment_motion_vectors = 0; | ||
784 | decoder->scan = mpeg2_scan_norm; | ||
785 | decoder->picture_structure = FRAME_PICTURE; | ||
786 | mpeg2dec->copy_matrix = 0; | ||
787 | |||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | static int picture_coding_ext (mpeg2dec_t * mpeg2dec) | ||
792 | { | ||
793 | uint8_t * buffer = mpeg2dec->chunk_start; | ||
794 | mpeg2_picture_t * picture = &mpeg2dec->new_picture; | ||
795 | mpeg2_decoder_t * decoder = &mpeg2dec->decoder; | ||
796 | uint32_t flags; | ||
797 | |||
798 | /* pre subtract 1 for use later in compute_motion_vector */ | ||
799 | decoder->f_motion.f_code[0] = (buffer[0] & 15) - 1; | ||
800 | decoder->f_motion.f_code[1] = (buffer[1] >> 4) - 1; | ||
801 | decoder->b_motion.f_code[0] = (buffer[1] & 15) - 1; | ||
802 | decoder->b_motion.f_code[1] = (buffer[2] >> 4) - 1; | ||
803 | |||
804 | flags = picture->flags; | ||
805 | |||
806 | decoder->intra_dc_precision = 7 - ((buffer[2] >> 2) & 3); | ||
807 | decoder->picture_structure = buffer[2] & 3; | ||
808 | |||
809 | switch (decoder->picture_structure) | ||
810 | { | ||
811 | case TOP_FIELD: | ||
812 | flags |= PIC_FLAG_TOP_FIELD_FIRST; | ||
813 | case BOTTOM_FIELD: | ||
814 | picture->nb_fields = 1; | ||
815 | break; | ||
816 | case FRAME_PICTURE: | ||
817 | if (!(mpeg2dec->sequence.flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE)) | ||
818 | { | ||
819 | picture->nb_fields = (buffer[3] & 2) ? 3 : 2; | ||
820 | flags |= (buffer[3] & 128) ? PIC_FLAG_TOP_FIELD_FIRST : 0; | ||
821 | } | ||
822 | else | ||
823 | { | ||
824 | picture->nb_fields = (buffer[3]&2) ? ((buffer[3]&128) ? 6 : 4) : 2; | ||
825 | } | ||
826 | break; | ||
827 | default: | ||
828 | return 1; | ||
829 | } | ||
830 | |||
831 | decoder->top_field_first = buffer[3] >> 7; | ||
832 | decoder->frame_pred_frame_dct = (buffer[3] >> 6) & 1; | ||
833 | decoder->concealment_motion_vectors = (buffer[3] >> 5) & 1; | ||
834 | mpeg2dec->q_scale_type = buffer[3] & 16; | ||
835 | decoder->intra_vlc_format = (buffer[3] >> 3) & 1; | ||
836 | decoder->scan = (buffer[3] & 4) ? mpeg2_scan_alt : mpeg2_scan_norm; | ||
837 | |||
838 | if (!(buffer[4] & 0x80)) | ||
839 | flags &= ~PIC_FLAG_PROGRESSIVE_FRAME; | ||
840 | |||
841 | if (buffer[4] & 0x40) | ||
842 | { | ||
843 | flags |= (((buffer[4]<<26) | (buffer[5]<<18) | (buffer[6]<<10)) & | ||
844 | PIC_MASK_COMPOSITE_DISPLAY) | PIC_FLAG_COMPOSITE_DISPLAY; | ||
845 | } | ||
846 | |||
847 | picture->flags = flags; | ||
848 | |||
849 | mpeg2dec->ext_state = PIC_DISPLAY_EXT | COPYRIGHT_EXT | QUANT_MATRIX_EXT; | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
854 | static int picture_display_ext (mpeg2dec_t * mpeg2dec) | ||
855 | { | ||
856 | uint8_t * buffer = mpeg2dec->chunk_start; | ||
857 | mpeg2_picture_t * picture = &mpeg2dec->new_picture; | ||
858 | int i, nb_pos; | ||
859 | |||
860 | nb_pos = picture->nb_fields; | ||
861 | |||
862 | if (mpeg2dec->sequence.flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE) | ||
863 | nb_pos >>= 1; | ||
864 | |||
865 | for (i = 0; i < nb_pos; i++) | ||
866 | { | ||
867 | int x, y; | ||
868 | |||
869 | x = ((buffer[4*i] << 24) | (buffer[4*i+1] << 16) | | ||
870 | (buffer[4*i+2] << 8) | buffer[4*i+3]) >> (11-2*i); | ||
871 | |||
872 | y = ((buffer[4*i+2] << 24) | (buffer[4*i+3] << 16) | | ||
873 | (buffer[4*i+4] << 8) | buffer[4*i+5]) >> (10-2*i); | ||
874 | |||
875 | if (! (x & y & 1)) | ||
876 | return 1; | ||
877 | |||
878 | picture->display_offset[i].x = mpeg2dec->display_offset_x = x >> 1; | ||
879 | picture->display_offset[i].y = mpeg2dec->display_offset_y = y >> 1; | ||
880 | } | ||
881 | |||
882 | for (; i < 3; i++) | ||
883 | { | ||
884 | picture->display_offset[i].x = mpeg2dec->display_offset_x; | ||
885 | picture->display_offset[i].y = mpeg2dec->display_offset_y; | ||
886 | } | ||
887 | |||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | void mpeg2_header_picture_finalize (mpeg2dec_t * mpeg2dec) | ||
892 | { | ||
893 | mpeg2_decoder_t * decoder = &mpeg2dec->decoder; | ||
894 | int old_type_b = decoder->coding_type == B_TYPE; | ||
895 | int low_delay = mpeg2dec->sequence.flags & SEQ_FLAG_LOW_DELAY; | ||
896 | |||
897 | finalize_matrix (mpeg2dec); | ||
898 | decoder->coding_type = mpeg2dec->new_picture.flags & PIC_MASK_CODING_TYPE; | ||
899 | |||
900 | if (mpeg2dec->state == STATE_PICTURE) | ||
901 | { | ||
902 | mpeg2_picture_t * picture; | ||
903 | mpeg2_picture_t * other; | ||
904 | |||
905 | decoder->second_field = 0; | ||
906 | |||
907 | picture = other = mpeg2dec->pictures; | ||
908 | |||
909 | if (old_type_b ^ (mpeg2dec->picture < mpeg2dec->pictures + 2)) | ||
910 | picture += 2; | ||
911 | else | ||
912 | other += 2; | ||
913 | |||
914 | mpeg2dec->picture = picture; | ||
915 | *picture = mpeg2dec->new_picture; | ||
916 | |||
917 | if (!old_type_b) | ||
918 | { | ||
919 | mpeg2dec->fbuf[2] = mpeg2dec->fbuf[1]; | ||
920 | mpeg2dec->fbuf[1] = mpeg2dec->fbuf[0]; | ||
921 | } | ||
922 | |||
923 | mpeg2dec->fbuf[0] = NULL; | ||
924 | mpeg2_reset_info (&mpeg2dec->info); | ||
925 | mpeg2dec->info.current_picture = picture; | ||
926 | mpeg2dec->info.display_picture = picture; | ||
927 | |||
928 | if (decoder->coding_type != B_TYPE) | ||
929 | { | ||
930 | if (!low_delay) | ||
931 | { | ||
932 | if (mpeg2dec->first) | ||
933 | { | ||
934 | mpeg2dec->info.display_picture = NULL; | ||
935 | mpeg2dec->first = 0; | ||
936 | } | ||
937 | else | ||
938 | { | ||
939 | mpeg2dec->info.display_picture = other; | ||
940 | |||
941 | if (other->nb_fields == 1) | ||
942 | mpeg2dec->info.display_picture_2nd = other + 1; | ||
943 | |||
944 | mpeg2dec->info.display_fbuf = mpeg2dec->fbuf[1]; | ||
945 | } | ||
946 | } | ||
947 | |||
948 | if (!low_delay + !mpeg2dec->convert) | ||
949 | { | ||
950 | mpeg2dec->info.discard_fbuf = | ||
951 | mpeg2dec->fbuf[!low_delay + !mpeg2dec->convert]; | ||
952 | } | ||
953 | } | ||
954 | |||
955 | if (mpeg2dec->convert) | ||
956 | { | ||
957 | mpeg2_convert_init_t convert_init; | ||
958 | |||
959 | if (!mpeg2dec->convert_start) | ||
960 | { | ||
961 | mpeg2dec->decoder.convert_id = | ||
962 | mpeg2_malloc (mpeg2dec->convert_id_size, | ||
963 | MPEG2_ALLOC_CONVERT_ID); | ||
964 | |||
965 | mpeg2dec->convert (MPEG2_CONVERT_START, | ||
966 | mpeg2dec->decoder.convert_id, | ||
967 | &mpeg2dec->sequence, | ||
968 | mpeg2dec->convert_stride, | ||
969 | mpeg2dec->convert_arg, &convert_init); | ||
970 | |||
971 | mpeg2dec->convert_start = convert_init.start; | ||
972 | mpeg2dec->decoder.convert = convert_init.copy; | ||
973 | |||
974 | int y_size = decoder->stride_frame * mpeg2dec->sequence.height; | ||
975 | |||
976 | mpeg2dec->yuv_buf[0][0] = | ||
977 | (uint8_t *) mpeg2_malloc(y_size, MPEG2_ALLOC_YUV); | ||
978 | #if MPEG2_COLOR | ||
979 | int uv_size = y_size >> (2 - mpeg2dec->decoder.chroma_format); | ||
980 | |||
981 | mpeg2dec->yuv_buf[0][1] = | ||
982 | (uint8_t *) mpeg2_malloc(uv_size, MPEG2_ALLOC_YUV); | ||
983 | mpeg2dec->yuv_buf[0][2] = | ||
984 | (uint8_t *) mpeg2_malloc(uv_size, MPEG2_ALLOC_YUV); | ||
985 | #endif | ||
986 | |||
987 | mpeg2dec->yuv_buf[1][0] = | ||
988 | (uint8_t *) mpeg2_malloc(y_size, MPEG2_ALLOC_YUV); | ||
989 | #if MPEG2_COLOR | ||
990 | mpeg2dec->yuv_buf[1][1] = | ||
991 | (uint8_t *) mpeg2_malloc(uv_size, MPEG2_ALLOC_YUV); | ||
992 | mpeg2dec->yuv_buf[1][2] = | ||
993 | (uint8_t *) mpeg2_malloc(uv_size, MPEG2_ALLOC_YUV); | ||
994 | #endif | ||
995 | y_size = decoder->stride_frame * 32; | ||
996 | |||
997 | mpeg2dec->yuv_buf[2][0] = | ||
998 | (uint8_t *) mpeg2_malloc(y_size, MPEG2_ALLOC_YUV); | ||
999 | #if MPEG2_COLOR | ||
1000 | uv_size = y_size >> (2 - mpeg2dec->decoder.chroma_format); | ||
1001 | |||
1002 | mpeg2dec->yuv_buf[2][1] = | ||
1003 | (uint8_t *) mpeg2_malloc(uv_size, MPEG2_ALLOC_YUV); | ||
1004 | mpeg2dec->yuv_buf[2][2] = | ||
1005 | (uint8_t *) mpeg2_malloc(uv_size, MPEG2_ALLOC_YUV); | ||
1006 | #endif | ||
1007 | } | ||
1008 | |||
1009 | if (!mpeg2dec->custom_fbuf) | ||
1010 | { | ||
1011 | while (mpeg2dec->alloc_index < 3) | ||
1012 | { | ||
1013 | mpeg2_fbuf_t * fbuf; | ||
1014 | |||
1015 | fbuf = &mpeg2dec->fbuf_alloc[mpeg2dec->alloc_index++].fbuf; | ||
1016 | fbuf->id = NULL; | ||
1017 | |||
1018 | fbuf->buf[0] = | ||
1019 | (uint8_t *) mpeg2_malloc (convert_init.buf_size[0], | ||
1020 | MPEG2_ALLOC_CONVERTED); | ||
1021 | #if MPEG2_COLOR | ||
1022 | fbuf->buf[1] = | ||
1023 | (uint8_t *) mpeg2_malloc (convert_init.buf_size[1], | ||
1024 | MPEG2_ALLOC_CONVERTED); | ||
1025 | fbuf->buf[2] = | ||
1026 | (uint8_t *) mpeg2_malloc (convert_init.buf_size[2], | ||
1027 | MPEG2_ALLOC_CONVERTED); | ||
1028 | #endif | ||
1029 | } | ||
1030 | |||
1031 | mpeg2_set_fbuf (mpeg2dec, (decoder->coding_type == B_TYPE)); | ||
1032 | } | ||
1033 | } | ||
1034 | else if (!mpeg2dec->custom_fbuf) | ||
1035 | { | ||
1036 | while (mpeg2dec->alloc_index < 3) | ||
1037 | { | ||
1038 | mpeg2_fbuf_t * fbuf; | ||
1039 | |||
1040 | fbuf = &mpeg2dec->fbuf_alloc[mpeg2dec->alloc_index++].fbuf; | ||
1041 | |||
1042 | fbuf->id = NULL; | ||
1043 | |||
1044 | int y_size = decoder->stride_frame * mpeg2dec->sequence.height; | ||
1045 | |||
1046 | fbuf->buf[0] = (uint8_t *) mpeg2_malloc (y_size, | ||
1047 | MPEG2_ALLOC_YUV); | ||
1048 | #if MPEG2_COLOR | ||
1049 | int uv_size = y_size >> (2 - decoder->chroma_format); | ||
1050 | |||
1051 | fbuf->buf[1] = (uint8_t *) mpeg2_malloc (uv_size, | ||
1052 | MPEG2_ALLOC_YUV); | ||
1053 | fbuf->buf[2] = (uint8_t *) mpeg2_malloc (uv_size, | ||
1054 | MPEG2_ALLOC_YUV); | ||
1055 | #endif | ||
1056 | } | ||
1057 | |||
1058 | mpeg2_set_fbuf (mpeg2dec, (decoder->coding_type == B_TYPE)); | ||
1059 | } | ||
1060 | } | ||
1061 | else | ||
1062 | { | ||
1063 | decoder->second_field = 1; | ||
1064 | mpeg2dec->picture++; /* second field picture */ | ||
1065 | |||
1066 | *(mpeg2dec->picture) = mpeg2dec->new_picture; | ||
1067 | |||
1068 | mpeg2dec->info.current_picture_2nd = mpeg2dec->picture; | ||
1069 | |||
1070 | if (low_delay || decoder->coding_type == B_TYPE) | ||
1071 | mpeg2dec->info.display_picture_2nd = mpeg2dec->picture; | ||
1072 | } | ||
1073 | |||
1074 | info_user_data (mpeg2dec); | ||
1075 | } | ||
1076 | |||
1077 | static int copyright_ext (mpeg2dec_t * mpeg2dec) | ||
1078 | { | ||
1079 | (void)mpeg2dec; | ||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | static int quant_matrix_ext (mpeg2dec_t * mpeg2dec) | ||
1084 | { | ||
1085 | uint8_t * buffer = mpeg2dec->chunk_start; | ||
1086 | int i, j; | ||
1087 | |||
1088 | for (i = 0; i < 4; i++) | ||
1089 | { | ||
1090 | if (buffer[0] & (8 >> i)) | ||
1091 | { | ||
1092 | for (j = 0; j < 64; j++) | ||
1093 | { | ||
1094 | mpeg2dec->new_quantizer_matrix[i][mpeg2_scan_norm[j]] = | ||
1095 | (buffer[j] << (i+5)) | (buffer[j+1] >> (3-i)); | ||
1096 | } | ||
1097 | |||
1098 | mpeg2dec->copy_matrix |= 1 << i; | ||
1099 | buffer += 64; | ||
1100 | } | ||
1101 | } | ||
1102 | |||
1103 | return 0; | ||
1104 | } | ||
1105 | |||
1106 | int mpeg2_header_extension (mpeg2dec_t * mpeg2dec) | ||
1107 | { | ||
1108 | static int (* const parser[9]) (mpeg2dec_t *) = | ||
1109 | { | ||
1110 | NULL, | ||
1111 | sequence_ext, | ||
1112 | sequence_display_ext, | ||
1113 | quant_matrix_ext, | ||
1114 | copyright_ext, | ||
1115 | NULL, | ||
1116 | NULL, | ||
1117 | picture_display_ext, | ||
1118 | picture_coding_ext | ||
1119 | }; | ||
1120 | |||
1121 | int ext, ext_bit; | ||
1122 | |||
1123 | ext = mpeg2dec->chunk_start[0] >> 4; | ||
1124 | ext_bit = 1 << ext; | ||
1125 | |||
1126 | if (!(mpeg2dec->ext_state & ext_bit)) | ||
1127 | return 0; /* ignore illegal extensions */ | ||
1128 | |||
1129 | mpeg2dec->ext_state &= ~ext_bit; | ||
1130 | |||
1131 | return parser[ext] (mpeg2dec); | ||
1132 | } | ||
1133 | |||
1134 | int mpeg2_header_user_data (mpeg2dec_t * mpeg2dec) | ||
1135 | { | ||
1136 | mpeg2dec->user_data_len += mpeg2dec->chunk_ptr - 1 - mpeg2dec->chunk_start; | ||
1137 | mpeg2dec->chunk_start = mpeg2dec->chunk_ptr - 1; | ||
1138 | |||
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | static void prescale (mpeg2dec_t * mpeg2dec, int index) | ||
1143 | { | ||
1144 | static const int non_linear_scale[32] = | ||
1145 | { | ||
1146 | 0, 1, 2, 3, 4, 5, 6, 7, | ||
1147 | 8, 10, 12, 14, 16, 18, 20, 22, | ||
1148 | 24, 28, 32, 36, 40, 44, 48, 52, | ||
1149 | 56, 64, 72, 80, 88, 96, 104, 112 | ||
1150 | }; | ||
1151 | |||
1152 | int i, j, k; | ||
1153 | mpeg2_decoder_t * decoder = &mpeg2dec->decoder; | ||
1154 | |||
1155 | if (mpeg2dec->scaled[index] != mpeg2dec->q_scale_type) | ||
1156 | { | ||
1157 | mpeg2dec->scaled[index] = mpeg2dec->q_scale_type; | ||
1158 | |||
1159 | for (i = 0; i < 32; i++) | ||
1160 | { | ||
1161 | k = mpeg2dec->q_scale_type ? non_linear_scale[i] : (i << 1); | ||
1162 | |||
1163 | for (j = 0; j < 64; j++) | ||
1164 | { | ||
1165 | decoder->quantizer_prescale[index][i][j] = | ||
1166 | k * mpeg2dec->quantizer_matrix[index][j]; | ||
1167 | } | ||
1168 | } | ||
1169 | } | ||
1170 | } | ||
1171 | |||
1172 | mpeg2_state_t mpeg2_header_slice_start (mpeg2dec_t * mpeg2dec) | ||
1173 | { | ||
1174 | mpeg2_decoder_t * decoder = &mpeg2dec->decoder; | ||
1175 | |||
1176 | mpeg2dec->info.user_data = NULL; | ||
1177 | mpeg2dec->info.user_data_len = 0; | ||
1178 | mpeg2dec->state = (mpeg2dec->picture->nb_fields > 1 || | ||
1179 | mpeg2dec->state == STATE_PICTURE_2ND) ? | ||
1180 | STATE_SLICE : STATE_SLICE_1ST; | ||
1181 | |||
1182 | if (mpeg2dec->decoder.coding_type != D_TYPE) | ||
1183 | { | ||
1184 | prescale (mpeg2dec, 0); | ||
1185 | |||
1186 | if (decoder->chroma_quantizer[0] == decoder->quantizer_prescale[2]) | ||
1187 | prescale (mpeg2dec, 2); | ||
1188 | |||
1189 | if (mpeg2dec->decoder.coding_type != I_TYPE) | ||
1190 | { | ||
1191 | prescale (mpeg2dec, 1); | ||
1192 | |||
1193 | if (decoder->chroma_quantizer[1] == decoder->quantizer_prescale[3]) | ||
1194 | prescale (mpeg2dec, 3); | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | if (!(mpeg2dec->nb_decode_slices)) | ||
1199 | { | ||
1200 | mpeg2dec->picture->flags |= PIC_FLAG_SKIP; | ||
1201 | } | ||
1202 | else if (mpeg2dec->convert_start) | ||
1203 | { | ||
1204 | mpeg2dec->convert_start (decoder->convert_id, mpeg2dec->fbuf[0], | ||
1205 | mpeg2dec->picture, mpeg2dec->info.gop); | ||
1206 | |||
1207 | if (mpeg2dec->decoder.coding_type == B_TYPE) | ||
1208 | { | ||
1209 | mpeg2_init_fbuf (&mpeg2dec->decoder, mpeg2dec->yuv_buf[2], | ||
1210 | mpeg2dec->yuv_buf[mpeg2dec->yuv_index ^ 1], | ||
1211 | mpeg2dec->yuv_buf[mpeg2dec->yuv_index]); | ||
1212 | } | ||
1213 | else | ||
1214 | { | ||
1215 | mpeg2_init_fbuf (&mpeg2dec->decoder, | ||
1216 | mpeg2dec->yuv_buf[mpeg2dec->yuv_index ^ 1], | ||
1217 | mpeg2dec->yuv_buf[mpeg2dec->yuv_index], | ||
1218 | mpeg2dec->yuv_buf[mpeg2dec->yuv_index]); | ||
1219 | |||
1220 | if (mpeg2dec->state == STATE_SLICE) | ||
1221 | mpeg2dec->yuv_index ^= 1; | ||
1222 | } | ||
1223 | } | ||
1224 | else | ||
1225 | { | ||
1226 | int b_type; | ||
1227 | |||
1228 | b_type = (mpeg2dec->decoder.coding_type == B_TYPE); | ||
1229 | |||
1230 | mpeg2_init_fbuf (&mpeg2dec->decoder, mpeg2dec->fbuf[0]->buf, | ||
1231 | mpeg2dec->fbuf[b_type + 1]->buf, | ||
1232 | mpeg2dec->fbuf[b_type]->buf); | ||
1233 | } | ||
1234 | |||
1235 | mpeg2dec->action = NULL; | ||
1236 | |||
1237 | return STATE_INTERNAL_NORETURN; | ||
1238 | } | ||
1239 | |||
1240 | static mpeg2_state_t seek_sequence (mpeg2dec_t * mpeg2dec) | ||
1241 | { | ||
1242 | mpeg2_reset_info (&mpeg2dec->info); | ||
1243 | |||
1244 | mpeg2dec->info.sequence = NULL; | ||
1245 | mpeg2dec->info.gop = NULL; | ||
1246 | |||
1247 | mpeg2_header_state_init (mpeg2dec); | ||
1248 | |||
1249 | mpeg2dec->action = mpeg2_seek_header; | ||
1250 | |||
1251 | return mpeg2_seek_header (mpeg2dec); | ||
1252 | } | ||
1253 | |||
1254 | mpeg2_state_t mpeg2_header_end (mpeg2dec_t * mpeg2dec) | ||
1255 | { | ||
1256 | mpeg2_picture_t * picture; | ||
1257 | int b_type; | ||
1258 | |||
1259 | b_type = (mpeg2dec->decoder.coding_type == B_TYPE); | ||
1260 | picture = mpeg2dec->pictures; | ||
1261 | |||
1262 | if ((mpeg2dec->picture >= picture + 2) ^ b_type) | ||
1263 | picture = mpeg2dec->pictures + 2; | ||
1264 | |||
1265 | mpeg2_reset_info (&mpeg2dec->info); | ||
1266 | |||
1267 | if (!(mpeg2dec->sequence.flags & SEQ_FLAG_LOW_DELAY)) | ||
1268 | { | ||
1269 | mpeg2dec->info.display_picture = picture; | ||
1270 | |||
1271 | if (picture->nb_fields == 1) | ||
1272 | mpeg2dec->info.display_picture_2nd = picture + 1; | ||
1273 | |||
1274 | mpeg2dec->info.display_fbuf = mpeg2dec->fbuf[b_type]; | ||
1275 | |||
1276 | if (!mpeg2dec->convert) | ||
1277 | mpeg2dec->info.discard_fbuf = mpeg2dec->fbuf[b_type + 1]; | ||
1278 | } | ||
1279 | else if (!mpeg2dec->convert) | ||
1280 | { | ||
1281 | mpeg2dec->info.discard_fbuf = mpeg2dec->fbuf[b_type]; | ||
1282 | } | ||
1283 | |||
1284 | mpeg2dec->action = seek_sequence; | ||
1285 | |||
1286 | return STATE_END; | ||
1287 | } | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/idct.c b/apps/plugins/mpegplayer/libmpeg2/idct.c deleted file mode 100644 index 7f0b9a3c12..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/idct.c +++ /dev/null | |||
@@ -1,274 +0,0 @@ | |||
1 | /* | ||
2 | * idct.c | ||
3 | * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> | ||
4 | * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> | ||
5 | * | ||
6 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
7 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
8 | * | ||
9 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * mpeg2dec is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | * $Id$ | ||
24 | * libmpeg2 sync history: | ||
25 | * 2008-07-01 - CVS revision 1.36 | ||
26 | */ | ||
27 | |||
28 | #include "plugin.h" | ||
29 | |||
30 | #include "mpeg2dec_config.h" | ||
31 | |||
32 | #include "mpeg2.h" | ||
33 | #include "attributes.h" | ||
34 | #include "mpeg2_internal.h" | ||
35 | |||
36 | #if defined(CPU_COLDFIRE) || defined (CPU_ARM) | ||
37 | #define IDCT_ASM | ||
38 | #endif | ||
39 | |||
40 | #ifndef IDCT_ASM | ||
41 | |||
42 | #define W1 2841 /* 2048 * sqrt (2) * cos (1 * pi / 16) */ | ||
43 | #define W2 2676 /* 2048 * sqrt (2) * cos (2 * pi / 16) */ | ||
44 | #define W3 2408 /* 2048 * sqrt (2) * cos (3 * pi / 16) */ | ||
45 | #define W5 1609 /* 2048 * sqrt (2) * cos (5 * pi / 16) */ | ||
46 | #define W6 1108 /* 2048 * sqrt (2) * cos (6 * pi / 16) */ | ||
47 | #define W7 565 /* 2048 * sqrt (2) * cos (7 * pi / 16) */ | ||
48 | |||
49 | /* | ||
50 | * In legal streams, the IDCT output should be between -384 and +384. | ||
51 | * In corrupted streams, it is possible to force the IDCT output to go | ||
52 | * to +-3826 - this is the worst case for a column IDCT where the | ||
53 | * column inputs are 16-bit values. | ||
54 | */ | ||
55 | #define CLIP(i) \ | ||
56 | ({ typeof (i) _i = (i); \ | ||
57 | if ((_i & 0xff) != _i) \ | ||
58 | _i = ~(_i >> (8*sizeof(_i) - 1)); \ | ||
59 | _i; }) | ||
60 | |||
61 | #if 0 | ||
62 | #define BUTTERFLY(t0,t1,W0,W1,d0,d1) \ | ||
63 | do { \ | ||
64 | t0 = W0 * d0 + W1 * d1; \ | ||
65 | t1 = W0 * d1 - W1 * d0; \ | ||
66 | } while (0) | ||
67 | #else | ||
68 | #define BUTTERFLY(t0,t1,W0,W1,d0,d1) \ | ||
69 | do { \ | ||
70 | int tmp = W0 * (d0 + d1); \ | ||
71 | t0 = tmp + (W1 - W0) * d1; \ | ||
72 | t1 = tmp - (W1 + W0) * d0; \ | ||
73 | } while (0) | ||
74 | #endif | ||
75 | |||
76 | static inline void idct_row (int16_t * const block) | ||
77 | { | ||
78 | int d0, d1, d2, d3; | ||
79 | int a0, a1, a2, a3, b0, b1, b2, b3; | ||
80 | int t0, t1, t2, t3; | ||
81 | |||
82 | /* shortcut */ | ||
83 | if (likely (!(block[1] | ((int32_t *)block)[1] | ((int32_t *)block)[2] | | ||
84 | ((int32_t *)block)[3]))) | ||
85 | { | ||
86 | uint32_t tmp = (uint16_t) (block[0] >> 1); | ||
87 | tmp |= tmp << 16; | ||
88 | ((int32_t *)block)[0] = tmp; | ||
89 | ((int32_t *)block)[1] = tmp; | ||
90 | ((int32_t *)block)[2] = tmp; | ||
91 | ((int32_t *)block)[3] = tmp; | ||
92 | return; | ||
93 | } | ||
94 | |||
95 | d0 = (block[0] << 11) + 2048; | ||
96 | d1 = block[1]; | ||
97 | d2 = block[2] << 11; | ||
98 | d3 = block[3]; | ||
99 | t0 = d0 + d2; | ||
100 | t1 = d0 - d2; | ||
101 | BUTTERFLY (t2, t3, W6, W2, d3, d1); | ||
102 | a0 = t0 + t2; | ||
103 | a1 = t1 + t3; | ||
104 | a2 = t1 - t3; | ||
105 | a3 = t0 - t2; | ||
106 | |||
107 | d0 = block[4]; | ||
108 | d1 = block[5]; | ||
109 | d2 = block[6]; | ||
110 | d3 = block[7]; | ||
111 | BUTTERFLY (t0, t1, W7, W1, d3, d0); | ||
112 | BUTTERFLY (t2, t3, W3, W5, d1, d2); | ||
113 | b0 = t0 + t2; | ||
114 | b3 = t1 + t3; | ||
115 | t0 -= t2; | ||
116 | t1 -= t3; | ||
117 | b1 = ((t0 + t1) >> 8) * 181; | ||
118 | b2 = ((t0 - t1) >> 8) * 181; | ||
119 | |||
120 | block[0] = (a0 + b0) >> 12; | ||
121 | block[1] = (a1 + b1) >> 12; | ||
122 | block[2] = (a2 + b2) >> 12; | ||
123 | block[3] = (a3 + b3) >> 12; | ||
124 | block[4] = (a3 - b3) >> 12; | ||
125 | block[5] = (a2 - b2) >> 12; | ||
126 | block[6] = (a1 - b1) >> 12; | ||
127 | block[7] = (a0 - b0) >> 12; | ||
128 | } | ||
129 | |||
130 | static inline void idct_col (int16_t * const block) | ||
131 | { | ||
132 | int d0, d1, d2, d3; | ||
133 | int a0, a1, a2, a3, b0, b1, b2, b3; | ||
134 | int t0, t1, t2, t3; | ||
135 | |||
136 | d0 = (block[8*0] << 11) + 65536; | ||
137 | d1 = block[8*1]; | ||
138 | d2 = block[8*2] << 11; | ||
139 | d3 = block[8*3]; | ||
140 | t0 = d0 + d2; | ||
141 | t1 = d0 - d2; | ||
142 | BUTTERFLY (t2, t3, W6, W2, d3, d1); | ||
143 | a0 = t0 + t2; | ||
144 | a1 = t1 + t3; | ||
145 | a2 = t1 - t3; | ||
146 | a3 = t0 - t2; | ||
147 | |||
148 | d0 = block[8*4]; | ||
149 | d1 = block[8*5]; | ||
150 | d2 = block[8*6]; | ||
151 | d3 = block[8*7]; | ||
152 | BUTTERFLY (t0, t1, W7, W1, d3, d0); | ||
153 | BUTTERFLY (t2, t3, W3, W5, d1, d2); | ||
154 | b0 = t0 + t2; | ||
155 | b3 = t1 + t3; | ||
156 | t0 -= t2; | ||
157 | t1 -= t3; | ||
158 | b1 = ((t0 + t1) >> 8) * 181; | ||
159 | b2 = ((t0 - t1) >> 8) * 181; | ||
160 | |||
161 | block[8*0] = (a0 + b0) >> 17; | ||
162 | block[8*1] = (a1 + b1) >> 17; | ||
163 | block[8*2] = (a2 + b2) >> 17; | ||
164 | block[8*3] = (a3 + b3) >> 17; | ||
165 | block[8*4] = (a3 - b3) >> 17; | ||
166 | block[8*5] = (a2 - b2) >> 17; | ||
167 | block[8*6] = (a1 - b1) >> 17; | ||
168 | block[8*7] = (a0 - b0) >> 17; | ||
169 | } | ||
170 | |||
171 | void mpeg2_idct_copy (int16_t * block, uint8_t * dest, | ||
172 | const int stride) | ||
173 | { | ||
174 | int i; | ||
175 | |||
176 | for (i = 0; i < 8; i++) | ||
177 | idct_row (block + 8 * i); | ||
178 | |||
179 | for (i = 0; i < 8; i++) | ||
180 | idct_col (block + i); | ||
181 | |||
182 | do | ||
183 | { | ||
184 | dest[0] = CLIP (block[0]); | ||
185 | dest[1] = CLIP (block[1]); | ||
186 | dest[2] = CLIP (block[2]); | ||
187 | dest[3] = CLIP (block[3]); | ||
188 | dest[4] = CLIP (block[4]); | ||
189 | dest[5] = CLIP (block[5]); | ||
190 | dest[6] = CLIP (block[6]); | ||
191 | dest[7] = CLIP (block[7]); | ||
192 | |||
193 | ((int32_t *)block)[0] = 0; | ||
194 | ((int32_t *)block)[1] = 0; | ||
195 | ((int32_t *)block)[2] = 0; | ||
196 | ((int32_t *)block)[3] = 0; | ||
197 | |||
198 | dest += stride; | ||
199 | block += 8; | ||
200 | } | ||
201 | while (--i); | ||
202 | } | ||
203 | |||
204 | void mpeg2_idct_add (const int last, int16_t * block, | ||
205 | uint8_t * dest, const int stride) | ||
206 | { | ||
207 | int i; | ||
208 | |||
209 | if (last != 129 || (block[0] & (7 << 4)) == (4 << 4)) | ||
210 | { | ||
211 | for (i = 0; i < 8; i++) | ||
212 | idct_row (block + 8 * i); | ||
213 | |||
214 | for (i = 0; i < 8; i++) | ||
215 | idct_col (block + i); | ||
216 | |||
217 | do | ||
218 | { | ||
219 | dest[0] = CLIP (block[0] + dest[0]); | ||
220 | dest[1] = CLIP (block[1] + dest[1]); | ||
221 | dest[2] = CLIP (block[2] + dest[2]); | ||
222 | dest[3] = CLIP (block[3] + dest[3]); | ||
223 | dest[4] = CLIP (block[4] + dest[4]); | ||
224 | dest[5] = CLIP (block[5] + dest[5]); | ||
225 | dest[6] = CLIP (block[6] + dest[6]); | ||
226 | dest[7] = CLIP (block[7] + dest[7]); | ||
227 | |||
228 | ((int32_t *)block)[0] = 0; | ||
229 | ((int32_t *)block)[1] = 0; | ||
230 | ((int32_t *)block)[2] = 0; | ||
231 | ((int32_t *)block)[3] = 0; | ||
232 | |||
233 | dest += stride; | ||
234 | block += 8; | ||
235 | } | ||
236 | while (--i); | ||
237 | } | ||
238 | else | ||
239 | { | ||
240 | int DC = (block[0] + 64) >> 7; | ||
241 | block[0] = block[63] = 0; | ||
242 | i = 8; | ||
243 | |||
244 | do | ||
245 | { | ||
246 | dest[0] = CLIP (DC + dest[0]); | ||
247 | dest[1] = CLIP (DC + dest[1]); | ||
248 | dest[2] = CLIP (DC + dest[2]); | ||
249 | dest[3] = CLIP (DC + dest[3]); | ||
250 | dest[4] = CLIP (DC + dest[4]); | ||
251 | dest[5] = CLIP (DC + dest[5]); | ||
252 | dest[6] = CLIP (DC + dest[6]); | ||
253 | dest[7] = CLIP (DC + dest[7]); | ||
254 | dest += stride; | ||
255 | } | ||
256 | while (--i); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | #endif /* IDCT_ASM */ | ||
261 | |||
262 | void mpeg2_idct_init (void) | ||
263 | { | ||
264 | int i, j; | ||
265 | |||
266 | for (i = 0; i < 64; i++) | ||
267 | { | ||
268 | j = default_mpeg2_scan_norm[i]; | ||
269 | mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); | ||
270 | |||
271 | j = default_mpeg2_scan_alt[i]; | ||
272 | mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); | ||
273 | } | ||
274 | } | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/idct_arm.S b/apps/plugins/mpegplayer/libmpeg2/idct_arm.S deleted file mode 100644 index 97a87a8b59..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/idct_arm.S +++ /dev/null | |||
@@ -1,443 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Michael Sevakis | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "config.h" | ||
23 | |||
24 | .global mpeg2_idct_copy | ||
25 | .type mpeg2_idct_copy, %function | ||
26 | .global mpeg2_idct_add | ||
27 | .type mpeg2_idct_add, %function | ||
28 | |||
29 | |||
30 | /* Custom calling convention: | ||
31 | * r0 contains block pointer and is non-volatile | ||
32 | * all non-volatile c context saved and restored on its behalf | ||
33 | */ | ||
34 | .idct: | ||
35 | add r12, r0, #128 | ||
36 | 1: | ||
37 | ldrsh r1, [r0, #0] /* d0 */ | ||
38 | ldrsh r2, [r0, #2] /* d1 */ | ||
39 | ldrsh r3, [r0, #4] /* d2 */ | ||
40 | ldrsh r4, [r0, #6] /* d3 */ | ||
41 | ldrsh r5, [r0, #8] /* d0 */ | ||
42 | ldrsh r6, [r0, #10] /* d1 */ | ||
43 | ldrsh r7, [r0, #12] /* d2 */ | ||
44 | ldrsh r8, [r0, #14] /* d3 */ | ||
45 | orrs r9, r2, r3 | ||
46 | orreqs r9, r4, r5 | ||
47 | orreqs r9, r6, r7 | ||
48 | cmpeq r8, #0 | ||
49 | bne 2f | ||
50 | mov r1, r1, asl #15 | ||
51 | bic r1, r1, #0x8000 | ||
52 | orr r1, r1, r1, lsr #16 | ||
53 | str r1, [r0], #4 | ||
54 | str r1, [r0], #4 | ||
55 | str r1, [r0], #4 | ||
56 | str r1, [r0], #4 | ||
57 | cmp r0, r12 | ||
58 | blo 1b | ||
59 | b 3f | ||
60 | 2: | ||
61 | mov r1, r1, asl #11 /* r1 = d0 = (block[0] << 11) + 2048 */ | ||
62 | add r1, r1, #2048 | ||
63 | add r1, r1, r3, asl #11 /* r1 = t0 = d0 + (block[2] << 11) */ | ||
64 | sub r3, r1, r3, asl #12 /* r3 = t1 = d0 - (block[2] << 11) */ | ||
65 | |||
66 | add r9, r2, r4 /* r9 = tmp = (d1+d3)*(1108/4) */ | ||
67 | add r10, r9, r9, asl #2 | ||
68 | add r10, r10, r9, asl #4 | ||
69 | add r9, r10, r9, asl #8 | ||
70 | |||
71 | add r10, r2, r2, asl #4 /* r2 = t2 = tmp + (d1*(1568/32)*8) */ | ||
72 | add r2, r10, r2, asl #5 | ||
73 | add r2, r9, r2, asl #3 | ||
74 | |||
75 | add r10, r4, r4, asl #2 /* r4 = t3 = tmp - (d3*(3784/8)*2) */ | ||
76 | rsb r10, r10, r4, asl #6 | ||
77 | add r4, r4, r10, asl #3 | ||
78 | sub r4, r9, r4, asl #1 | ||
79 | /* t2 & t3 are 1/4 final value here */ | ||
80 | add r1, r1, r2, asl #2 /* r1 = a0 = t0 + t2 */ | ||
81 | sub r2, r1, r2, asl #3 /* r2 = a3 = t0 - t2 */ | ||
82 | add r3, r3, r4, asl #2 /* r3 = a1 = t1 + t3 */ | ||
83 | sub r4, r3, r4, asl #3 /* r4 = a2 = t1 - t3 */ | ||
84 | |||
85 | add r9, r8, r5 /* r9 = tmp = 565*(d3 + d0) */ | ||
86 | add r10, r9, r9, asl #4 | ||
87 | add r10, r10, r10, asl #5 | ||
88 | add r9, r10, r9, asl #2 | ||
89 | |||
90 | add r10, r5, r5, asl #4 /* r5 = t0 = tmp + (((2276/4)*d0)*4) */ | ||
91 | add r10, r10, r10, asl #5 | ||
92 | add r5, r10, r5, asl #3 | ||
93 | add r5, r9, r5, asl #2 | ||
94 | |||
95 | add r10, r8, r8, asl #2 /* r8 = t1 = tmp - (((3406/2)*d3)*2) */ | ||
96 | add r10, r10, r10, asl #4 | ||
97 | add r10, r10, r8, asl #7 | ||
98 | rsb r8, r8, r10, asl #3 | ||
99 | sub r8, r9, r8, asl #1 | ||
100 | |||
101 | add r9, r6, r7 /* r9 = tmp = (2408/8)*(d1 + d2) */ | ||
102 | add r10, r9, r9, asl #3 | ||
103 | add r10, r10, r10, asl #5 | ||
104 | add r9, r10, r9, asl #2 | ||
105 | |||
106 | add r10, r7, r7, asl #3 /* r7 = t2 = (tmp*8) - 799*d2 */ | ||
107 | add r10, r10, r7, asl #4 | ||
108 | rsb r7, r7, r10, asl #5 | ||
109 | rsb r7, r7, r9, asl #3 | ||
110 | |||
111 | sub r10, r6, r6, asl #4 /* r6 = t3 = (tmp*8) - 4017*d1 */ | ||
112 | sub r10, r10, r6, asl #6 | ||
113 | add r10, r10, r6, asl #12 | ||
114 | add r6, r10, r6 | ||
115 | rsb r6, r6, r9, asl #3 | ||
116 | /* t0 = r5, t1 = r8, t2 = r7, t3 = r6*/ | ||
117 | add r9, r5, r7 /* r9 = b0 = t0 + t2 */ | ||
118 | add r10, r8, r6 /* r10 = b3 = t1 + t3 */ | ||
119 | sub r5, r5, r7 /* t0 -= t2 */ | ||
120 | sub r8, r8, r6 /* t1 -= t3 */ | ||
121 | add r6, r5, r8 /* r6 = t0 + t1 */ | ||
122 | sub r7, r5, r8 /* r7 = t0 - t1 */ | ||
123 | |||
124 | add r11, r6, r6, asr #2 /* r6 = b1 = r6*(181/128) */ | ||
125 | add r11, r11, r11, asr #5 | ||
126 | add r6, r11, r6, asr #3 | ||
127 | add r11, r7, r7, asr #2 /* r7 = b2 = r7*(181/128) */ | ||
128 | add r11, r11, r11, asr #5 | ||
129 | add r7, r11, r7, asr #3 | ||
130 | /* r1 = a0, r3 = a1, r4 = a2, r2 = a3 */ | ||
131 | /* r9 = b0, r6 = b1*2, r7 = b2*2, r10 = b3 */ | ||
132 | add r5, r1, r9 /* block[0] = (a0 + b0) >> 12 */ | ||
133 | mov r5, r5, asr #12 | ||
134 | strh r5, [r0], #2 | ||
135 | add r8, r3, r6, asr #1 /* block[1] = (a1 + b1) >> 12 */ | ||
136 | mov r8, r8, asr #12 | ||
137 | strh r8, [r0], #2 | ||
138 | add r5, r4, r7, asr #1 /* block[2] = (a2 + b2) >> 12 */ | ||
139 | mov r5, r5, asr #12 | ||
140 | strh r5, [r0], #2 | ||
141 | add r8, r2, r10 /* block[3] = (a3 + b3) >> 12 */ | ||
142 | mov r8, r8, asr #12 | ||
143 | strh r8, [r0], #2 | ||
144 | sub r5, r2, r10 /* block[4] = (a3 - b3) >> 12 */ | ||
145 | mov r5, r5, asr #12 | ||
146 | strh r5, [r0], #2 | ||
147 | sub r8, r4, r7, asr #1 /* block[5] = (a2 - b2) >> 12 */ | ||
148 | mov r8, r8, asr #12 | ||
149 | strh r8, [r0], #2 | ||
150 | sub r5, r3, r6, asr #1 /* block[6] = (a1 - b1) >> 12 */ | ||
151 | mov r5, r5, asr #12 | ||
152 | strh r5, [r0], #2 | ||
153 | sub r8, r1, r9 /* block[7] = (a0 - b0) >> 12 */ | ||
154 | mov r8, r8, asr #12 | ||
155 | strh r8, [r0], #2 | ||
156 | cmp r0, r12 | ||
157 | blo 1b | ||
158 | 3: | ||
159 | sub r0, r0, #128 | ||
160 | add r12, r0, #16 | ||
161 | 4: | ||
162 | ldrsh r1, [r0, #0*8] /* d0 */ | ||
163 | ldrsh r2, [r0, #2*8] /* d1 */ | ||
164 | ldrsh r3, [r0, #4*8] /* d2 */ | ||
165 | ldrsh r4, [r0, #6*8] /* d3 */ | ||
166 | ldrsh r5, [r0, #8*8] /* d0 */ | ||
167 | ldrsh r6, [r0, #10*8] /* d1 */ | ||
168 | ldrsh r7, [r0, #12*8] /* d2 */ | ||
169 | ldrsh r8, [r0, #14*8] /* d3 */ | ||
170 | |||
171 | mov r1, r1, asl #11 /* r1 = d0 = (block[0] << 11) + 2048 */ | ||
172 | add r1, r1, #65536 | ||
173 | add r1, r1, r3, asl #11 /* r1 = t0 = d0 + d2:(block[2] << 11) */ | ||
174 | sub r3, r1, r3, asl #12 /* r3 = t1 = d0 - d2:(block[2] << 11) */ | ||
175 | |||
176 | add r9, r2, r4 /* r9 = tmp = (d1+d3)*(1108/4) */ | ||
177 | add r10, r9, r9, asl #2 | ||
178 | add r10, r10, r9, asl #4 | ||
179 | add r9, r10, r9, asl #8 | ||
180 | |||
181 | add r11, r2, r2, asl #4 /* r2 = t2 = tmp + (d1*(1568/32)*8) */ | ||
182 | add r2, r11, r2, asl #5 | ||
183 | add r2, r9, r2, asl #3 | ||
184 | |||
185 | add r10, r4, r4, asl #2 /* r4 = t3 = tmp - (d3*(3784/8)*2) */ | ||
186 | rsb r10, r10, r4, asl #6 | ||
187 | add r4, r4, r10, asl #3 | ||
188 | sub r4, r9, r4, asl #1 | ||
189 | /* t2 & t3 are 1/4 final value here */ | ||
190 | add r1, r1, r2, asl #2 /* r1 = a0 = t0 + t2 */ | ||
191 | sub r2, r1, r2, asl #3 /* r2 = a3 = t0 - t2 */ | ||
192 | add r3, r3, r4, asl #2 /* r3 = a1 = t1 + t3 */ | ||
193 | sub r4, r3, r4, asl #3 /* r4 = a2 = t1 - t3 */ | ||
194 | |||
195 | add r9, r8, r5 /* r9 = tmp = 565*(d3 + d0) */ | ||
196 | add r10, r9, r9, asl #4 | ||
197 | add r10, r10, r10, asl #5 | ||
198 | add r9, r10, r9, asl #2 | ||
199 | |||
200 | add r10, r5, r5, asl #4 /* r5 = t0 = tmp + (((2276/4)*d0)*4) */ | ||
201 | add r10, r10, r10, asl #5 | ||
202 | add r5, r10, r5, asl #3 | ||
203 | add r5, r9, r5, asl #2 | ||
204 | |||
205 | add r10, r8, r8, asl #2 /* r8 = t1 = tmp - (((3406/2)*d3)*2) */ | ||
206 | add r10, r10, r10, asl #4 | ||
207 | add r10, r10, r8, asl #7 | ||
208 | rsb r8, r8, r10, asl #3 | ||
209 | sub r8, r9, r8, asl #1 | ||
210 | |||
211 | add r9, r6, r7 /* r9 = tmp = (2408/8)*(d1 + d2) */ | ||
212 | add r10, r9, r9, asl #3 | ||
213 | add r10, r10, r10, asl #5 | ||
214 | add r9, r10, r9, asl #2 | ||
215 | |||
216 | add r10, r7, r7, asl #3 /* r7 = t2 = (tmp*8) - 799*d2 */ | ||
217 | add r10, r10, r7, asl #4 | ||
218 | rsb r7, r7, r10, asl #5 | ||
219 | rsb r7, r7, r9, asl #3 | ||
220 | |||
221 | sub r10, r6, r6, asl #4 /* r6 = t3 = (tmp*8) - 4017*d1 */ | ||
222 | sub r10, r10, r6, asl #6 | ||
223 | add r10, r10, r6, asl #12 | ||
224 | add r6, r10, r6 | ||
225 | rsb r6, r6, r9, asl #3 | ||
226 | /* t0=r5, t1=r8, t2=r7, t3=r6*/ | ||
227 | add r9, r5, r7 /* r9 = b0 = t0 + t2 */ | ||
228 | add r10, r8, r6 /* r10 = b3 = t1 + t3 */ | ||
229 | sub r5, r5, r7 /* t0 -= t2 */ | ||
230 | sub r8, r8, r6 /* t1 -= t3 */ | ||
231 | add r6, r5, r8 /* r6 = t0 + t1 */ | ||
232 | sub r7, r5, r8 /* r7 = t0 - t1 */ | ||
233 | |||
234 | add r11, r6, r6, asr #2 /* r6 = b1 = r5*(181/128) */ | ||
235 | add r11, r11, r11, asr #5 | ||
236 | add r6, r11, r6, asr #3 | ||
237 | add r11, r7, r7, asr #2 /* r7 = b2 = r6*(181/128) */ | ||
238 | add r11, r11, r11, asr #5 | ||
239 | add r7, r11, r7, asr #3 | ||
240 | /* r1 = a0, r3 = a1, r4 = a2, r2 = a3 */ | ||
241 | /* r9 = b0, r6 = b1*2, r7 = b2*2, r10 = b3 */ | ||
242 | add r5, r1, r9 /* block[0] = (a0 + b0) >> 17 */ | ||
243 | mov r5, r5, asr #17 | ||
244 | strh r5, [r0, #0*8] | ||
245 | add r8, r3, r6, asr #1 /* block[1] = (a1 + b1) >> 17 */ | ||
246 | mov r8, r8, asr #17 | ||
247 | strh r8, [r0, #2*8] | ||
248 | add r5, r4, r7, asr #1 /* block[2] = (a2 + b2) >> 17 */ | ||
249 | mov r5, r5, asr #17 | ||
250 | strh r5, [r0, #4*8] | ||
251 | add r8, r2, r10 /* block[3] = (a3 + b3) >> 17 */ | ||
252 | mov r8, r8, asr #17 | ||
253 | strh r8, [r0, #6*8] | ||
254 | sub r5, r2, r10 /* block[4] = (a3 - b3) >> 17 */ | ||
255 | mov r5, r5, asr #17 | ||
256 | strh r5, [r0, #8*8] | ||
257 | sub r8, r4, r7, asr #1 /* block[5] = (a2 - b2) >> 17 */ | ||
258 | mov r8, r8, asr #17 | ||
259 | strh r8, [r0, #10*8] | ||
260 | sub r5, r3, r6, asr #1 /* block[6] = (a1 - b1) >> 17 */ | ||
261 | mov r5, r5, asr #17 | ||
262 | strh r5, [r0, #12*8] | ||
263 | sub r8, r1, r9 /* block[7] = (a0 - b0) >> 17 */ | ||
264 | mov r8, r8, asr #17 | ||
265 | strh r8, [r0, #14*8] | ||
266 | add r0, r0, #2 | ||
267 | cmp r0, r12 | ||
268 | blo 4b | ||
269 | sub r0, r0, #16 | ||
270 | bx lr | ||
271 | |||
272 | mpeg2_idct_copy: | ||
273 | stmfd sp!, { r1-r2, r4-r11, lr } | ||
274 | bl .idct | ||
275 | ldmfd sp!, { r1-r2 } | ||
276 | mov r11, #0 | ||
277 | add r12, r0, #128 | ||
278 | 1: | ||
279 | ldrsh r3, [r0, #0] | ||
280 | ldrsh r4, [r0, #2] | ||
281 | ldrsh r5, [r0, #4] | ||
282 | ldrsh r6, [r0, #6] | ||
283 | ldrsh r7, [r0, #8] | ||
284 | ldrsh r8, [r0, #10] | ||
285 | ldrsh r9, [r0, #12] | ||
286 | ldrsh r10, [r0, #14] | ||
287 | cmp r3, #255 | ||
288 | mvnhi r3, r3, asr #31 | ||
289 | strb r3, [r1, #0] | ||
290 | str r11, [r0], #4 | ||
291 | cmp r4, #255 | ||
292 | mvnhi r4, r4, asr #31 | ||
293 | strb r4, [r1, #1] | ||
294 | cmp r5, #255 | ||
295 | mvnhi r5, r5, asr #31 | ||
296 | strb r5, [r1, #2] | ||
297 | str r11, [r0], #4 | ||
298 | cmp r6, #255 | ||
299 | mvnhi r6, r6, asr #31 | ||
300 | strb r6, [r1, #3] | ||
301 | cmp r7, #255 | ||
302 | mvnhi r7, r7, asr #31 | ||
303 | strb r7, [r1, #4] | ||
304 | str r11, [r0], #4 | ||
305 | cmp r8, #255 | ||
306 | mvnhi r8, r8, asr #31 | ||
307 | strb r8, [r1, #5] | ||
308 | cmp r9, #255 | ||
309 | mvnhi r9, r9, asr #31 | ||
310 | strb r9, [r1, #6] | ||
311 | str r11, [r0], #4 | ||
312 | cmp r10, #255 | ||
313 | mvnhi r10, r10, asr #31 | ||
314 | strb r10, [r1, #7] | ||
315 | add r1, r1, r2 | ||
316 | cmp r0, r12 | ||
317 | blo 1b | ||
318 | ldmpc regs=r4-r11 | ||
319 | |||
320 | mpeg2_idct_add: | ||
321 | cmp r0, #129 | ||
322 | mov r0, r1 | ||
323 | ldreqsh r1, [r0, #0] | ||
324 | bne 1f | ||
325 | and r1, r1, #0x70 | ||
326 | cmp r1, #0x40 | ||
327 | bne 3f | ||
328 | 1: | ||
329 | stmfd sp!, { r2-r11, lr } | ||
330 | bl .idct | ||
331 | ldmfd sp!, { r1-r2 } | ||
332 | mov r11, #0 | ||
333 | add r12, r0, #128 | ||
334 | 2: | ||
335 | ldrb r3, [r1, #0] | ||
336 | ldrb r4, [r1, #1] | ||
337 | ldrb r5, [r1, #2] | ||
338 | ldrb r6, [r1, #3] | ||
339 | ldrsh r7, [r0, #0] | ||
340 | ldrsh r8, [r0, #2] | ||
341 | ldrsh r9, [r0, #4] | ||
342 | ldrsh r10, [r0, #6] | ||
343 | add r7, r7, r3 | ||
344 | ldrb r3, [r1, #4] | ||
345 | cmp r7, #255 | ||
346 | mvnhi r7, r7, asr #31 | ||
347 | strb r7, [r1, #0] | ||
348 | ldrsh r7, [r0, #8] | ||
349 | add r8, r8, r4 | ||
350 | ldrb r4, [r1, #5] | ||
351 | cmp r8, #255 | ||
352 | mvnhi r8, r8, asr #31 | ||
353 | strb r8, [r1, #1] | ||
354 | ldrsh r8, [r0, #10] | ||
355 | add r9, r9, r5 | ||
356 | ldrb r5, [r1, #6] | ||
357 | cmp r9, #255 | ||
358 | mvnhi r9, r9, asr #31 | ||
359 | strb r9, [r1, #2] | ||
360 | ldrsh r9, [r0, #12] | ||
361 | add r10, r10, r6 | ||
362 | ldrb r6, [r1, #7] | ||
363 | cmp r10, #255 | ||
364 | mvnhi r10, r10, asr #31 | ||
365 | strb r10, [r1, #3] | ||
366 | ldrsh r10, [r0, #14] | ||
367 | str r11, [r0], #4 | ||
368 | add r7, r7, r3 | ||
369 | cmp r7, #255 | ||
370 | mvnhi r7, r7, asr #31 | ||
371 | strb r7, [r1, #4] | ||
372 | str r11, [r0], #4 | ||
373 | add r8, r8, r4 | ||
374 | cmp r8, #255 | ||
375 | mvnhi r8, r8, asr #31 | ||
376 | strb r8, [r1, #5] | ||
377 | str r11, [r0], #4 | ||
378 | add r9, r9, r5 | ||
379 | cmp r9, #255 | ||
380 | mvnhi r9, r9, asr #31 | ||
381 | strb r9, [r1, #6] | ||
382 | add r10, r10, r6 | ||
383 | cmp r10, #255 | ||
384 | mvnhi r10, r10, asr #31 | ||
385 | strb r10, [r1, #7] | ||
386 | str r11, [r0], #4 | ||
387 | add r1, r1, r2 | ||
388 | cmp r0, r12 | ||
389 | blo 2b | ||
390 | ldmpc regs=r4-r11 | ||
391 | 3: | ||
392 | stmfd sp!, { r4-r5, lr } | ||
393 | ldrsh r1, [r0, #0] /* r1 = block[0] */ | ||
394 | mov r4, #0 | ||
395 | strh r4, [r0, #0] /* block[0] = 0 */ | ||
396 | strh r4, [r0, #126] /* block[63] = 0 */ | ||
397 | add r1, r1, #64 /* r1 = DC << 7 */ | ||
398 | add r0, r2, r3, asl #3 | ||
399 | 4: | ||
400 | ldrb r4, [r2, #0] | ||
401 | ldrb r5, [r2, #1] | ||
402 | ldrb r12, [r2, #2] | ||
403 | ldrb lr, [r2, #3] | ||
404 | add r4, r4, r1, asr #7 | ||
405 | cmp r4, #255 | ||
406 | mvnhi r4, r4, asr #31 | ||
407 | strb r4, [r2, #0] | ||
408 | add r5, r5, r1, asr #7 | ||
409 | cmp r5, #255 | ||
410 | mvnhi r5, r5, asr #31 | ||
411 | strb r5, [r2, #1] | ||
412 | add r12, r12, r1, asr #7 | ||
413 | cmp r12, #255 | ||
414 | mvnhi r12, r12, asr #31 | ||
415 | strb r12, [r2, #2] | ||
416 | add lr, lr, r1, asr #7 | ||
417 | cmp lr, #255 | ||
418 | mvnhi lr, lr, asr #31 | ||
419 | strb lr, [r2, #3] | ||
420 | ldrb r4, [r2, #4] | ||
421 | ldrb r5, [r2, #5] | ||
422 | ldrb r12, [r2, #6] | ||
423 | ldrb lr, [r2, #7] | ||
424 | add r4, r4, r1, asr #7 | ||
425 | cmp r4, #255 | ||
426 | mvnhi r4, r4, asr #31 | ||
427 | strb r4, [r2, #4] | ||
428 | add r5, r5, r1, asr #7 | ||
429 | cmp r5, #255 | ||
430 | mvnhi r5, r5, asr #31 | ||
431 | strb r5, [r2, #5] | ||
432 | add r12, r12, r1, asr #7 | ||
433 | cmp r12, #255 | ||
434 | mvnhi r12, r12, asr #31 | ||
435 | strb r12, [r2, #6] | ||
436 | add lr, lr, r1, asr #7 | ||
437 | cmp lr, #255 | ||
438 | mvnhi lr, lr, asr #31 | ||
439 | strb lr, [r2, #7] | ||
440 | add r2, r2, r3 | ||
441 | cmp r2, r0 | ||
442 | blo 4b | ||
443 | ldmpc regs=r4-r5 | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/idct_armv6.S b/apps/plugins/mpegplayer/libmpeg2/idct_armv6.S deleted file mode 100644 index dc53cbd7bd..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/idct_armv6.S +++ /dev/null | |||
@@ -1,297 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2009 by Jens Arnold | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | |||
23 | .global mpeg2_idct_copy | ||
24 | .type mpeg2_idct_copy, %function | ||
25 | .global mpeg2_idct_add | ||
26 | .type mpeg2_idct_add, %function | ||
27 | |||
28 | /* Custom calling convention: | ||
29 | * r0 contains block pointer and is non-volatile | ||
30 | * all non-volatile c context saved and restored on its behalf | ||
31 | */ | ||
32 | .idct: | ||
33 | str lr, [sp, #-4]! @ lr is used | ||
34 | add r1, r0, #128 @ secondary, transposed temp buffer | ||
35 | mov r14, #8 @ loop counter | ||
36 | |||
37 | .row_loop: | ||
38 | ldmia r0!, {r2, r3, r10, r11} @ fetch f0, f2, f4, f6, f1, f3, f5, f7 | ||
39 | ldrd r4, L_W1357 @ load W1, W3, W5, W7 | ||
40 | |||
41 | smuad r6, r4, r10 @ b0 = W1 * f1 + W3 * f3 | ||
42 | smultt r7, r5, r10 @ -b1 = W7 * f3 | ||
43 | smulbt r8, r4, r10 @ -b2 = W1 * f3 | ||
44 | |||
45 | smusdx r9, r10, r5 @ b3 = f1 * W7 - f3 * W5 | ||
46 | smlabb r7, r4, r11, r7 @ -b1 += W1 * f5 | ||
47 | rsb r8, r8, #0 @ b2 = -b2 | ||
48 | smlabb r8, r5, r10, r8 @ b2 += W5 * f1 | ||
49 | |||
50 | smlad r6, r5, r11, r6 @ b0 += W5 * f5 + W7 * f7 | ||
51 | smlabt r7, r5, r11, r7 @ -b1 += W5 * f7 | ||
52 | smlatb r8, r5, r11, r8 @ b2 += W7 * f5 | ||
53 | |||
54 | smlsdx r9, r11, r4, r9 @ b3 += f5 * W3 - f7 * W1 | ||
55 | rsb r7, r7, #0 @ b1 = -b1 | ||
56 | smlatb r7, r4, r10, r7 @ b1 += W3 * f1 | ||
57 | smlatt r8, r4, r11, r8 @ b2 += W3 * f7 | ||
58 | |||
59 | ldrd r4, L_W0246 @ load W0, W2, W4, W6 | ||
60 | add r2, r2, #1 @ f0 += 1 | ||
61 | |||
62 | smulbb r10, r5, r3 @ a0' = W4 * f4 | ||
63 | smultt r12, r5, r3 @ a3' = W6 * f6 | ||
64 | smultt r3, r4, r3 @ -a2' = W2 * f6 | ||
65 | |||
66 | rsb r11, r10, #0 @ a1' = -W4 * f4 | ||
67 | smlabb r10, r4, r2, r10 @ a0' += W0 * f0 | ||
68 | smlabb r11, r4, r2, r11 @ a1' += W0 * f0 | ||
69 | smlatt r12, r4, r2, r12 @ a3' += W2 * f2 | ||
70 | rsb r3, r3, #0 @ a2' = -a2' | ||
71 | smlatt r3, r5, r2, r3 @ a2' += W6 * f2 | ||
72 | |||
73 | add r10, r10, r12 @ a0 = a0' + a3' | ||
74 | sub r12, r10, r12, lsl #1 @ a3 = a0 - 2 * a3' | ||
75 | add r11, r11, r3 @ a1 = a1' + a2' | ||
76 | sub r3, r11, r3, lsl #1 @ a2 = a1 - 2 * a2' | ||
77 | |||
78 | subs r14, r14, #1 @ decrease loop count | ||
79 | |||
80 | @ Special store order for making the column pass calculate columns in | ||
81 | @ the order 0-2-1-3-4-6-5-7, allowing for uxtab16 use in later stages. | ||
82 | sub r2, r10, r6 @ block[7] = (a0 - b0) | ||
83 | mov r2, r2, asr #12 @ >> 12 | ||
84 | strh r2, [r1, #7*16] | ||
85 | sub r2, r11, r7 @ block[6] = (a1 - b1) | ||
86 | mov r2, r2, asr #12 @ >> 12 | ||
87 | strh r2, [r1, #5*16] | ||
88 | sub r2, r3, r8 @ block[5] = (a2 - b2) | ||
89 | mov r2, r2, asr #12 @ >> 12 | ||
90 | strh r2, [r1, #6*16] | ||
91 | sub r2, r12, r9 @ block[4] = (a3 - b3) | ||
92 | mov r2, r2, asr #12 @ >> 12 | ||
93 | strh r2, [r1, #4*16] | ||
94 | add r2, r12, r9 @ block[3] = (a3 + b3) | ||
95 | mov r2, r2, asr #12 @ >> 12 | ||
96 | strh r2, [r1, #3*16] | ||
97 | add r2, r3, r8 @ block[2] = (a2 + b2) | ||
98 | mov r2, r2, asr #12 @ >> 12 | ||
99 | strh r2, [r1, #1*16] | ||
100 | add r2, r11, r7 @ block[1] = (a1 + b1) | ||
101 | mov r2, r2, asr #12 @ >> 12 | ||
102 | strh r2, [r1, #2*16] | ||
103 | add r2, r10, r6 @ block[0] = (a0 + b0) | ||
104 | mov r2, r2, asr #12 @ >> 12 | ||
105 | strh r2, [r1], #2 @ advance to next temp column | ||
106 | |||
107 | bne .row_loop | ||
108 | b .col_start | ||
109 | |||
110 | @placed here because of ldrd's offset limit | ||
111 | L_W1357: | ||
112 | .short 2841 | ||
113 | .short 2408 | ||
114 | .short 1609 | ||
115 | .short 565 | ||
116 | |||
117 | L_W0246: | ||
118 | .short 2048 | ||
119 | .short 2676 | ||
120 | .short 2048 | ||
121 | .short 1108 | ||
122 | |||
123 | .col_start: | ||
124 | @ r0 now points to the temp buffer, where we need it. | ||
125 | sub r1, r1, #128+16 @ point r1 back to the input block | ||
126 | mov r14, #8 @ loop counter | ||
127 | |||
128 | .col_loop: | ||
129 | ldmia r0!, {r2, r3, r10, r11} @ fetch f0, f2, f4, f6, f1, f3, f5, f7 | ||
130 | ldrd r4, L_W1357 @ load W1, W3, W5, W7 | ||
131 | |||
132 | smuad r6, r4, r10 @ b0 = W1 * f1 + W3 * f3 | ||
133 | smultt r7, r5, r10 @ -b1 = W7 * f3 | ||
134 | smulbt r8, r4, r10 @ -b2 = W1 * f3 | ||
135 | |||
136 | smusdx r9, r10, r5 @ b3 = f1 * W7 - f3 * W5 | ||
137 | smlabb r7, r4, r11, r7 @ -b1 += W1 * f5 | ||
138 | rsb r8, r8, #0 @ b2 = -b2 | ||
139 | smlabb r8, r5, r10, r8 @ b2 += W5 * f1 | ||
140 | |||
141 | smlad r6, r5, r11, r6 @ b0 += W5 * f5 + W7 * f7 | ||
142 | smlabt r7, r5, r11, r7 @ -b1 += W5 * f7 | ||
143 | smlatb r8, r5, r11, r8 @ b2 += W7 * f5 | ||
144 | |||
145 | smlsdx r9, r11, r4, r9 @ b3 += f5 * W3 - f7 * W1 | ||
146 | rsb r7, r7, #0 @ b1 = -b1 | ||
147 | smlatb r7, r4, r10, r7 @ b1 += W3 * f1 | ||
148 | smlatt r8, r4, r11, r8 @ b2 += W3 * f7 | ||
149 | |||
150 | ldrd r4, L_W0246 @ load W0, W2, W4, W6 | ||
151 | add r2, r2, #32 @ DC offset: 0.5 | ||
152 | |||
153 | smulbb r10, r5, r3 @ a0' = W4 * f4 | ||
154 | smultt r12, r5, r3 @ a3' = W6 * f6 | ||
155 | smultt r3, r4, r3 @ -a2' = W2 * f6 | ||
156 | |||
157 | rsb r11, r10, #0 @ a1' = -W4 * f4 | ||
158 | smlabb r10, r4, r2, r10 @ a0' += W0 * f0 | ||
159 | smlabb r11, r4, r2, r11 @ a1' += W0 * f0 | ||
160 | smlatt r12, r4, r2, r12 @ a3' += W2 * f2 | ||
161 | rsb r3, r3, #0 @ a2' = -a2' | ||
162 | smlatt r3, r5, r2, r3 @ a2' += W6 * f2 | ||
163 | |||
164 | add r10, r10, r12 @ a0 = a0' + a3' | ||
165 | sub r12, r10, r12, lsl #1 @ a3 = a0 - 2 * a3' | ||
166 | add r11, r11, r3 @ a1 = a1' + a2' | ||
167 | sub r3, r11, r3, lsl #1 @ a2 = a1 - 2 * a2' | ||
168 | |||
169 | subs r14, r14, #1 @ decrease loop count | ||
170 | |||
171 | sub r2, r10, r6 @ block[7] = (a0 - b0) | ||
172 | mov r2, r2, asr #17 @ >> 17 | ||
173 | strh r2, [r1, #7*16] | ||
174 | sub r2, r11, r7 @ block[6] = (a1 - b1) | ||
175 | mov r2, r2, asr #17 @ >> 17 | ||
176 | strh r2, [r1, #6*16] | ||
177 | sub r2, r3, r8 @ block[5] = (a2 - b2) | ||
178 | mov r2, r2, asr #17 @ >> 17 | ||
179 | strh r2, [r1, #5*16] | ||
180 | sub r2, r12, r9 @ block[4] = (a3 - b3) | ||
181 | mov r2, r2, asr #17 @ >> 17 | ||
182 | strh r2, [r1, #4*16] | ||
183 | add r2, r12, r9 @ block[3] = (a3 + b3) | ||
184 | mov r2, r2, asr #17 @ >> 17 | ||
185 | strh r2, [r1, #3*16] | ||
186 | add r2, r3, r8 @ block[2] = (a2 + b2) | ||
187 | mov r2, r2, asr #17 @ >> 17 | ||
188 | strh r2, [r1, #2*16] | ||
189 | add r2, r11, r7 @ block[1] = (a1 + b1) | ||
190 | mov r2, r2, asr #17 @ >> 17 | ||
191 | strh r2, [r1, #1*16] | ||
192 | add r2, r10, r6 @ block[0] = (a0 + b0) | ||
193 | mov r2, r2, asr #17 @ >> 17 | ||
194 | strh r2, [r1], #2 @ advance to next column | ||
195 | |||
196 | bne .col_loop | ||
197 | |||
198 | sub r0, r0, #256 @ point r0 back to the input block | ||
199 | ldr pc, [sp], #4 | ||
200 | |||
201 | |||
202 | mpeg2_idct_copy: | ||
203 | stmfd sp!, {r1-r2, r4-r11, lr} | ||
204 | bl .idct | ||
205 | ldmfd sp!, {r1-r2} | ||
206 | |||
207 | add r3, r0, #128 | ||
208 | mov r8, #0 | ||
209 | mov r9, #0 | ||
210 | mov r10, #0 | ||
211 | mov r11, #0 | ||
212 | 1: @ idct data is in order 0-2-1-3-4-6-5-7, | ||
213 | ldmia r0, {r4-r7} @ see above | ||
214 | stmia r0!, {r8-r11} | ||
215 | usat16 r4, #8, r4 | ||
216 | usat16 r5, #8, r5 | ||
217 | orr r4, r4, r5, lsl #8 | ||
218 | usat16 r6, #8, r6 | ||
219 | usat16 r7, #8, r7 | ||
220 | orr r5, r6, r7, lsl #8 | ||
221 | strd r4, [r1] @ r4, r5 | ||
222 | add r1, r1, r2 | ||
223 | cmp r0, r3 | ||
224 | blo 1b | ||
225 | |||
226 | ldmfd sp!, {r4-r11, pc} | ||
227 | |||
228 | mpeg2_idct_add: | ||
229 | cmp r0, #129 | ||
230 | mov r0, r1 | ||
231 | ldreqsh r1, [r0, #0] | ||
232 | bne 1f | ||
233 | and r1, r1, #0x70 | ||
234 | cmp r1, #0x40 | ||
235 | bne 3f | ||
236 | 1: | ||
237 | stmfd sp!, {r2-r11, lr} | ||
238 | bl .idct | ||
239 | ldmfd sp!, {r1-r2} | ||
240 | |||
241 | add r3, r0, #128 | ||
242 | mov r10, #0 | ||
243 | mov r11, #0 | ||
244 | mov r12, #0 | ||
245 | mov lr, #0 | ||
246 | ldrd r8, [r1] @ r8, r9 | ||
247 | 2: @ idct data is in order 0-2-1-3-4-6-5-7, | ||
248 | ldmia r0, {r4-r7} @ see above | ||
249 | stmia r0!, {r10-r12, lr} | ||
250 | uxtab16 r4, r4, r8 | ||
251 | uxtab16 r5, r5, r8, ror #8 | ||
252 | usat16 r4, #8, r4 | ||
253 | usat16 r5, #8, r5 | ||
254 | orr r4, r4, r5, lsl #8 | ||
255 | uxtab16 r6, r6, r9 | ||
256 | uxtab16 r7, r7, r9, ror #8 | ||
257 | usat16 r6, #8, r6 | ||
258 | usat16 r7, #8, r7 | ||
259 | orr r5, r6, r7, lsl #8 | ||
260 | strd r4, [r1] @ r4, r5 | ||
261 | add r1, r1, r2 | ||
262 | cmp r0, r3 | ||
263 | ldrlod r8, [r1] @ r8, r9 | ||
264 | blo 2b | ||
265 | |||
266 | ldmfd sp!, {r4-r11, pc} | ||
267 | |||
268 | 3: | ||
269 | stmfd sp!, {r4, lr} | ||
270 | ldrsh r4, [r0, #0] @ r4 = block[0] | ||
271 | mov r12, #0 | ||
272 | strh r12, [r0, #0] @ block[0] = 0 | ||
273 | strh r12, [r0, #126] @ block[63] = 0 | ||
274 | add r4, r4, #64 | ||
275 | mov r4, r4, asr #7 @ r4 = DC | ||
276 | mov r4, r4, lsl #16 @ spread to 2 halfwords | ||
277 | orr r4, r4, r4, lsr #16 | ||
278 | ldrd r0, [r2] @ r0, r1 | ||
279 | add r12, r2, r3, asl #3 | ||
280 | 4: | ||
281 | uxtab16 lr, r4, r0, ror #8 | ||
282 | uxtab16 r0, r4, r0 | ||
283 | usat16 lr, #8, lr | ||
284 | usat16 r0, #8, r0 | ||
285 | orr r0, r0, lr, lsl #8 | ||
286 | uxtab16 lr, r4, r1, ror #8 | ||
287 | uxtab16 r1, r4, r1 | ||
288 | usat16 lr, #8, lr | ||
289 | usat16 r1, #8, r1 | ||
290 | orr r1, r1, lr, lsl #8 | ||
291 | strd r0, [r2] @ r0, r1 | ||
292 | add r2, r2, r3 | ||
293 | cmp r2, r12 | ||
294 | ldrlod r0, [r2] @ r0, r1 | ||
295 | blo 4b | ||
296 | |||
297 | ldmfd sp!, {r4, pc} | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/idct_coldfire.S b/apps/plugins/mpegplayer/libmpeg2/idct_coldfire.S deleted file mode 100644 index abc54b16cb..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/idct_coldfire.S +++ /dev/null | |||
@@ -1,575 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 Jens Arnold | ||
11 | * Based on the work of Karim Boucher and Rani Hod | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | |||
23 | .global mpeg2_idct_copy | ||
24 | .type mpeg2_idct_copy, @function | ||
25 | .global mpeg2_idct_add | ||
26 | .type mpeg2_idct_add, @function | ||
27 | |||
28 | /* The IDCT itself. | ||
29 | * Input: %a0: block pointer | ||
30 | * Caller must save all registers. */ | ||
31 | .align 2 | ||
32 | .idct: | ||
33 | move.l %a0, %a6 | ||
34 | |||
35 | move.l #0, %macsr | signed integer mode | ||
36 | |||
37 | move.l #((2048<<16)+2841), %a0 | W0, W1 | ||
38 | move.l #((2676<<16)+2408), %a1 | W2, W3 | ||
39 | move.l #((2048<<16)+1609), %a2 | W4, W5 | ||
40 | move.l #((1108<<16)+ 565), %a3 | W6, W7 | ||
41 | |||
42 | lea.l (128,%a6), %a4 | secondary, transposed temp buffer | ||
43 | moveq.l #8, %d3 | loop counter | ||
44 | |||
45 | .row_loop: | ||
46 | movem.l (%a6), %d0-%d2/%a5 | fetch (f0, f2, f4, f6, f1, f3, f5, f7) | ||
47 | |||
48 | mac.w %a0l, %d2u, %acc0 | %acc0 = W1 * f1 | ||
49 | mac.w %a1l, %d2l, %acc0 | + W3 * f3 | ||
50 | mac.w %a2l, %a5u, %acc0 | + W5 * f5 | ||
51 | mac.w %a3l, %a5l, %acc0 | + W7 * f7 | ||
52 | |||
53 | mac.w %a1l, %d2u, %acc1 | %acc1 = W3 * f1 | ||
54 | msac.w %a3l, %d2l, %acc1 | - W7 * f3 | ||
55 | msac.w %a0l, %a5u, %acc1 | - W1 * f5 | ||
56 | msac.w %a2l, %a5l, %acc1 | - W5 * f7 | ||
57 | |||
58 | mac.w %a2l, %d2u, %acc2 | %acc2 = W5 * f1 | ||
59 | msac.w %a0l, %d2l, %acc2 | - W1 * f3 | ||
60 | mac.w %a3l, %a5u, %acc2 | + W7 * f5 | ||
61 | mac.w %a1l, %a5l, %acc2 | + W3 * f7 | ||
62 | |||
63 | mac.w %a3l, %d2u, %acc3 | %acc3 = W7 * f1 | ||
64 | msac.w %a2l, %d2l, %acc3 | - W5 * f3 | ||
65 | mac.w %a1l, %a5u, %acc3 | + W3 * f5 | ||
66 | msac.w %a0l, %a5l, %acc3 | - W1 * f7 | ||
67 | |||
68 | lea.l (16,%a6), %a6 | Advance to next row; put here to fill EMAC latency | ||
69 | add.l #(1<<16), %d0 | f0 += 1; | ||
70 | |||
71 | movclr.l %acc0, %d4 | b0 | ||
72 | movclr.l %acc1, %d5 | b1 | ||
73 | movclr.l %acc2, %d6 | b2 | ||
74 | movclr.l %acc3, %d7 | b3 | ||
75 | |||
76 | mac.w %a0u, %d0u, %acc0 | %acc0 = W0 * f0 | ||
77 | mac.w %a2u, %d1u, %acc0 | + W4 * f4 | ||
78 | move.l %acc0, %acc3 | ||
79 | mac.w %a1u, %d0l, %acc0 | + W2 * f2 | ||
80 | mac.w %a3u, %d1l, %acc0 | + W6 * f6 | ||
81 | |||
82 | mac.w %a0u, %d0u, %acc1 | %acc1 = W0 * f0 | ||
83 | msac.w %a2u, %d1u, %acc1 | - W4 * f4 | ||
84 | move.l %acc1, %acc2 | ||
85 | mac.w %a3u, %d0l, %acc1 | + W6 * f2 | ||
86 | msac.w %a1u, %d1l, %acc1 | - W2 * f6 | ||
87 | |||
88 | | ^ move.l %acc1, %acc2 %acc2 = W0 * f0 - W4 * f4 | ||
89 | msac.w %a3u, %d0l, %acc2 | - W6 * f2 | ||
90 | mac.w %a1u, %d1l, %acc2 | + W2 * f6 | ||
91 | |||
92 | | ^ move.l %acc0, %acc3 %acc3 = W0 * f0 + W4 * f4 | ||
93 | msac.w %a1u, %d0l, %acc3 | - W2 * f2 | ||
94 | msac.w %a3u, %d1l, %acc3 | - W6 * f6 | ||
95 | |||
96 | moveq.l #12, %d1 | shift amount | ||
97 | |||
98 | move.l %acc0, %d0 | block[7] = (a0 | ||
99 | sub.l %d4,%d0 | - b0) | ||
100 | asr.l %d1, %d0 | >> 12 | ||
101 | move.w %d0, (7*16,%a4) | ||
102 | |||
103 | move.l %acc1, %d0 | block[6] = (a1 | ||
104 | sub.l %d5,%d0 | - b1) | ||
105 | asr.l %d1, %d0 | >> 12 | ||
106 | move.w %d0, (6*16,%a4) | ||
107 | |||
108 | move.l %acc2, %d0 | block[5] = (a2 | ||
109 | sub.l %d6,%d0 | - b2) | ||
110 | asr.l %d1, %d0 | >> 12 | ||
111 | move.w %d0, (5*16,%a4) | ||
112 | |||
113 | move.l %acc3, %d0 | block[4] = (a3 | ||
114 | sub.l %d7,%d0 | - b3) | ||
115 | asr.l %d1, %d0 | >> 12 | ||
116 | move.w %d0, (4*16,%a4) | ||
117 | |||
118 | movclr.l %acc3, %d0 | block[3] = (a3 | ||
119 | add.l %d7, %d0 | + b3) | ||
120 | asr.l %d1, %d0 | >> 12 | ||
121 | move.w %d0, (3*16,%a4) | ||
122 | |||
123 | movclr.l %acc2, %d0 | block[2] = (a2 | ||
124 | add.l %d6, %d0 | + b2) | ||
125 | asr.l %d1, %d0 | >> 12 | ||
126 | move.w %d0, (2*16,%a4) | ||
127 | |||
128 | movclr.l %acc1, %d0 | block[1] = (a1 | ||
129 | add.l %d5, %d0 | + b1) | ||
130 | asr.l %d1, %d0 | >> 12 | ||
131 | move.w %d0, (1*16,%a4) | ||
132 | |||
133 | movclr.l %acc0, %d0 | block[0] = (a0 | ||
134 | add.l %d4, %d0 | + b0) | ||
135 | asr.l %d1, %d0 | >> 12 | ||
136 | move.w %d0, (%a4)+ | advance to next temp column | ||
137 | |||
138 | subq.l #1, %d3 | loop 8 times | ||
139 | bne.w .row_loop | ||
140 | |||
141 | | %a6 now points to the temp buffer, where we need it. | ||
142 | lea.l (-16-128,%a4), %a4 | point %a4 back to the input block | ||
143 | moveq.l #8, %d3 | loop counter | ||
144 | |||
145 | .col_loop: | ||
146 | movem.l (%a6), %d0-%d2/%a5 | fetch (f0, f2, f4, f6, f1, f3, f5, f7) | ||
147 | |||
148 | mac.w %a0l, %d2u, %acc0 | %acc0 = W1 * f1 | ||
149 | mac.w %a1l, %d2l, %acc0 | + W3 * f3 | ||
150 | mac.w %a2l, %a5u, %acc0 | + W5 * f5 | ||
151 | mac.w %a3l, %a5l, %acc0 | + W7 * f7 | ||
152 | |||
153 | mac.w %a1l, %d2u, %acc1 | %acc1 = W3 * f1 | ||
154 | msac.w %a3l, %d2l, %acc1 | - W7 * f3 | ||
155 | msac.w %a0l, %a5u, %acc1 | - W1 * f5 | ||
156 | msac.w %a2l, %a5l, %acc1 | - W5 * f7 | ||
157 | |||
158 | mac.w %a2l, %d2u, %acc2 | %acc2 = W5 * f1 | ||
159 | msac.w %a0l, %d2l, %acc2 | - W1 * f3 | ||
160 | mac.w %a3l, %a5u, %acc2 | + W7 * f5 | ||
161 | mac.w %a1l, %a5l, %acc2 | + W3 * f7 | ||
162 | |||
163 | mac.w %a3l, %d2u, %acc3 | %acc3 = W7 * f1 | ||
164 | msac.w %a2l, %d2l, %acc3 | - W5 * f3 | ||
165 | mac.w %a1l, %a5u, %acc3 | + W3 * f5 | ||
166 | msac.w %a0l, %a5l, %acc3 | - W1 * f7 | ||
167 | |||
168 | lea.l (16,%a6), %a6 | Advance to next row; put here to fill EMAC latency | ||
169 | add.l #(32<<16), %d0 | DC offset: 0.5 | ||
170 | |||
171 | movclr.l %acc0, %d4 | b0 | ||
172 | movclr.l %acc1, %d5 | b1 | ||
173 | movclr.l %acc2, %d6 | b2 | ||
174 | movclr.l %acc3, %d7 | b3 | ||
175 | |||
176 | mac.w %a0u, %d0u, %acc0 | %acc0 = W0 * f0 | ||
177 | mac.w %a2u, %d1u, %acc0 | + W4 * f4 | ||
178 | move.l %acc0, %acc3 | ||
179 | mac.w %a1u, %d0l, %acc0 | + W2 * f2 | ||
180 | mac.w %a3u, %d1l, %acc0 | + W6 * f6 | ||
181 | |||
182 | mac.w %a0u, %d0u, %acc1 | %acc1 = W0 * f0 | ||
183 | msac.w %a2u, %d1u, %acc1 | - W4 * f4 | ||
184 | move.l %acc1, %acc2 | ||
185 | mac.w %a3u, %d0l, %acc1 | + W6 * f2 | ||
186 | msac.w %a1u, %d1l, %acc1 | - W2 * f6 | ||
187 | |||
188 | | ^ move.l %acc1, %acc2 %acc2 = W0 * f0 - W4 * f4 | ||
189 | msac.w %a3u, %d0l, %acc2 | - W6 * f2 | ||
190 | mac.w %a1u, %d1l, %acc2 | + W2 * f6 | ||
191 | |||
192 | | ^ move.l %acc0, %acc3 %acc3 = W0 * f0 + W4 * f4 | ||
193 | msac.w %a1u, %d0l, %acc3 | - W2 * f2 | ||
194 | msac.w %a3u, %d1l, %acc3 | - W6 * f6 | ||
195 | |||
196 | moveq.l #17, %d1 | shift amount | ||
197 | |||
198 | move.l %acc0, %d0 | block[7] = (a0 | ||
199 | sub.l %d4,%d0 | - b0) | ||
200 | asr.l %d1, %d0 | >> 17 | ||
201 | move.w %d0, (7*16,%a4) | ||
202 | |||
203 | move.l %acc1, %d0 | block[6] = (a1 | ||
204 | sub.l %d5,%d0 | - b1) | ||
205 | asr.l %d1, %d0 | >> 17 | ||
206 | move.w %d0, (6*16,%a4) | ||
207 | |||
208 | move.l %acc2, %d0 | block[5] = (a2 | ||
209 | sub.l %d6,%d0 | - b2) | ||
210 | asr.l %d1, %d0 | >> 17 | ||
211 | move.w %d0, (5*16,%a4) | ||
212 | |||
213 | move.l %acc3, %d0 | block[4] = (a3 | ||
214 | sub.l %d7,%d0 | - b3) | ||
215 | asr.l %d1, %d0 | >> 17 | ||
216 | move.w %d0, (4*16,%a4) | ||
217 | |||
218 | movclr.l %acc3, %d0 | block[3] = (a3 | ||
219 | add.l %d7, %d0 | + b3) | ||
220 | asr.l %d1, %d0 | >> 17 | ||
221 | move.w %d0, (3*16,%a4) | ||
222 | |||
223 | movclr.l %acc2, %d0 | block[2] = (a2 | ||
224 | add.l %d6, %d0 | + b2) | ||
225 | asr.l %d1, %d0 | >> 17 | ||
226 | move.w %d0, (2*16,%a4) | ||
227 | |||
228 | movclr.l %acc1, %d0 | block[1] = (a1 | ||
229 | add.l %d5, %d0 | + b1) | ||
230 | asr.l %d1, %d0 | >> 17 | ||
231 | move.w %d0, (1*16,%a4) | ||
232 | |||
233 | movclr.l %acc0, %d0 | block[0] = (a0 | ||
234 | add.l %d4, %d0 | + b0) | ||
235 | asr.l %d1, %d0 | >> 17 | ||
236 | move.w %d0, (%a4)+ | advance to next column | ||
237 | |||
238 | subq.l #1, %d3 | loop 8 times | ||
239 | bne.w .col_loop | ||
240 | |||
241 | rts | ||
242 | |||
243 | .align 2 | ||
244 | |||
245 | mpeg2_idct_copy: | ||
246 | lea.l (-11*4,%sp), %sp | ||
247 | movem.l %d2-%d7/%a2-%a6, (%sp) | save some registers | ||
248 | move.l (11*4+4,%sp), %a0 | %a0 - block pointer for idct | ||
249 | |||
250 | bsr.w .idct | apply idct to block | ||
251 | movem.l (11*4+4,%sp), %a0-%a2 | %a0 - block pointer | ||
252 | | %a1 - destination pointer | ||
253 | | %a2 - stride | ||
254 | |||
255 | move.l #255, %d1 | preload constant for clipping | ||
256 | moveq.l #8, %d4 | loop counter | ||
257 | |||
258 | .copy_clip_loop: | ||
259 | move.w (%a0), %d0 | load block[0] | ||
260 | ext.l %d0 | sign extend | ||
261 | cmp.l %d1, %d0 | overflow? | ||
262 | bls.b 1f | ||
263 | spl.b %d0 | yes: set appropriate limit value in low byte | ||
264 | 1: | ||
265 | move.b %d0, %d2 | collect output bytes 0..3 in %d2 | ||
266 | lsl.l #8, %d2 | ||
267 | |||
268 | move.w (2,%a0), %d0 | load block[1] | ||
269 | ext.l %d0 | sign extend | ||
270 | cmp.l %d1, %d0 | overflow? | ||
271 | bls.b 1f | ||
272 | spl.b %d0 | yes: set appropriate limit value in low byte | ||
273 | 1: | ||
274 | move.b %d0, %d2 | collect output bytes 0..3 in %d2 | ||
275 | lsl.l #8, %d2 | ||
276 | clr.l (%a0)+ | clear block[0] and block[1], | ||
277 | | %a0 now pointing to block[2] | ||
278 | move.w (%a0), %d0 | do b2 and b3 | ||
279 | ext.l %d0 | ||
280 | cmp.l %d1, %d0 | ||
281 | bls.b 1f | ||
282 | spl.b %d0 | ||
283 | 1: | ||
284 | move.b %d0, %d2 | ||
285 | lsl.l #8, %d2 | ||
286 | |||
287 | move.w (2,%a0), %d0 | ||
288 | ext.l %d0 | ||
289 | cmp.l %d1, %d0 | ||
290 | bls.b 1f | ||
291 | spl.b %d0 | ||
292 | 1: | ||
293 | move.b %d0, %d2 | ||
294 | clr.l (%a0)+ | ||
295 | |||
296 | move.w (%a0), %d0 | do b4 and b5 | ||
297 | ext.l %d0 | ||
298 | cmp.l %d1, %d0 | ||
299 | bls.b 1f | ||
300 | spl.b %d0 | ||
301 | 1: | ||
302 | move.b %d0, %d3 | ||
303 | lsl.l #8, %d3 | ||
304 | |||
305 | move.w (2,%a0), %d0 | ||
306 | ext.l %d0 | ||
307 | cmp.l %d1, %d0 | ||
308 | bls.b 1f | ||
309 | spl.b %d0 | ||
310 | 1: | ||
311 | move.b %d0, %d3 | ||
312 | lsl.l #8, %d3 | ||
313 | clr.l (%a0)+ | ||
314 | |||
315 | move.w (%a0), %d0 | do b6 and b7 | ||
316 | ext.l %d0 | ||
317 | cmp.l %d1, %d0 | ||
318 | bls.b 1f | ||
319 | spl.b %d0 | ||
320 | 1: | ||
321 | move.b %d0, %d3 | ||
322 | lsl.l #8, %d3 | ||
323 | |||
324 | move.w (2,%a0), %d0 | ||
325 | ext.l %d0 | ||
326 | cmp.l %d1, %d0 | ||
327 | bls.b 1f | ||
328 | spl.b %d0 | ||
329 | 1: | ||
330 | move.b %d0, %d3 | ||
331 | clr.l (%a0)+ | ||
332 | |||
333 | movem.l %d2-%d3, (%a1) | write all 8 output bytes at once | ||
334 | add.l %a2, %a1 | advance output pointer | ||
335 | subq.l #1, %d4 | loop 8 times | ||
336 | bne.w .copy_clip_loop | ||
337 | |||
338 | movem.l (%sp), %d2-%d7/%a2-%a6 | ||
339 | lea.l (11*4,%sp), %sp | ||
340 | rts | ||
341 | |||
342 | .align 2 | ||
343 | |||
344 | mpeg2_idct_add: | ||
345 | lea.l (-11*4,%sp), %sp | ||
346 | movem.l %d2-%d7/%a2-%a6, (%sp) | ||
347 | movem.l (11*4+4,%sp), %d0/%a0-%a2 | %d0 - last value | ||
348 | | %a0 - block pointer | ||
349 | | %a1 - destination pointer | ||
350 | | %a2 - stride | ||
351 | |||
352 | cmp.l #129, %d0 | last == 129 ? | ||
353 | bne.b .idct_add | no: perform idct + addition | ||
354 | move.w (%a0), %d0 | ||
355 | ext.l %d0 | ((block[0] | ||
356 | asr.l #4, %d0 | >> 4) | ||
357 | and.l #7, %d0 | & 7) | ||
358 | subq.l #4, %d0 | - 4 == 0 ? | ||
359 | bne.w .dc_add | no: just perform addition | ||
360 | |||
361 | .idct_add: | ||
362 | bsr.w .idct | apply idct | ||
363 | movem.l (11*4+8,%sp), %a0-%a2 | reload arguments %a0..%a2 | ||
364 | |||
365 | move.l #255, %d2 | preload constant for clipping | ||
366 | clr.l %d3 | used for splitting input words into bytes | ||
367 | moveq.l #8, %d4 | loop counter | ||
368 | |||
369 | .add_clip_loop: | ||
370 | movem.l (%a1), %d6-%d7 | fetch (b0 b1 b2 b3) (b4 b5 b6 b7) | ||
371 | swap %d6 | (b2 b3 b0 b1) | ||
372 | swap %d7 | (b6 b7 b4 b5) | ||
373 | |||
374 | move.w (2,%a0), %d0 | load block[1] | ||
375 | ext.l %d0 | sign extend | ||
376 | move.b %d6, %d3 | copy b1 | ||
377 | lsr.l #8, %d6 | prepare 1st buffer for next byte | ||
378 | add.l %d3, %d0 | add b1 | ||
379 | cmp.l %d2, %d0 | overflow ? | ||
380 | bls.b 1f | ||
381 | spl.b %d0 | yes: set appropriate limit value in low byte | ||
382 | 1: | ||
383 | move.w (%a0), %d1 | load block[0] | ||
384 | ext.l %d1 | sign extend | ||
385 | move.b %d6, %d3 | copy b0 | ||
386 | lsr.l #8, %d6 | prepare 1st buffer for next byte | ||
387 | add.l %d3, %d1 | add b0 | ||
388 | cmp.l %d2, %d1 | overflow ? | ||
389 | bls.b 1f | ||
390 | spl.b %d1 | yes: set appropriate limit value in low byte | ||
391 | 1: | ||
392 | move.b %d1, %d5 | collect output bytes 0..3 in %d5 | ||
393 | lsl.l #8, %d5 | ||
394 | move.b %d0, %d5 | ||
395 | lsl.l #8, %d5 | ||
396 | clr.l (%a0)+ | clear block[0] and block[1] | ||
397 | | %a0 now pointing to block[2] | ||
398 | move.w (2,%a0), %d0 | do b3 and b2 | ||
399 | ext.l %d0 | ||
400 | move.b %d6, %d3 | ||
401 | lsr.l #8, %d6 | ||
402 | add.l %d3, %d0 | ||
403 | cmp.l %d2, %d0 | ||
404 | bls.b 1f | ||
405 | spl.b %d0 | ||
406 | 1: | ||
407 | move.w (%a0), %d1 | ||
408 | ext.l %d1 | ||
409 | add.l %d6, %d1 | ||
410 | cmp.l %d2, %d1 | ||
411 | bls.b 1f | ||
412 | spl.b %d1 | ||
413 | 1: | ||
414 | move.b %d1, %d5 | ||
415 | lsl.l #8, %d5 | ||
416 | move.b %d0, %d5 | ||
417 | clr.l (%a0)+ | ||
418 | |||
419 | move.w (2,%a0), %d0 | do b5 and b4 | ||
420 | ext.l %d0 | ||
421 | move.b %d7, %d3 | ||
422 | lsr.l #8, %d7 | ||
423 | add.l %d3, %d0 | ||
424 | cmp.l %d2, %d0 | ||
425 | bls.b 1f | ||
426 | spl.b %d0 | ||
427 | 1: | ||
428 | move.w (%a0), %d1 | ||
429 | ext.l %d1 | ||
430 | move.b %d7, %d3 | ||
431 | lsr.l #8, %d7 | ||
432 | add.l %d3, %d1 | ||
433 | cmp.l %d2, %d1 | ||
434 | bls.b 1f | ||
435 | spl.b %d1 | ||
436 | 1: | ||
437 | move.b %d1, %d6 | ||
438 | lsl.l #8, %d6 | ||
439 | move.b %d0, %d6 | ||
440 | lsl.l #8, %d6 | ||
441 | clr.l (%a0)+ | ||
442 | |||
443 | move.w (2,%a0), %d0 | do b7 and b6 | ||
444 | ext.l %d0 | ||
445 | move.b %d7, %d3 | ||
446 | lsr.l #8, %d7 | ||
447 | add.l %d3, %d0 | ||
448 | cmp.l %d2, %d0 | ||
449 | bls.b 1f | ||
450 | spl.b %d0 | ||
451 | 1: | ||
452 | move.w (%a0), %d1 | ||
453 | ext.l %d1 | ||
454 | add.l %d7, %d1 | ||
455 | cmp.l %d2, %d1 | ||
456 | bls.b 1f | ||
457 | spl.b %d1 | ||
458 | 1: | ||
459 | move.b %d1, %d6 | ||
460 | lsl.l #8, %d6 | ||
461 | move.b %d0, %d6 | ||
462 | clr.l (%a0)+ | ||
463 | |||
464 | movem.l %d5-%d6, (%a1) | write all 8 output bytes at once | ||
465 | add.l %a2, %a1 | advance output pointer | ||
466 | subq.l #1, %d4 | loop 8 times | ||
467 | bne.w .add_clip_loop | ||
468 | |||
469 | bra.w .idct_add_end | ||
470 | |||
471 | .dc_add: | ||
472 | move.w (%a0), %d0 | ||
473 | ext.l %d0 | %d0 = (block[0] | ||
474 | add.l #64, %d0 | + 64) | ||
475 | asr.l #7, %d0 | >> 7 | ||
476 | clr.w (%a0) | clear block[0] | ||
477 | clr.w (63*2,%a0) | and block[63] | ||
478 | move.l %d0, %a0 | DC value in %a0 | ||
479 | |||
480 | move.l #255, %d2 | preload constant for clipping | ||
481 | clr.l %d3 | for splitting input words into bytes | ||
482 | moveq.l #8, %d4 | loop counter | ||
483 | |||
484 | .dc_clip_loop: | ||
485 | movem.l (%a1), %d6-%d7 | (b0 b1 b2 b3) (b4 b5 b6 b7) | ||
486 | swap %d6 | (b2 b3 b0 b1) | ||
487 | swap %d7 | (b6 b7 b4 b5) | ||
488 | |||
489 | move.l %a0, %d0 | copy DC | ||
490 | move.b %d6, %d3 | copy b1 | ||
491 | lsr.l #8, %d6 | prepare 1st buffer for next byte | ||
492 | add.l %d3, %d0 | add b1 | ||
493 | cmp.l %d2, %d0 | overflow ? | ||
494 | bls.b 1f | ||
495 | spl.b %d0 | yes: set appropriate limit value in low byte | ||
496 | 1: | ||
497 | move.l %a0, %d1 | copy DC | ||
498 | move.b %d6, %d3 | copy b0 | ||
499 | lsr.l #8, %d6 | prepare 1st buffer for next byte | ||
500 | add.l %d3, %d1 | add b0 | ||
501 | cmp.l %d2, %d1 | overflow ? | ||
502 | bls.b 1f | ||
503 | spl.b %d1 | yes: set appropriate limit value in low byte | ||
504 | 1: | ||
505 | move.b %d1, %d5 | collect output bytes 0..3 in %d5 | ||
506 | lsl.l #8, %d5 | ||
507 | move.b %d0, %d5 | ||
508 | lsl.l #8, %d5 | ||
509 | |||
510 | move.l %a0, %d0 | do b3 and b2 | ||
511 | move.b %d6, %d3 | ||
512 | lsr.l #8, %d6 | ||
513 | add.l %d3, %d0 | ||
514 | cmp.l %d2, %d0 | ||
515 | bls.b 1f | ||
516 | spl.b %d0 | ||
517 | 1: | ||
518 | move.l %a0, %d1 | ||
519 | add.l %d6, %d1 | ||
520 | cmp.l %d2, %d1 | ||
521 | bls.b 1f | ||
522 | spl.b %d1 | ||
523 | 1: | ||
524 | move.b %d1, %d5 | ||
525 | lsl.l #8, %d5 | ||
526 | move.b %d0, %d5 | ||
527 | |||
528 | move.l %a0, %d0 | do b5 and b4 | ||
529 | move.b %d7, %d3 | ||
530 | lsr.l #8, %d7 | ||
531 | add.l %d3, %d0 | ||
532 | cmp.l %d2, %d0 | ||
533 | bls.b 1f | ||
534 | spl.b %d0 | ||
535 | 1: | ||
536 | move.l %a0, %d1 | ||
537 | move.b %d7, %d3 | ||
538 | lsr.l #8, %d7 | ||
539 | add.l %d3, %d1 | ||
540 | cmp.l %d2, %d1 | ||
541 | bls.b 1f | ||
542 | spl.b %d1 | ||
543 | 1: | ||
544 | move.b %d1, %d6 | do b7 and b6 | ||
545 | lsl.l #8, %d6 | ||
546 | move.b %d0, %d6 | ||
547 | lsl.l #8, %d6 | ||
548 | |||
549 | move.l %a0, %d0 | ||
550 | move.b %d7, %d3 | ||
551 | lsr.l #8, %d7 | ||
552 | add.l %d3, %d0 | ||
553 | cmp.l %d2, %d0 | ||
554 | bls.b 1f | ||
555 | spl.b %d0 | ||
556 | 1: | ||
557 | move.l %a0, %d1 | ||
558 | add.l %d7, %d1 | ||
559 | cmp.l %d2, %d1 | ||
560 | bls.b 1f | ||
561 | spl.b %d1 | ||
562 | 1: | ||
563 | move.b %d1, %d6 | ||
564 | lsl.l #8, %d6 | ||
565 | move.b %d0, %d6 | ||
566 | |||
567 | movem.l %d5-%d6, (%a1) | write all 8 output bytes at once | ||
568 | add.l %a2, %a1 | advance output pointer | ||
569 | subq.l #1, %d4 | loop 8 times | ||
570 | bne.w .dc_clip_loop | ||
571 | |||
572 | .idct_add_end: | ||
573 | movem.l (%sp), %d2-%d7/%a2-%a6 | ||
574 | lea.l (11*4,%sp), %sp | ||
575 | rts | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/motion_comp.c b/apps/plugins/mpegplayer/libmpeg2/motion_comp.c deleted file mode 100644 index d6968f68ce..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/motion_comp.c +++ /dev/null | |||
@@ -1,66 +0,0 @@ | |||
1 | /* | ||
2 | * motion_comp.c | ||
3 | * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> | ||
4 | * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> | ||
5 | * | ||
6 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
7 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
8 | * | ||
9 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * mpeg2dec is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | * $Id$ | ||
24 | * libmpeg2 sync history: | ||
25 | * 2008-07-01 - CVS revision 1.17 - lost compatibility previously to | ||
26 | * provide simplified and CPU-optimized motion compensation. | ||
27 | */ | ||
28 | |||
29 | #include "plugin.h" | ||
30 | |||
31 | #include "mpeg2dec_config.h" | ||
32 | |||
33 | #include "mpeg2.h" | ||
34 | #include "attributes.h" | ||
35 | #include "mpeg2_internal.h" | ||
36 | |||
37 | /* These are defined in their respective target files - motion_comp_X.c */ | ||
38 | extern mpeg2_mc_fct MC_put_o_16; | ||
39 | extern mpeg2_mc_fct MC_put_o_8; | ||
40 | extern mpeg2_mc_fct MC_put_x_16; | ||
41 | extern mpeg2_mc_fct MC_put_x_8; | ||
42 | extern mpeg2_mc_fct MC_put_y_16; | ||
43 | extern mpeg2_mc_fct MC_put_y_8; | ||
44 | extern mpeg2_mc_fct MC_put_xy_16; | ||
45 | extern mpeg2_mc_fct MC_put_xy_8; | ||
46 | |||
47 | extern mpeg2_mc_fct MC_avg_o_16; | ||
48 | extern mpeg2_mc_fct MC_avg_o_8; | ||
49 | extern mpeg2_mc_fct MC_avg_x_16; | ||
50 | extern mpeg2_mc_fct MC_avg_x_8; | ||
51 | extern mpeg2_mc_fct MC_avg_y_16; | ||
52 | extern mpeg2_mc_fct MC_avg_y_8; | ||
53 | extern mpeg2_mc_fct MC_avg_xy_16; | ||
54 | extern mpeg2_mc_fct MC_avg_xy_8; | ||
55 | |||
56 | const mpeg2_mc_t mpeg2_mc = | ||
57 | { | ||
58 | { | ||
59 | MC_put_o_16, MC_put_x_16, MC_put_y_16, MC_put_xy_16, | ||
60 | MC_put_o_8, MC_put_x_8, MC_put_y_8, MC_put_xy_8 | ||
61 | }, | ||
62 | { | ||
63 | MC_avg_o_16, MC_avg_x_16, MC_avg_y_16, MC_avg_xy_16, | ||
64 | MC_avg_o_8, MC_avg_x_8, MC_avg_y_8, MC_avg_xy_8 | ||
65 | } | ||
66 | }; | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/motion_comp.h b/apps/plugins/mpegplayer/libmpeg2/motion_comp.h deleted file mode 100644 index 4737e72cab..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/motion_comp.h +++ /dev/null | |||
@@ -1,86 +0,0 @@ | |||
1 | /* | ||
2 | * motion_comp.h | ||
3 | * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> | ||
4 | * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> | ||
5 | * | ||
6 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
7 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
8 | * | ||
9 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * mpeg2dec is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | * $Id$ | ||
24 | */ | ||
25 | |||
26 | |||
27 | #define avg2(a,b) ((a+b+1)>>1) | ||
28 | #define avg4(a,b,c,d) ((a+b+c+d+2)>>2) | ||
29 | |||
30 | #define predict_o(i) (ref[i]) | ||
31 | #define predict_x(i) (avg2 (ref[i], ref[i+1])) | ||
32 | #define predict_y(i) (avg2 (ref[i], (ref+stride)[i])) | ||
33 | #define predict_xy(i) (avg4 (ref[i], ref[i+1], \ | ||
34 | (ref+stride)[i], (ref+stride)[i+1])) | ||
35 | |||
36 | #define put(predictor,i) dest[i] = predictor (i) | ||
37 | #define avg(predictor,i) dest[i] = avg2 (predictor (i), dest[i]) | ||
38 | |||
39 | /* mc function template */ | ||
40 | #define MC_FUNC(op, xy) \ | ||
41 | MC_FUNC_16(op, xy) \ | ||
42 | MC_FUNC_8(op, xy) | ||
43 | |||
44 | #define MC_FUNC_16(op, xy) \ | ||
45 | void MC_##op##_##xy##_16 (uint8_t * dest, const uint8_t * ref, \ | ||
46 | const int stride, int height) \ | ||
47 | { \ | ||
48 | do { \ | ||
49 | op (predict_##xy, 0); \ | ||
50 | op (predict_##xy, 1); \ | ||
51 | op (predict_##xy, 2); \ | ||
52 | op (predict_##xy, 3); \ | ||
53 | op (predict_##xy, 4); \ | ||
54 | op (predict_##xy, 5); \ | ||
55 | op (predict_##xy, 6); \ | ||
56 | op (predict_##xy, 7); \ | ||
57 | op (predict_##xy, 8); \ | ||
58 | op (predict_##xy, 9); \ | ||
59 | op (predict_##xy, 10); \ | ||
60 | op (predict_##xy, 11); \ | ||
61 | op (predict_##xy, 12); \ | ||
62 | op (predict_##xy, 13); \ | ||
63 | op (predict_##xy, 14); \ | ||
64 | op (predict_##xy, 15); \ | ||
65 | ref += stride; \ | ||
66 | dest += stride; \ | ||
67 | } while (--height); \ | ||
68 | } | ||
69 | |||
70 | #define MC_FUNC_8(op, xy) \ | ||
71 | void MC_##op##_##xy##_8 (uint8_t * dest, const uint8_t * ref, \ | ||
72 | const int stride, int height) \ | ||
73 | { \ | ||
74 | do { \ | ||
75 | op (predict_##xy, 0); \ | ||
76 | op (predict_##xy, 1); \ | ||
77 | op (predict_##xy, 2); \ | ||
78 | op (predict_##xy, 3); \ | ||
79 | op (predict_##xy, 4); \ | ||
80 | op (predict_##xy, 5); \ | ||
81 | op (predict_##xy, 6); \ | ||
82 | op (predict_##xy, 7); \ | ||
83 | ref += stride; \ | ||
84 | dest += stride; \ | ||
85 | } while (--height); \ | ||
86 | } | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/motion_comp_arm_c.c b/apps/plugins/mpegplayer/libmpeg2/motion_comp_arm_c.c deleted file mode 100644 index dcf1df53e9..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/motion_comp_arm_c.c +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | /* | ||
2 | * motion_comp_arm.c | ||
3 | * Copyright (C) 2004 AGAWA Koji <i (AT) atty (DOT) jp> | ||
4 | * | ||
5 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
6 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
7 | * | ||
8 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * mpeg2dec is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | * $Id$ | ||
23 | */ | ||
24 | #include <inttypes.h> | ||
25 | #include "mpeg2.h" | ||
26 | #include "attributes.h" | ||
27 | #include "mpeg2_internal.h" | ||
28 | #include "motion_comp.h" | ||
29 | |||
30 | /* definitions of the actual mc functions */ | ||
31 | |||
32 | /* MC_FUNC (put, o) <= ASM */ | ||
33 | MC_FUNC (avg, o) | ||
34 | /* MC_FUNC (put, x) <= ASM */ | ||
35 | MC_FUNC (avg, x) | ||
36 | MC_FUNC (put, y) | ||
37 | MC_FUNC (avg, y) | ||
38 | MC_FUNC (put, xy) | ||
39 | MC_FUNC (avg, xy) | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/motion_comp_arm_s.S b/apps/plugins/mpegplayer/libmpeg2/motion_comp_arm_s.S deleted file mode 100644 index 1ec1b0686e..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/motion_comp_arm_s.S +++ /dev/null | |||
@@ -1,342 +0,0 @@ | |||
1 | @ motion_comp_arm_s.S | ||
2 | @ Copyright (C) 2004 AGAWA Koji <i (AT) atty (DOT) jp> | ||
3 | @ | ||
4 | @ This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
5 | @ See http://libmpeg2.sourceforge.net/ for updates. | ||
6 | @ | ||
7 | @ mpeg2dec is free software; you can redistribute it and/or modify | ||
8 | @ it under the terms of the GNU General Public License as published by | ||
9 | @ the Free Software Foundation; either version 2 of the License, or | ||
10 | @ (at your option) any later version. | ||
11 | @ | ||
12 | @ mpeg2dec is distributed in the hope that it will be useful, | ||
13 | @ but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | @ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | @ GNU General Public License for more details. | ||
16 | @ | ||
17 | @ You should have received a copy of the GNU General Public License | ||
18 | @ along with this program; if not, write to the Free Software | ||
19 | @ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | @ | ||
21 | @ $Id$ | ||
22 | |||
23 | #include "config.h" /* Rockbox: ARM architecture version */ | ||
24 | |||
25 | .text | ||
26 | |||
27 | @ ---------------------------------------------------------------- | ||
28 | .align | ||
29 | .global MC_put_o_16 | ||
30 | MC_put_o_16: | ||
31 | @@ void func(uint8_t * dest, const uint8_t * ref, int stride, int height) | ||
32 | @@ pld [r1] | ||
33 | stmfd sp!, {r4-r7, lr} @ R14 is also called LR | ||
34 | and r4, r1, #3 | ||
35 | ldr pc, [pc, r4, lsl #2] | ||
36 | .word 0 | ||
37 | .word MC_put_o_16_align0 | ||
38 | .word MC_put_o_16_align1 | ||
39 | .word MC_put_o_16_align2 | ||
40 | .word MC_put_o_16_align3 | ||
41 | |||
42 | MC_put_o_16_align0: | ||
43 | ldmia r1, {r4-r7} | ||
44 | add r1, r1, r2 | ||
45 | @@ pld [r1] | ||
46 | stmia r0, {r4-r7} | ||
47 | subs r3, r3, #1 | ||
48 | add r0, r0, r2 | ||
49 | bne MC_put_o_16_align0 | ||
50 | ldmpc regs=r4-r7 @@ update PC with LR content. | ||
51 | |||
52 | .macro ADJ_ALIGN_QW shift, R0, R1, R2, R3, R4 | ||
53 | mov \R0, \R0, lsr #(\shift) | ||
54 | orr \R0, \R0, \R1, lsl #(32 - \shift) | ||
55 | mov \R1, \R1, lsr #(\shift) | ||
56 | orr \R1, \R1, \R2, lsl #(32 - \shift) | ||
57 | mov \R2, \R2, lsr #(\shift) | ||
58 | orr \R2, \R2, \R3, lsl #(32 - \shift) | ||
59 | mov \R3, \R3, lsr #(\shift) | ||
60 | orr \R3, \R3, \R4, lsl #(32 - \shift) | ||
61 | mov \R4, \R4, lsr #(\shift) | ||
62 | .endm | ||
63 | |||
64 | MC_put_o_16_align1: | ||
65 | and r1, r1, #0xFFFFFFFC | ||
66 | 1: ldmia r1, {r4-r7, r12} | ||
67 | add r1, r1, r2 | ||
68 | @@ pld [r1] | ||
69 | ADJ_ALIGN_QW 8, r4, r5, r6, r7, r12 | ||
70 | stmia r0, {r4-r7} | ||
71 | subs r3, r3, #1 | ||
72 | add r0, r0, r2 | ||
73 | bne 1b | ||
74 | ldmpc regs=r4-r7 @@ update PC with LR content. | ||
75 | |||
76 | MC_put_o_16_align2: | ||
77 | and r1, r1, #0xFFFFFFFC | ||
78 | 1: ldmia r1, {r4-r7, r12} | ||
79 | add r1, r1, r2 | ||
80 | @@ pld [r1] | ||
81 | ADJ_ALIGN_QW 16, r4, r5, r6, r7, r12 | ||
82 | stmia r0, {r4-r7} | ||
83 | subs r3, r3, #1 | ||
84 | add r0, r0, r2 | ||
85 | bne 1b | ||
86 | ldmpc regs=r4-r7 @@ update PC with LR content. | ||
87 | |||
88 | MC_put_o_16_align3: | ||
89 | and r1, r1, #0xFFFFFFFC | ||
90 | 1: ldmia r1, {r4-r7, r12} | ||
91 | add r1, r1, r2 | ||
92 | @@ pld [r1] | ||
93 | ADJ_ALIGN_QW 24, r4, r5, r6, r7, r12 | ||
94 | stmia r0, {r4-r7} | ||
95 | subs r3, r3, #1 | ||
96 | add r0, r0, r2 | ||
97 | bne 1b | ||
98 | ldmpc regs=r4-r7 @@ update PC with LR content. | ||
99 | |||
100 | @ ---------------------------------------------------------------- | ||
101 | .align | ||
102 | .global MC_put_o_8 | ||
103 | MC_put_o_8: | ||
104 | @@ void func(uint8_t * dest, const uint8_t * ref, int stride, int height) | ||
105 | @@ pld [r1] | ||
106 | stmfd sp!, {r4, r5, lr} @ R14 is also called LR | ||
107 | and r4, r1, #3 | ||
108 | ldr pc, [pc, r4, lsl #2] | ||
109 | .word 0 | ||
110 | .word MC_put_o_8_align0 | ||
111 | .word MC_put_o_8_align1 | ||
112 | .word MC_put_o_8_align2 | ||
113 | .word MC_put_o_8_align3 | ||
114 | |||
115 | MC_put_o_8_align0: | ||
116 | ldmia r1, {r4, r5} | ||
117 | add r1, r1, r2 | ||
118 | @@ pld [r1] | ||
119 | stmia r0, {r4, r5} | ||
120 | add r0, r0, r2 | ||
121 | subs r3, r3, #1 | ||
122 | bne MC_put_o_8_align0 | ||
123 | ldmpc regs=r4-r5 @@ update PC with LR content. | ||
124 | |||
125 | .macro ADJ_ALIGN_DW shift, R0, R1, R2 | ||
126 | mov \R0, \R0, lsr #(\shift) | ||
127 | orr \R0, \R0, \R1, lsl #(32 - \shift) | ||
128 | mov \R1, \R1, lsr #(\shift) | ||
129 | orr \R1, \R1, \R2, lsl #(32 - \shift) | ||
130 | mov \R2, \R2, lsr #(\shift) | ||
131 | .endm | ||
132 | |||
133 | MC_put_o_8_align1: | ||
134 | and r1, r1, #0xFFFFFFFC | ||
135 | 1: ldmia r1, {r4, r5, r12} | ||
136 | add r1, r1, r2 | ||
137 | @@ pld [r1] | ||
138 | ADJ_ALIGN_DW 8, r4, r5, r12 | ||
139 | stmia r0, {r4, r5} | ||
140 | subs r3, r3, #1 | ||
141 | add r0, r0, r2 | ||
142 | bne 1b | ||
143 | ldmpc regs=r4-r5 @@ update PC with LR content. | ||
144 | |||
145 | MC_put_o_8_align2: | ||
146 | and r1, r1, #0xFFFFFFFC | ||
147 | 1: ldmia r1, {r4, r5, r12} | ||
148 | add r1, r1, r2 | ||
149 | @@ pld [r1] | ||
150 | ADJ_ALIGN_DW 16, r4, r5, r12 | ||
151 | stmia r0, {r4, r5} | ||
152 | subs r3, r3, #1 | ||
153 | add r0, r0, r2 | ||
154 | bne 1b | ||
155 | ldmpc regs=r4-r5 @@ update PC with LR content. | ||
156 | |||
157 | MC_put_o_8_align3: | ||
158 | and r1, r1, #0xFFFFFFFC | ||
159 | 1: ldmia r1, {r4, r5, r12} | ||
160 | add r1, r1, r2 | ||
161 | @@ pld [r1] | ||
162 | ADJ_ALIGN_DW 24, r4, r5, r12 | ||
163 | stmia r0, {r4, r5} | ||
164 | subs r3, r3, #1 | ||
165 | add r0, r0, r2 | ||
166 | bne 1b | ||
167 | ldmpc regs=r4-r5 @@ update PC with LR content. | ||
168 | |||
169 | @ ---------------------------------------------------------------- | ||
170 | .macro AVG_PW rW1, rW2 | ||
171 | mov \rW2, \rW2, lsl #24 | ||
172 | orr \rW2, \rW2, \rW1, lsr #8 | ||
173 | eor r9, \rW1, \rW2 | ||
174 | #if ARM_ARCH >= 6 | ||
175 | uhadd8 \rW2, \rW1, \rW2 | ||
176 | #else | ||
177 | and \rW2, \rW1, \rW2 | ||
178 | and r10, r9, r11 | ||
179 | add \rW2, \rW2, r10, lsr #1 | ||
180 | #endif | ||
181 | and r9, r9, r12 | ||
182 | add \rW2, \rW2, r9 | ||
183 | .endm | ||
184 | |||
185 | #if ARM_ARCH >= 6 | ||
186 | #define HIGHEST_REG r9 | ||
187 | #else | ||
188 | #define HIGHEST_REG r11 | ||
189 | #endif | ||
190 | |||
191 | .align | ||
192 | .global MC_put_x_16 | ||
193 | MC_put_x_16: | ||
194 | @@ void func(uint8_t * dest, const uint8_t * ref, int stride, int height) | ||
195 | @@ pld [r1] | ||
196 | stmfd sp!, {r4-HIGHEST_REG, lr} @ R14 is also called LR | ||
197 | and r4, r1, #3 | ||
198 | ldr r12, 2f | ||
199 | #if ARM_ARCH < 6 | ||
200 | mvn r11, r12 | ||
201 | #endif | ||
202 | ldr pc, [pc, r4, lsl #2] | ||
203 | 2: .word 0x01010101 | ||
204 | .word MC_put_x_16_align0 | ||
205 | .word MC_put_x_16_align1 | ||
206 | .word MC_put_x_16_align2 | ||
207 | .word MC_put_x_16_align3 | ||
208 | |||
209 | MC_put_x_16_align0: | ||
210 | ldmia r1, {r4-r8} | ||
211 | add r1, r1, r2 | ||
212 | @@ pld [r1] | ||
213 | AVG_PW r7, r8 | ||
214 | AVG_PW r6, r7 | ||
215 | AVG_PW r5, r6 | ||
216 | AVG_PW r4, r5 | ||
217 | stmia r0, {r5-r8} | ||
218 | subs r3, r3, #1 | ||
219 | add r0, r0, r2 | ||
220 | bne MC_put_x_16_align0 | ||
221 | ldmpc regs=r4-HIGHEST_REG @@ update PC with LR content. | ||
222 | |||
223 | MC_put_x_16_align1: | ||
224 | and r1, r1, #0xFFFFFFFC | ||
225 | 1: ldmia r1, {r4-r8} | ||
226 | add r1, r1, r2 | ||
227 | @@ pld [r1] | ||
228 | ADJ_ALIGN_QW 8, r4, r5, r6, r7, r8 | ||
229 | AVG_PW r7, r8 | ||
230 | AVG_PW r6, r7 | ||
231 | AVG_PW r5, r6 | ||
232 | AVG_PW r4, r5 | ||
233 | stmia r0, {r5-r8} | ||
234 | subs r3, r3, #1 | ||
235 | add r0, r0, r2 | ||
236 | bne 1b | ||
237 | ldmpc regs=r4-HIGHEST_REG @@ update PC with LR content. | ||
238 | |||
239 | MC_put_x_16_align2: | ||
240 | and r1, r1, #0xFFFFFFFC | ||
241 | 1: ldmia r1, {r4-r8} | ||
242 | add r1, r1, r2 | ||
243 | @@ pld [r1] | ||
244 | ADJ_ALIGN_QW 16, r4, r5, r6, r7, r8 | ||
245 | AVG_PW r7, r8 | ||
246 | AVG_PW r6, r7 | ||
247 | AVG_PW r5, r6 | ||
248 | AVG_PW r4, r5 | ||
249 | stmia r0, {r5-r8} | ||
250 | subs r3, r3, #1 | ||
251 | add r0, r0, r2 | ||
252 | bne 1b | ||
253 | ldmpc regs=r4-HIGHEST_REG @@ update PC with LR content. | ||
254 | |||
255 | MC_put_x_16_align3: | ||
256 | and r1, r1, #0xFFFFFFFC | ||
257 | 1: ldmia r1, {r4-r8} | ||
258 | add r1, r1, r2 | ||
259 | @@ pld [r1] | ||
260 | ADJ_ALIGN_QW 24, r4, r5, r6, r7, r8 | ||
261 | AVG_PW r7, r8 | ||
262 | AVG_PW r6, r7 | ||
263 | AVG_PW r5, r6 | ||
264 | AVG_PW r4, r5 | ||
265 | stmia r0, {r5-r8} | ||
266 | subs r3, r3, #1 | ||
267 | add r0, r0, r2 | ||
268 | bne 1b | ||
269 | ldmpc regs=r4-HIGHEST_REG @@ update PC with LR content. | ||
270 | |||
271 | @ ---------------------------------------------------------------- | ||
272 | .align | ||
273 | .global MC_put_x_8 | ||
274 | MC_put_x_8: | ||
275 | @@ void func(uint8_t * dest, const uint8_t * ref, int stride, int height) | ||
276 | @@ pld [r1] | ||
277 | stmfd sp!, {r6-HIGHEST_REG, lr} @ R14 is also called LR | ||
278 | and r6, r1, #3 | ||
279 | ldr r12, 2f | ||
280 | #if ARM_ARCH < 6 | ||
281 | mvn r11, r12 | ||
282 | #endif | ||
283 | ldr pc, [pc, r6, lsl #2] | ||
284 | 2: .word 0x01010101 | ||
285 | .word MC_put_x_8_align0 | ||
286 | .word MC_put_x_8_align1 | ||
287 | .word MC_put_x_8_align2 | ||
288 | .word MC_put_x_8_align3 | ||
289 | |||
290 | MC_put_x_8_align0: | ||
291 | ldmia r1, {r6-r8} | ||
292 | add r1, r1, r2 | ||
293 | @@ pld [r1] | ||
294 | AVG_PW r7, r8 | ||
295 | AVG_PW r6, r7 | ||
296 | stmia r0, {r7-r8} | ||
297 | subs r3, r3, #1 | ||
298 | add r0, r0, r2 | ||
299 | bne MC_put_x_8_align0 | ||
300 | ldmpc regs=r6-HIGHEST_REG @@ update PC with LR content. | ||
301 | |||
302 | MC_put_x_8_align1: | ||
303 | and r1, r1, #0xFFFFFFFC | ||
304 | 1: ldmia r1, {r6-r8} | ||
305 | add r1, r1, r2 | ||
306 | @@ pld [r1] | ||
307 | ADJ_ALIGN_DW 8, r6, r7, r8 | ||
308 | AVG_PW r7, r8 | ||
309 | AVG_PW r6, r7 | ||
310 | stmia r0, {r7-r8} | ||
311 | subs r3, r3, #1 | ||
312 | add r0, r0, r2 | ||
313 | bne 1b | ||
314 | ldmpc regs=r6-HIGHEST_REG @@ update PC with LR content. | ||
315 | |||
316 | MC_put_x_8_align2: | ||
317 | and r1, r1, #0xFFFFFFFC | ||
318 | 1: ldmia r1, {r6-r8} | ||
319 | add r1, r1, r2 | ||
320 | @@ pld [r1] | ||
321 | ADJ_ALIGN_DW 16, r6, r7, r8 | ||
322 | AVG_PW r7, r8 | ||
323 | AVG_PW r6, r7 | ||
324 | stmia r0, {r7-r8} | ||
325 | subs r3, r3, #1 | ||
326 | add r0, r0, r2 | ||
327 | bne 1b | ||
328 | ldmpc regs=r6-HIGHEST_REG @@ update PC with LR content. | ||
329 | |||
330 | MC_put_x_8_align3: | ||
331 | and r1, r1, #0xFFFFFFFC | ||
332 | 1: ldmia r1, {r6-r8} | ||
333 | add r1, r1, r2 | ||
334 | @@ pld [r1] | ||
335 | ADJ_ALIGN_DW 24, r6, r7, r8 | ||
336 | AVG_PW r7, r8 | ||
337 | AVG_PW r6, r7 | ||
338 | stmia r0, {r7-r8} | ||
339 | subs r3, r3, #1 | ||
340 | add r0, r0, r2 | ||
341 | bne 1b | ||
342 | ldmpc regs=r6-HIGHEST_REG @@ update PC with LR content. | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/motion_comp_c.c b/apps/plugins/mpegplayer/libmpeg2/motion_comp_c.c deleted file mode 100644 index 9a8640e7e6..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/motion_comp_c.c +++ /dev/null | |||
@@ -1,40 +0,0 @@ | |||
1 | /* | ||
2 | * motion_comp.c | ||
3 | * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> | ||
4 | * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> | ||
5 | * | ||
6 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
7 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
8 | * | ||
9 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * mpeg2dec is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | * $Id$ | ||
24 | */ | ||
25 | #include <inttypes.h> | ||
26 | #include "mpeg2.h" | ||
27 | #include "attributes.h" | ||
28 | #include "mpeg2_internal.h" | ||
29 | #include "motion_comp.h" | ||
30 | |||
31 | /* definitions of the actual mc functions */ | ||
32 | |||
33 | MC_FUNC (put, o) | ||
34 | MC_FUNC (avg, o) | ||
35 | MC_FUNC (put, x) | ||
36 | MC_FUNC (avg, x) | ||
37 | MC_FUNC (put, y) | ||
38 | MC_FUNC (avg, y) | ||
39 | MC_FUNC (put, xy) | ||
40 | MC_FUNC (avg, xy) | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/motion_comp_coldfire_c.c b/apps/plugins/mpegplayer/libmpeg2/motion_comp_coldfire_c.c deleted file mode 100644 index b97e3510e7..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/motion_comp_coldfire_c.c +++ /dev/null | |||
@@ -1,38 +0,0 @@ | |||
1 | /* | ||
2 | * Based on: | ||
3 | * motion_comp_arm.c | ||
4 | * Copyright (C) 2004 AGAWA Koji <i (AT) atty (DOT) jp> | ||
5 | * | ||
6 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
7 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
8 | * | ||
9 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * mpeg2dec is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | #include <inttypes.h> | ||
24 | #include "mpeg2.h" | ||
25 | #include "attributes.h" | ||
26 | #include "mpeg2_internal.h" | ||
27 | #include "motion_comp.h" | ||
28 | |||
29 | /* definitions of the actual mc functions */ | ||
30 | |||
31 | /* MC_FUNC (put, o) <= ASM */ | ||
32 | MC_FUNC (avg, o) | ||
33 | /* MC_FUNC (put, x) <= ASM */ | ||
34 | MC_FUNC (avg, x) | ||
35 | MC_FUNC (put, y) | ||
36 | MC_FUNC (avg, y) | ||
37 | MC_FUNC (put, xy) | ||
38 | MC_FUNC (avg, xy) | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/motion_comp_coldfire_s.S b/apps/plugins/mpegplayer/libmpeg2/motion_comp_coldfire_s.S deleted file mode 100644 index 55d87cb708..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/motion_comp_coldfire_s.S +++ /dev/null | |||
@@ -1,436 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 Jens Arnold | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | .macro LEFT8_PW dW1, dW2 | needs %d0 == 24, clobbers %d2 | ||
23 | lsl.l #8, \dW1 | changes dW1, keeps dW2 | ||
24 | move.l \dW2, %d2 | ||
25 | lsr.l %d0, %d2 | ||
26 | or.l %d2, \dW1 | ||
27 | .endm | ||
28 | |||
29 | .macro LEFT24_PW dW1, dW2 | needs %d0 == 24, clobbers %d2 | ||
30 | lsl.l %d0, \dW1 | changes dW1, keeps dW2 | ||
31 | move.l \dW2, %d2 | ||
32 | lsr.l #8, %d2 | ||
33 | or.l %d2, \dW1 | ||
34 | .endm | ||
35 | |||
36 | /*****************************************************************************/ | ||
37 | |||
38 | .align 2 | ||
39 | .global MC_put_o_8 | ||
40 | .type MC_put_o_8, @function | ||
41 | |||
42 | MC_put_o_8: | ||
43 | movem.l (4,%sp), %a0-%a1 | dest, source | ||
44 | move.l %a1, %d0 | ||
45 | and.l #3, %d0 | ||
46 | sub.l %d0, %a1 | align source | ||
47 | jmp.l (2, %pc, %d0.l*4) | ||
48 | bra.w .po8_0 | ||
49 | bra.w .po8_1 | ||
50 | bra.w .po8_2 | ||
51 | | last table entry coincides with target | ||
52 | |||
53 | .po8_3: | ||
54 | lea.l (-5*4,%sp), %sp | ||
55 | movem.l %d2-%d5/%a2, (%sp) | save some registers | ||
56 | move.l (5*4+12,%sp), %a2 | stride | ||
57 | move.l (5*4+16,%sp), %d1 | height | ||
58 | moveq.l #24, %d0 | shift amount | ||
59 | 1: | ||
60 | movem.l (%a1), %d3-%d5 | ||
61 | add.l %a2, %a1 | ||
62 | LEFT24_PW %d3, %d4 | ||
63 | lsl.l %d0, %d4 | ||
64 | lsr.l #8, %d5 | ||
65 | or.l %d5, %d4 | ||
66 | movem.l %d3-%d4, (%a0) | ||
67 | add.l %a2, %a0 | ||
68 | subq.l #1, %d1 | ||
69 | bne.s 1b | ||
70 | movem.l (%sp), %d2-%d5/%a2 | ||
71 | lea.l (5*4,%sp), %sp | ||
72 | rts | ||
73 | |||
74 | .po8_2: | ||
75 | lea.l (-3*4,%sp), %sp | ||
76 | movem.l %d2-%d4, (%sp) | save some registers | ||
77 | movem.l (3*4+12,%sp), %d0-%d1 | stride, height | ||
78 | 1: | ||
79 | movem.l (%a1), %d2-%d4 | ||
80 | add.l %d0, %a1 | ||
81 | swap %d2 | ||
82 | swap %d3 | ||
83 | move.w %d3, %d2 | ||
84 | swap %d4 | ||
85 | move.w %d4, %d3 | ||
86 | movem.l %d2-%d3, (%a0) | ||
87 | add.l %d0, %a0 | ||
88 | subq.l #1, %d1 | ||
89 | bne.s 1b | ||
90 | movem.l (%sp), %d2-%d4 | ||
91 | lea.l (3*4,%sp), %sp | ||
92 | rts | ||
93 | |||
94 | .po8_1: | ||
95 | lea.l (-5*4,%sp), %sp | ||
96 | movem.l %d2-%d5/%a2, (%sp) | save some registers | ||
97 | move.l (5*4+12,%sp), %a2 | stride | ||
98 | move.l (5*4+16,%sp), %d1 | height | ||
99 | moveq.l #24, %d0 | shift amount | ||
100 | 1: | ||
101 | movem.l (%a1), %d3-%d5 | ||
102 | add.l %a2, %a1 | ||
103 | LEFT8_PW %d3, %d4 | ||
104 | lsl.l #8, %d4 | ||
105 | lsr.l %d0, %d5 | ||
106 | or.l %d5, %d4 | ||
107 | movem.l %d3-%d4, (%a0) | ||
108 | add.l %a2, %a0 | ||
109 | subq.l #1, %d1 | ||
110 | bne.s 1b | ||
111 | movem.l (%sp), %d2-%d5/%a2 | ||
112 | lea.l (5*4,%sp), %sp | ||
113 | rts | ||
114 | |||
115 | .po8_0: | ||
116 | movem.l (12,%sp), %d0-%d1 | stride, height | ||
117 | subq.l #4, %d0 | adjust for increment within the loop | ||
118 | 1: | ||
119 | move.l (%a1)+, (%a0)+ | ||
120 | move.l (%a1), (%a0) | ||
121 | add.l %d0, %a0 | ||
122 | add.l %d0, %a1 | ||
123 | subq.l #1, %d1 | ||
124 | bne.s 1b | ||
125 | rts | ||
126 | |||
127 | /*****************************************************************************/ | ||
128 | |||
129 | .align 2 | ||
130 | .global MC_put_o_16 | ||
131 | .type MC_put_o_16, @function | ||
132 | |||
133 | MC_put_o_16: | ||
134 | lea.l (-7*4,%sp), %sp | ||
135 | movem.l %d2-%d7/%a2, (%sp) | save some registers | ||
136 | movem.l (7*4+4,%sp), %a0-%a2| dest, source, stride | ||
137 | move.l (7*4+16,%sp), %d1 | height | ||
138 | move.l %a1, %d0 | ||
139 | and.l #3, %d0 | ||
140 | sub.l %d0, %a1 | ||
141 | jmp.l (2, %pc, %d0.l*4) | ||
142 | bra.w .po16_0 | ||
143 | bra.w .po16_1 | ||
144 | bra.w .po16_2 | ||
145 | | last table entry coincides with target | ||
146 | |||
147 | .po16_3: | ||
148 | moveq.l #24, %d0 | shift amount | ||
149 | 1: | ||
150 | movem.l (%a1), %d3-%d7 | ||
151 | add.l %a2, %a1 | ||
152 | LEFT24_PW %d3, %d4 | ||
153 | LEFT24_PW %d4, %d5 | ||
154 | LEFT24_PW %d5, %d6 | ||
155 | lsl.l %d0, %d6 | ||
156 | lsr.l #8, %d7 | ||
157 | or.l %d7, %d6 | ||
158 | movem.l %d3-%d6, (%a0) | ||
159 | add.l %a2, %a0 | ||
160 | subq.l #1, %d1 | ||
161 | bne.s 1b | ||
162 | movem.l (%sp), %d2-%d7/%a2 | ||
163 | lea.l (7*4,%sp), %sp | ||
164 | rts | ||
165 | |||
166 | .po16_2: | ||
167 | 1: | ||
168 | movem.l (%a1), %d3-%d7 | ||
169 | add.l %a2, %a1 | ||
170 | swap %d3 | ||
171 | swap %d4 | ||
172 | move.w %d4, %d3 | ||
173 | swap %d5 | ||
174 | move.w %d5, %d4 | ||
175 | swap %d6 | ||
176 | move.w %d6, %d5 | ||
177 | swap %d7 | ||
178 | move.w %d7, %d6 | ||
179 | movem.l %d3-%d6, (%a0) | ||
180 | add.l %a2, %a0 | ||
181 | subq.l #1, %d1 | ||
182 | bne.s 1b | ||
183 | movem.l (%sp), %d2-%d7/%a2 | ||
184 | lea.l (7*4,%sp), %sp | ||
185 | rts | ||
186 | |||
187 | .po16_1: | ||
188 | moveq.l #24, %d0 | shift amount | ||
189 | 1: | ||
190 | movem.l (%a1), %d3-%d7 | ||
191 | add.l %a2, %a1 | ||
192 | LEFT8_PW %d3, %d4 | ||
193 | LEFT8_PW %d4, %d5 | ||
194 | LEFT8_PW %d5, %d6 | ||
195 | lsl.l #8, %d6 | ||
196 | lsr.l %d0, %d7 | ||
197 | or.l %d7, %d6 | ||
198 | movem.l %d3-%d6, (%a0) | ||
199 | add.l %a2, %a0 | ||
200 | subq.l #1, %d1 | ||
201 | bne.s 1b | ||
202 | movem.l (%sp), %d2-%d7/%a2 | ||
203 | lea.l (7*4,%sp), %sp | ||
204 | rts | ||
205 | |||
206 | .po16_0: | ||
207 | 1: | ||
208 | movem.l (%a1), %d3-%d6 | ||
209 | add.l %a2, %a1 | ||
210 | movem.l %d3-%d6, (%a0) | ||
211 | add.l %a2, %a0 | ||
212 | subq.l #1, %d1 | ||
213 | bne.s 1b | ||
214 | movem.l (%sp), %d2-%d7/%a2 | ||
215 | lea.l (7*4,%sp), %sp | ||
216 | rts | ||
217 | |||
218 | /*****************************************************************************/ | ||
219 | |||
220 | .macro AVG_PW dW1, dW2 | needs %d0 == 24, clobbers %d1, %d2, | ||
221 | move.l \dW1, %d1 | changes dW1, keeps dW2 | ||
222 | lsl.l #8, \dW1 | ||
223 | move.l \dW2, %d2 | ||
224 | lsr.l %d0, %d2 | ||
225 | or.l %d2, \dW1 | ||
226 | move.l %d1, %d2 | ||
227 | eor.l \dW1, %d1 | ||
228 | and.l %d2, \dW1 | ||
229 | move.l #0xfefefefe, %d2 | ||
230 | and.l %d1, %d2 | ||
231 | eor.l %d2, %d1 | ||
232 | lsr.l #1, %d2 | ||
233 | add.l %d2, \dW1 | ||
234 | add.l %d1, \dW1 | ||
235 | .endm | ||
236 | |||
237 | /*****************************************************************************/ | ||
238 | |||
239 | .align 2 | ||
240 | .global MC_put_x_8 | ||
241 | .type MC_put_x_8, @function | ||
242 | |||
243 | MC_put_x_8: | ||
244 | lea.l (-6*4,%sp), %sp | ||
245 | movem.l %d2-%d6/%a2, (%sp) | save some registers | ||
246 | movem.l (6*4+4,%sp), %a0-%a2| dest, source, stride | ||
247 | move.l (6*4+16,%sp), %d6 | height | ||
248 | move.l %a1, %d0 | ||
249 | and.l #3, %d0 | ||
250 | sub.l %d0, %a1 | ||
251 | jmp.l (2, %pc, %d0.l*4) | ||
252 | bra.w .px8_0 | ||
253 | bra.w .px8_1 | ||
254 | bra.w .px8_2 | ||
255 | | last table entry coincides with target | ||
256 | |||
257 | .px8_3: | ||
258 | moveq.l #24, %d0 | ||
259 | 1: | ||
260 | movem.l (%a1), %d3-%d5 | ||
261 | add.l %a2, %a1 | ||
262 | LEFT24_PW %d3, %d4 | ||
263 | LEFT24_PW %d4, %d5 | ||
264 | lsl.l %d0, %d5 | ||
265 | AVG_PW %d3, %d4 | ||
266 | AVG_PW %d4, %d5 | ||
267 | movem.l %d3-%d4, (%a0) | ||
268 | add.l %a2, %a0 | ||
269 | subq.l #1, %d6 | ||
270 | bne.s 1b | ||
271 | movem.l (%sp), %d2-%d6/%a2 | ||
272 | lea.l (6*4,%sp), %sp | ||
273 | rts | ||
274 | |||
275 | .px8_2: | ||
276 | moveq.l #24, %d0 | ||
277 | 1: | ||
278 | movem.l (%a1), %d3-%d5 | ||
279 | add.l %a2, %a1 | ||
280 | swap %d3 | ||
281 | swap %d4 | ||
282 | move.w %d4, %d3 | ||
283 | swap %d5 | ||
284 | move.w %d5, %d4 | ||
285 | AVG_PW %d3, %d4 | ||
286 | AVG_PW %d4, %d5 | ||
287 | movem.l %d3-%d4, (%a0) | ||
288 | add.l %a2, %a0 | ||
289 | subq.l #1, %d6 | ||
290 | bne.s 1b | ||
291 | movem.l (%sp), %d2-%d6/%a2 | ||
292 | lea.l (6*4,%sp), %sp | ||
293 | rts | ||
294 | |||
295 | .px8_1: | ||
296 | moveq.l #24, %d0 | ||
297 | 1: | ||
298 | movem.l (%a1), %d3-%d5 | ||
299 | add.l %a2, %a1 | ||
300 | LEFT8_PW %d3, %d4 | ||
301 | LEFT8_PW %d4, %d5 | ||
302 | lsl.l #8, %d5 | ||
303 | AVG_PW %d3, %d4 | ||
304 | AVG_PW %d4, %d5 | ||
305 | movem.l %d3-%d4, (%a0) | ||
306 | add.l %a2, %a0 | ||
307 | subq.l #1, %d6 | ||
308 | bne.s 1b | ||
309 | movem.l (%sp), %d2-%d6/%a2 | ||
310 | lea.l (6*4,%sp), %sp | ||
311 | rts | ||
312 | |||
313 | .px8_0: | ||
314 | moveq.l #24, %d0 | ||
315 | 1: | ||
316 | movem.l (%a1), %d3-%d5 | ||
317 | add.l %a2, %a1 | ||
318 | AVG_PW %d3, %d4 | ||
319 | AVG_PW %d4, %d5 | ||
320 | movem.l %d3-%d4, (%a0) | ||
321 | add.l %a2, %a0 | ||
322 | subq.l #1, %d6 | ||
323 | bne.s 1b | ||
324 | movem.l (%sp), %d2-%d6/%a2 | ||
325 | lea.l (6*4,%sp), %sp | ||
326 | rts | ||
327 | |||
328 | /*****************************************************************************/ | ||
329 | |||
330 | .align 2 | ||
331 | .global MC_put_x_16 | ||
332 | .type MC_put_x_16, @function | ||
333 | |||
334 | MC_put_x_16: | ||
335 | lea.l (-8*4,%sp), %sp | ||
336 | movem.l %d2-%d7/%a2-%a3, (%sp) | save some registers | ||
337 | movem.l (8*4+4,%sp), %a0-%a3 | dest, source, stride, height | ||
338 | move.l %a1, %d0 | ||
339 | and.l #3, %d0 | ||
340 | sub.l %d0, %a1 | ||
341 | jmp.l (2, %pc, %d0.l*4) | ||
342 | bra.w .px16_0 | ||
343 | bra.w .px16_1 | ||
344 | bra.w .px16_2 | ||
345 | | last table entry coincides with target | ||
346 | |||
347 | .px16_3: | ||
348 | moveq.l #24, %d0 | ||
349 | 1: | ||
350 | movem.l (%a1), %d3-%d7 | ||
351 | add.l %a2, %a1 | ||
352 | LEFT24_PW %d3, %d4 | ||
353 | LEFT24_PW %d4, %d5 | ||
354 | LEFT24_PW %d5, %d6 | ||
355 | LEFT24_PW %d6, %d7 | ||
356 | lsl.l %d0, %d7 | ||
357 | AVG_PW %d3, %d4 | ||
358 | AVG_PW %d4, %d5 | ||
359 | AVG_PW %d5, %d6 | ||
360 | AVG_PW %d6, %d7 | ||
361 | movem.l %d3-%d6, (%a0) | ||
362 | add.l %a2, %a0 | ||
363 | subq.l #1, %a3 | ||
364 | tst.l %a3 | ||
365 | bne.w 1b | ||
366 | movem.l (%sp), %d2-%d7/%a2-%a3 | ||
367 | lea.l (8*4,%sp), %sp | ||
368 | rts | ||
369 | |||
370 | .px16_2: | ||
371 | moveq.l #24, %d0 | ||
372 | 1: | ||
373 | movem.l (%a1), %d3-%d7 | ||
374 | add.l %a2, %a1 | ||
375 | swap %d3 | ||
376 | swap %d4 | ||
377 | move.w %d4, %d3 | ||
378 | swap %d5 | ||
379 | move.w %d5, %d4 | ||
380 | swap %d6 | ||
381 | move.w %d6, %d5 | ||
382 | swap %d7 | ||
383 | move.w %d7, %d6 | ||
384 | AVG_PW %d3, %d4 | ||
385 | AVG_PW %d4, %d5 | ||
386 | AVG_PW %d5, %d6 | ||
387 | AVG_PW %d6, %d7 | ||
388 | movem.l %d3-%d6, (%a0) | ||
389 | add.l %a2, %a0 | ||
390 | subq.l #1, %a3 | ||
391 | tst.l %a3 | ||
392 | bne.w 1b | ||
393 | movem.l (%sp), %d2-%d7/%a2-%a3 | ||
394 | lea.l (8*4,%sp), %sp | ||
395 | rts | ||
396 | |||
397 | .px16_1: | ||
398 | moveq.l #24, %d0 | ||
399 | 1: | ||
400 | movem.l (%a1), %d3-%d7 | ||
401 | add.l %a2, %a1 | ||
402 | LEFT8_PW %d3, %d4 | ||
403 | LEFT8_PW %d4, %d5 | ||
404 | LEFT8_PW %d5, %d6 | ||
405 | LEFT8_PW %d6, %d7 | ||
406 | lsl.l #8, %d7 | ||
407 | AVG_PW %d3, %d4 | ||
408 | AVG_PW %d4, %d5 | ||
409 | AVG_PW %d5, %d6 | ||
410 | AVG_PW %d6, %d7 | ||
411 | movem.l %d3-%d6, (%a0) | ||
412 | add.l %a2, %a0 | ||
413 | subq.l #1, %a3 | ||
414 | tst.l %a3 | ||
415 | bne.w 1b | ||
416 | movem.l (%sp), %d2-%d7/%a2-%a3 | ||
417 | lea.l (8*4,%sp), %sp | ||
418 | rts | ||
419 | |||
420 | .px16_0: | ||
421 | moveq.l #24, %d0 | ||
422 | 1: | ||
423 | movem.l (%a1), %d3-%d7 | ||
424 | add.l %a2, %a1 | ||
425 | AVG_PW %d3, %d4 | ||
426 | AVG_PW %d4, %d5 | ||
427 | AVG_PW %d5, %d6 | ||
428 | AVG_PW %d6, %d7 | ||
429 | movem.l %d3-%d6, (%a0) | ||
430 | add.l %a2, %a0 | ||
431 | subq.l #1, %a3 | ||
432 | tst.l %a3 | ||
433 | bne.w 1b | ||
434 | movem.l (%sp), %d2-%d7/%a2-%a3 | ||
435 | lea.l (8*4,%sp), %sp | ||
436 | rts | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/mpeg2.h b/apps/plugins/mpegplayer/libmpeg2/mpeg2.h deleted file mode 100644 index bd14ead96e..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/mpeg2.h +++ /dev/null | |||
@@ -1,223 +0,0 @@ | |||
1 | /* | ||
2 | * mpeg2.h | ||
3 | * Copyright (C) 2000-2004 Michel Lespinasse <walken@zoy.org> | ||
4 | * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> | ||
5 | * | ||
6 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
7 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
8 | * | ||
9 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * mpeg2dec is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | * $Id$ | ||
24 | * libmpeg2 sync history: | ||
25 | * 2008-07-01 - CVS revision 1.67 | ||
26 | */ | ||
27 | |||
28 | #ifndef MPEG2_H | ||
29 | #define MPEG2_H | ||
30 | |||
31 | #include "mpeg2dec_config.h" | ||
32 | |||
33 | #define MPEG2_VERSION(a,b,c) (((a)<<16)|((b)<<8)|(c)) | ||
34 | #define MPEG2_RELEASE MPEG2_VERSION (0, 5, 0) /* 0.5.0 */ | ||
35 | |||
36 | #define SEQ_FLAG_MPEG2 1 | ||
37 | #define SEQ_FLAG_CONSTRAINED_PARAMETERS 2 | ||
38 | #define SEQ_FLAG_PROGRESSIVE_SEQUENCE 4 | ||
39 | #define SEQ_FLAG_LOW_DELAY 8 | ||
40 | #define SEQ_FLAG_COLOUR_DESCRIPTION 16 | ||
41 | |||
42 | #define SEQ_MASK_VIDEO_FORMAT 0xe0 | ||
43 | #define SEQ_VIDEO_FORMAT_COMPONENT 0x00 | ||
44 | #define SEQ_VIDEO_FORMAT_PAL 0x20 | ||
45 | #define SEQ_VIDEO_FORMAT_NTSC 0x40 | ||
46 | #define SEQ_VIDEO_FORMAT_SECAM 0x60 | ||
47 | #define SEQ_VIDEO_FORMAT_MAC 0x80 | ||
48 | #define SEQ_VIDEO_FORMAT_UNSPECIFIED 0xa0 | ||
49 | |||
50 | typedef struct mpeg2_sequence_s | ||
51 | { | ||
52 | unsigned int width, height; | ||
53 | unsigned int chroma_width, chroma_height; | ||
54 | unsigned int byte_rate; | ||
55 | unsigned int vbv_buffer_size; | ||
56 | uint32_t flags; | ||
57 | |||
58 | unsigned int picture_width, picture_height; | ||
59 | unsigned int display_width, display_height; | ||
60 | unsigned int pixel_width, pixel_height; | ||
61 | unsigned int frame_period; | ||
62 | |||
63 | uint8_t profile_level_id; | ||
64 | uint8_t colour_primaries; | ||
65 | uint8_t transfer_characteristics; | ||
66 | uint8_t matrix_coefficients; | ||
67 | } mpeg2_sequence_t; | ||
68 | |||
69 | #define GOP_FLAG_DROP_FRAME 1 | ||
70 | #define GOP_FLAG_BROKEN_LINK 2 | ||
71 | #define GOP_FLAG_CLOSED_GOP 4 | ||
72 | |||
73 | typedef struct mpeg2_gop_s | ||
74 | { | ||
75 | uint8_t hours; | ||
76 | uint8_t minutes; | ||
77 | uint8_t seconds; | ||
78 | uint8_t pictures; | ||
79 | uint32_t flags; | ||
80 | } mpeg2_gop_t; | ||
81 | |||
82 | #define PIC_MASK_CODING_TYPE 7 | ||
83 | #define PIC_FLAG_CODING_TYPE_I 1 | ||
84 | #define PIC_FLAG_CODING_TYPE_P 2 | ||
85 | #define PIC_FLAG_CODING_TYPE_B 3 | ||
86 | #define PIC_FLAG_CODING_TYPE_D 4 | ||
87 | |||
88 | #define PIC_FLAG_TOP_FIELD_FIRST 8 | ||
89 | #define PIC_FLAG_PROGRESSIVE_FRAME 16 | ||
90 | #define PIC_FLAG_COMPOSITE_DISPLAY 32 | ||
91 | #define PIC_FLAG_SKIP 64 | ||
92 | #define PIC_FLAG_TAGS 128 | ||
93 | #define PIC_MASK_COMPOSITE_DISPLAY 0xfffff000 | ||
94 | |||
95 | typedef struct mpeg2_picture_s | ||
96 | { | ||
97 | unsigned int temporal_reference; | ||
98 | unsigned int nb_fields; | ||
99 | uint32_t tag, tag2; | ||
100 | uint32_t flags; | ||
101 | struct | ||
102 | { | ||
103 | int x, y; | ||
104 | } display_offset[3]; | ||
105 | } mpeg2_picture_t; | ||
106 | |||
107 | typedef struct mpeg2_fbuf_s | ||
108 | { | ||
109 | uint8_t * buf[MPEG2_COMPONENTS]; | ||
110 | void * id; | ||
111 | } mpeg2_fbuf_t; | ||
112 | |||
113 | typedef struct mpeg2_info_s | ||
114 | { | ||
115 | const mpeg2_sequence_t * sequence; | ||
116 | const mpeg2_gop_t * gop; | ||
117 | const mpeg2_picture_t * current_picture; | ||
118 | const mpeg2_picture_t * current_picture_2nd; | ||
119 | const mpeg2_fbuf_t * current_fbuf; | ||
120 | const mpeg2_picture_t * display_picture; | ||
121 | const mpeg2_picture_t * display_picture_2nd; | ||
122 | const mpeg2_fbuf_t * display_fbuf; | ||
123 | const mpeg2_fbuf_t * discard_fbuf; | ||
124 | const uint8_t * user_data; | ||
125 | unsigned int user_data_len; | ||
126 | } mpeg2_info_t; | ||
127 | |||
128 | typedef struct mpeg2dec_s mpeg2dec_t; | ||
129 | typedef struct mpeg2_decoder_s mpeg2_decoder_t; | ||
130 | |||
131 | typedef enum | ||
132 | { | ||
133 | STATE_INTERNAL_NORETURN = -1, | ||
134 | STATE_BUFFER = 0, | ||
135 | STATE_SEQUENCE = 1, | ||
136 | STATE_SEQUENCE_REPEATED = 2, | ||
137 | STATE_SEQUENCE_MODIFIED = 3, | ||
138 | STATE_GOP = 4, | ||
139 | STATE_PICTURE = 5, | ||
140 | STATE_SLICE_1ST = 6, | ||
141 | STATE_PICTURE_2ND = 7, | ||
142 | STATE_SLICE = 8, | ||
143 | STATE_END = 9, | ||
144 | STATE_INVALID = 10, | ||
145 | STATE_INVALID_END = 11, | ||
146 | } mpeg2_state_t; | ||
147 | |||
148 | typedef struct mpeg2_convert_init_s | ||
149 | { | ||
150 | unsigned int id_size; | ||
151 | unsigned int buf_size[MPEG2_COMPONENTS]; | ||
152 | void (* start)(void * id, const mpeg2_fbuf_t * fbuf, | ||
153 | const mpeg2_picture_t * picture, const mpeg2_gop_t * gop); | ||
154 | void (* copy)(void * id, uint8_t * const * src, unsigned int v_offset); | ||
155 | } mpeg2_convert_init_t; | ||
156 | |||
157 | typedef enum | ||
158 | { | ||
159 | MPEG2_CONVERT_SET = 0, | ||
160 | MPEG2_CONVERT_STRIDE = 1, | ||
161 | MPEG2_CONVERT_START = 2 | ||
162 | } mpeg2_convert_stage_t; | ||
163 | |||
164 | typedef int mpeg2_convert_t (int stage, void * id, | ||
165 | const mpeg2_sequence_t * sequence, int stride, | ||
166 | void * arg, mpeg2_convert_init_t * result); | ||
167 | int mpeg2_convert (mpeg2dec_t * mpeg2dec, mpeg2_convert_t convert, void * arg); | ||
168 | int mpeg2_stride (mpeg2dec_t * mpeg2dec, int stride); | ||
169 | void mpeg2_set_buf (mpeg2dec_t * mpeg2dec, uint8_t * buf[MPEG2_COMPONENTS], | ||
170 | void * id); | ||
171 | void mpeg2_custom_fbuf (mpeg2dec_t * mpeg2dec, int custom_fbuf); | ||
172 | |||
173 | mpeg2dec_t * mpeg2_init (void); | ||
174 | const mpeg2_info_t * mpeg2_info (mpeg2dec_t * mpeg2dec); | ||
175 | void mpeg2_close (mpeg2dec_t * mpeg2dec); | ||
176 | |||
177 | void mpeg2_buffer (mpeg2dec_t * mpeg2dec, uint8_t * start, uint8_t * end); | ||
178 | int mpeg2_getpos (mpeg2dec_t * mpeg2dec); | ||
179 | mpeg2_state_t mpeg2_parse (mpeg2dec_t * mpeg2dec); | ||
180 | |||
181 | void mpeg2_reset (mpeg2dec_t * mpeg2dec, int full_reset); | ||
182 | void mpeg2_skip (mpeg2dec_t * mpeg2dec, int skip); | ||
183 | void mpeg2_slice_region (mpeg2dec_t * mpeg2dec, int start, int end); | ||
184 | |||
185 | void mpeg2_tag_picture (mpeg2dec_t * mpeg2dec, uint32_t tag, uint32_t tag2); | ||
186 | |||
187 | void mpeg2_init_fbuf (mpeg2_decoder_t * decoder, | ||
188 | uint8_t * current_fbuf[MPEG2_COMPONENTS], | ||
189 | uint8_t * forward_fbuf[MPEG2_COMPONENTS], | ||
190 | uint8_t * backward_fbuf[MPEG2_COMPONENTS]); | ||
191 | void mpeg2_slice (mpeg2_decoder_t * decoder, int code, const uint8_t * buffer); | ||
192 | |||
193 | int mpeg2_guess_aspect (const mpeg2_sequence_t * sequence, | ||
194 | unsigned int * pixel_width, | ||
195 | unsigned int * pixel_height); | ||
196 | |||
197 | typedef enum | ||
198 | { | ||
199 | MPEG2_ALLOC_MPEG2DEC = 0, | ||
200 | MPEG2_ALLOC_CHUNK = 1, | ||
201 | MPEG2_ALLOC_YUV = 2, | ||
202 | MPEG2_ALLOC_CONVERT_ID = 3, | ||
203 | MPEG2_ALLOC_CONVERTED = 4, | ||
204 | MPEG_ALLOC_CODEC_MALLOC, | ||
205 | MPEG_ALLOC_CODEC_CALLOC, | ||
206 | MPEG_ALLOC_MPEG2_BUFFER, | ||
207 | MPEG_ALLOC_AUDIOBUF, | ||
208 | MPEG_ALLOC_PCMOUT, | ||
209 | MPEG_ALLOC_DISKBUF, | ||
210 | __MPEG_ALLOC_FIRST = -256, | ||
211 | } mpeg2_alloc_t; | ||
212 | |||
213 | void * mpeg2_malloc (unsigned size, mpeg2_alloc_t reason); | ||
214 | #if 0 | ||
215 | void mpeg2_free (void * buf); | ||
216 | #endif | ||
217 | /* allocates a dedicated buffer and locks all previous allocation in place */ | ||
218 | void * mpeg2_bufalloc(unsigned size, mpeg2_alloc_t reason); | ||
219 | /* clears all non-dedicated buffer space */ | ||
220 | void mpeg2_mem_reset(void); | ||
221 | void mpeg2_alloc_init(unsigned char* buf, int mallocsize); | ||
222 | |||
223 | #endif /* MPEG2_H */ | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/mpeg2_internal.h b/apps/plugins/mpegplayer/libmpeg2/mpeg2_internal.h deleted file mode 100644 index e04562e18d..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/mpeg2_internal.h +++ /dev/null | |||
@@ -1,274 +0,0 @@ | |||
1 | /* | ||
2 | * mpeg2_internal.h | ||
3 | * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> | ||
4 | * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> | ||
5 | * | ||
6 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
7 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
8 | * | ||
9 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * mpeg2dec is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | * $Id$ | ||
24 | * libmpeg2 sync history: | ||
25 | * 2008-07-01 - CVS revision 1.89 | ||
26 | */ | ||
27 | #ifndef MPEG2_INTERNAL_H | ||
28 | #define MPEG2_INTERNAL_H | ||
29 | |||
30 | #include "config.h" /* for Rockbox CPU_ #defines */ | ||
31 | |||
32 | /* macroblock modes */ | ||
33 | #define MACROBLOCK_INTRA 1 | ||
34 | #define MACROBLOCK_PATTERN 2 | ||
35 | #define MACROBLOCK_MOTION_BACKWARD 4 | ||
36 | #define MACROBLOCK_MOTION_FORWARD 8 | ||
37 | #define MACROBLOCK_QUANT 16 | ||
38 | #define DCT_TYPE_INTERLACED 32 | ||
39 | /* motion_type */ | ||
40 | #define MOTION_TYPE_SHIFT 6 | ||
41 | #define MC_FIELD 1 | ||
42 | #define MC_FRAME 2 | ||
43 | #define MC_16X8 2 | ||
44 | #define MC_DMV 3 | ||
45 | |||
46 | /* picture structure */ | ||
47 | #define TOP_FIELD 1 | ||
48 | #define BOTTOM_FIELD 2 | ||
49 | #define FRAME_PICTURE 3 | ||
50 | |||
51 | /* picture coding type */ | ||
52 | #define I_TYPE 1 | ||
53 | #define P_TYPE 2 | ||
54 | #define B_TYPE 3 | ||
55 | #define D_TYPE 4 | ||
56 | |||
57 | typedef void mpeg2_mc_fct (uint8_t *, const uint8_t *, int, int); | ||
58 | |||
59 | typedef struct | ||
60 | { | ||
61 | uint8_t * ref[2][MPEG2_COMPONENTS]; | ||
62 | uint8_t ** ref2[2]; | ||
63 | int pmv[2][2]; | ||
64 | int f_code[2]; | ||
65 | } motion_t; | ||
66 | |||
67 | typedef void motion_parser_t(mpeg2_decoder_t * decoder, | ||
68 | motion_t * motion, | ||
69 | mpeg2_mc_fct * const * table); | ||
70 | |||
71 | struct mpeg2_decoder_s | ||
72 | { | ||
73 | /* first, state that carries information from one macroblock to the */ | ||
74 | /* next inside a slice, and is never used outside of mpeg2_slice() */ | ||
75 | |||
76 | /* bit parsing stuff */ | ||
77 | uint32_t bitstream_buf; /* current 32 bit working set */ | ||
78 | int bitstream_bits; /* used bits in working set */ | ||
79 | const uint8_t * bitstream_ptr; /* buffer with stream data */ | ||
80 | |||
81 | uint8_t * dest[MPEG2_COMPONENTS]; | ||
82 | |||
83 | int offset; | ||
84 | int stride; | ||
85 | int uv_stride; | ||
86 | int slice_stride; | ||
87 | int slice_uv_stride; | ||
88 | int stride_frame; | ||
89 | unsigned int limit_x; | ||
90 | unsigned int limit_y_16; | ||
91 | unsigned int limit_y_8; | ||
92 | unsigned int limit_y; | ||
93 | |||
94 | /* Motion vectors */ | ||
95 | /* The f_ and b_ correspond to the forward and backward motion */ | ||
96 | /* predictors */ | ||
97 | motion_t b_motion; | ||
98 | motion_t f_motion; | ||
99 | motion_parser_t * motion_parser[5]; | ||
100 | |||
101 | /* predictor for DC coefficients in intra blocks */ | ||
102 | int16_t dc_dct_pred[MPEG2_COMPONENTS]; | ||
103 | |||
104 | /* DCT coefficients */ | ||
105 | int16_t * DCTblock; /* put buffer separately to have it in IRAM */ | ||
106 | |||
107 | uint8_t * picture_dest[MPEG2_COMPONENTS]; | ||
108 | void (* convert) (void * convert_id, uint8_t * const * src, | ||
109 | unsigned int v_offset); | ||
110 | void * convert_id; | ||
111 | |||
112 | int dmv_offset; | ||
113 | unsigned int v_offset; | ||
114 | |||
115 | /* now non-slice-specific information */ | ||
116 | |||
117 | /* sequence header stuff */ | ||
118 | uint16_t * quantizer_matrix[4]; | ||
119 | uint16_t (* chroma_quantizer[2])[64]; | ||
120 | uint16_t quantizer_prescale[4][32][64]; | ||
121 | |||
122 | /* The width and height of the picture snapped to macroblock units */ | ||
123 | int width; | ||
124 | int height; | ||
125 | int vertical_position_extension; | ||
126 | int chroma_format; | ||
127 | |||
128 | /* picture header stuff */ | ||
129 | |||
130 | /* what type of picture this is (I, P, B, D) */ | ||
131 | int coding_type; | ||
132 | |||
133 | /* picture coding extension stuff */ | ||
134 | |||
135 | /* quantization factor for intra dc coefficients */ | ||
136 | int intra_dc_precision; | ||
137 | /* top/bottom/both fields */ | ||
138 | int picture_structure; | ||
139 | /* bool to indicate all predictions are frame based */ | ||
140 | int frame_pred_frame_dct; | ||
141 | /* bool to indicate whether intra blocks have motion vectors */ | ||
142 | /* (for concealment) */ | ||
143 | int concealment_motion_vectors; | ||
144 | /* bool to use different vlc tables */ | ||
145 | int intra_vlc_format; | ||
146 | /* used for DMV MC */ | ||
147 | int top_field_first; | ||
148 | |||
149 | /* stuff derived from bitstream */ | ||
150 | |||
151 | /* pointer to the zigzag scan we're supposed to be using */ | ||
152 | const uint8_t * scan; | ||
153 | |||
154 | int second_field; | ||
155 | |||
156 | int mpeg1; | ||
157 | }; | ||
158 | |||
159 | typedef struct | ||
160 | { | ||
161 | mpeg2_fbuf_t fbuf; | ||
162 | } fbuf_alloc_t; | ||
163 | |||
164 | struct mpeg2dec_s | ||
165 | { | ||
166 | mpeg2_decoder_t decoder; | ||
167 | |||
168 | mpeg2_info_t info; | ||
169 | |||
170 | uint32_t shift; | ||
171 | int is_display_initialized; | ||
172 | mpeg2_state_t (* action) (struct mpeg2dec_s * mpeg2dec); | ||
173 | mpeg2_state_t state; | ||
174 | uint32_t ext_state; | ||
175 | |||
176 | /* allocated in init - gcc has problems allocating such big structures */ | ||
177 | uint8_t * ATTR_ALIGN(4) chunk_buffer; | ||
178 | /* pointer to start of the current chunk */ | ||
179 | uint8_t * chunk_start; | ||
180 | /* pointer to current position in chunk_buffer */ | ||
181 | uint8_t * chunk_ptr; | ||
182 | /* last start code ? */ | ||
183 | uint8_t code; | ||
184 | |||
185 | /* picture tags */ | ||
186 | uint32_t tag_current, tag2_current, tag_previous, tag2_previous; | ||
187 | int num_tags; | ||
188 | int bytes_since_tag; | ||
189 | |||
190 | int first; | ||
191 | int alloc_index_user; | ||
192 | int alloc_index; | ||
193 | uint8_t first_decode_slice; | ||
194 | uint8_t nb_decode_slices; | ||
195 | |||
196 | unsigned int user_data_len; | ||
197 | |||
198 | mpeg2_sequence_t new_sequence; | ||
199 | mpeg2_sequence_t sequence; | ||
200 | mpeg2_gop_t new_gop; | ||
201 | mpeg2_gop_t gop; | ||
202 | mpeg2_picture_t new_picture; | ||
203 | mpeg2_picture_t pictures[4]; | ||
204 | mpeg2_picture_t * picture; | ||
205 | /*const*/ mpeg2_fbuf_t * fbuf[3]; /* 0: current fbuf, 1-2: prediction fbufs */ | ||
206 | |||
207 | fbuf_alloc_t fbuf_alloc[3]; | ||
208 | int custom_fbuf; | ||
209 | |||
210 | uint8_t * yuv_buf[3][MPEG2_COMPONENTS]; | ||
211 | int yuv_index; | ||
212 | mpeg2_convert_t * convert; | ||
213 | void * convert_arg; | ||
214 | unsigned int convert_id_size; | ||
215 | int convert_stride; | ||
216 | void (* convert_start) (void * id, const mpeg2_fbuf_t * fbuf, | ||
217 | const mpeg2_picture_t * picture, | ||
218 | const mpeg2_gop_t * gop); | ||
219 | |||
220 | uint8_t * buf_start; | ||
221 | uint8_t * buf_end; | ||
222 | |||
223 | int16_t display_offset_x, display_offset_y; | ||
224 | |||
225 | int copy_matrix; | ||
226 | int8_t q_scale_type, scaled[4]; | ||
227 | uint8_t quantizer_matrix[4][64]; | ||
228 | uint8_t new_quantizer_matrix[4][64]; | ||
229 | }; | ||
230 | |||
231 | /* decode.c */ | ||
232 | mpeg2_state_t mpeg2_seek_header (mpeg2dec_t * mpeg2dec); | ||
233 | mpeg2_state_t mpeg2_parse_header (mpeg2dec_t * mpeg2dec); | ||
234 | |||
235 | /* header.c */ | ||
236 | void mpeg2_header_state_init (mpeg2dec_t * mpeg2dec); | ||
237 | void mpeg2_reset_info (mpeg2_info_t * info); | ||
238 | int mpeg2_header_sequence (mpeg2dec_t * mpeg2dec); | ||
239 | int mpeg2_header_gop (mpeg2dec_t * mpeg2dec); | ||
240 | int mpeg2_header_picture (mpeg2dec_t * mpeg2dec); | ||
241 | int mpeg2_header_extension (mpeg2dec_t * mpeg2dec); | ||
242 | int mpeg2_header_user_data (mpeg2dec_t * mpeg2dec); | ||
243 | void mpeg2_header_sequence_finalize (mpeg2dec_t * mpeg2dec); | ||
244 | void mpeg2_header_gop_finalize (mpeg2dec_t * mpeg2dec); | ||
245 | void mpeg2_header_picture_finalize (mpeg2dec_t * mpeg2dec); | ||
246 | mpeg2_state_t mpeg2_header_slice_start (mpeg2dec_t * mpeg2dec); | ||
247 | mpeg2_state_t mpeg2_header_end (mpeg2dec_t * mpeg2dec); | ||
248 | void mpeg2_set_fbuf (mpeg2dec_t * mpeg2dec, int b_type); | ||
249 | |||
250 | /* idct.c */ | ||
251 | void mpeg2_idct_init (void); | ||
252 | void mpeg2_idct_copy(int16_t * block, uint8_t * dest, | ||
253 | const int stride); | ||
254 | void mpeg2_idct_add(const int last, int16_t * block, | ||
255 | uint8_t * dest, const int stride); | ||
256 | |||
257 | extern const uint8_t default_mpeg2_scan_norm[64]; | ||
258 | extern const uint8_t default_mpeg2_scan_alt[64]; | ||
259 | extern uint8_t mpeg2_scan_norm[64]; | ||
260 | extern uint8_t mpeg2_scan_alt[64]; | ||
261 | |||
262 | /* motion_comp.c */ | ||
263 | void mpeg2_mc_init (void); | ||
264 | |||
265 | typedef struct | ||
266 | { | ||
267 | mpeg2_mc_fct * put [8]; | ||
268 | mpeg2_mc_fct * avg [8]; | ||
269 | } mpeg2_mc_t; | ||
270 | |||
271 | extern const mpeg2_mc_t mpeg2_mc; | ||
272 | |||
273 | #endif /* MPEG2_INTERNAL_H */ | ||
274 | |||
diff --git a/apps/plugins/mpegplayer/libmpeg2/mpeg2dec_config.h b/apps/plugins/mpegplayer/libmpeg2/mpeg2dec_config.h deleted file mode 100644 index c34ee374df..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/mpeg2dec_config.h +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | /* $Id$ */ | ||
2 | #ifndef MPEG2DEC_CONFIG_H | ||
3 | #define MPEG2DEC_CONFIG_H | ||
4 | |||
5 | #define ATTRIBUTE_ALIGNED_MAX 16 | ||
6 | |||
7 | #ifdef HAVE_LCD_COLOR | ||
8 | #define MPEG2_COLOR 1 | ||
9 | #define MPEG2_COMPONENTS 3 | ||
10 | #else | ||
11 | #define MPEG2_COLOR 0 | ||
12 | #define MPEG2_COMPONENTS 1 | ||
13 | #endif | ||
14 | |||
15 | #endif /* MPEG2DEC_CONFIG_H */ | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/slice.c b/apps/plugins/mpegplayer/libmpeg2/slice.c deleted file mode 100644 index 926333d5d0..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/slice.c +++ /dev/null | |||
@@ -1,2898 +0,0 @@ | |||
1 | /* | ||
2 | * slice.c | ||
3 | * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> | ||
4 | * Copyright (C) 2003 Peter Gubanov <peter@elecard.net.ru> | ||
5 | * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> | ||
6 | * | ||
7 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
8 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
9 | * | ||
10 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * mpeg2dec is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * $Id$ | ||
25 | * libmpeg2 sync history: | ||
26 | * 2008-07-01 - CVS revision 1.55 | ||
27 | */ | ||
28 | |||
29 | #include "plugin.h" | ||
30 | |||
31 | #include "mpeg2dec_config.h" | ||
32 | |||
33 | #include "mpeg2.h" | ||
34 | #include "attributes.h" | ||
35 | #include "mpeg2_internal.h" | ||
36 | |||
37 | #include "vlc.h" | ||
38 | |||
39 | static inline int get_macroblock_modes (mpeg2_decoder_t * const decoder) | ||
40 | { | ||
41 | #define bit_buf (decoder->bitstream_buf) | ||
42 | #define bits (decoder->bitstream_bits) | ||
43 | #define bit_ptr (decoder->bitstream_ptr) | ||
44 | |||
45 | int macroblock_modes; | ||
46 | const MBtab * tab; | ||
47 | |||
48 | switch (decoder->coding_type) | ||
49 | { | ||
50 | case I_TYPE: | ||
51 | tab = MB_I + UBITS (bit_buf, 1); | ||
52 | DUMPBITS (bit_buf, bits, tab->len); | ||
53 | macroblock_modes = tab->modes; | ||
54 | |||
55 | if (!(decoder->frame_pred_frame_dct) && | ||
56 | decoder->picture_structure == FRAME_PICTURE) | ||
57 | { | ||
58 | macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; | ||
59 | DUMPBITS (bit_buf, bits, 1); | ||
60 | } | ||
61 | |||
62 | return macroblock_modes; | ||
63 | |||
64 | case P_TYPE: | ||
65 | tab = MB_P + UBITS (bit_buf, 5); | ||
66 | DUMPBITS (bit_buf, bits, tab->len); | ||
67 | macroblock_modes = tab->modes; | ||
68 | |||
69 | if (decoder->picture_structure != FRAME_PICTURE) | ||
70 | { | ||
71 | if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) | ||
72 | { | ||
73 | macroblock_modes |= UBITS (bit_buf, 2) << MOTION_TYPE_SHIFT; | ||
74 | DUMPBITS (bit_buf, bits, 2); | ||
75 | } | ||
76 | |||
77 | return macroblock_modes | MACROBLOCK_MOTION_FORWARD; | ||
78 | } | ||
79 | else if (decoder->frame_pred_frame_dct) | ||
80 | { | ||
81 | if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) | ||
82 | macroblock_modes |= MC_FRAME << MOTION_TYPE_SHIFT; | ||
83 | |||
84 | return macroblock_modes | MACROBLOCK_MOTION_FORWARD; | ||
85 | } | ||
86 | else | ||
87 | { | ||
88 | if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) | ||
89 | { | ||
90 | macroblock_modes |= UBITS (bit_buf, 2) << MOTION_TYPE_SHIFT; | ||
91 | DUMPBITS (bit_buf, bits, 2); | ||
92 | } | ||
93 | |||
94 | if (macroblock_modes & (MACROBLOCK_INTRA | MACROBLOCK_PATTERN)) | ||
95 | { | ||
96 | macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; | ||
97 | DUMPBITS (bit_buf, bits, 1); | ||
98 | } | ||
99 | |||
100 | return macroblock_modes | MACROBLOCK_MOTION_FORWARD; | ||
101 | } | ||
102 | |||
103 | case B_TYPE: | ||
104 | tab = MB_B + UBITS (bit_buf, 6); | ||
105 | DUMPBITS (bit_buf, bits, tab->len); | ||
106 | macroblock_modes = tab->modes; | ||
107 | |||
108 | if (decoder->picture_structure != FRAME_PICTURE) | ||
109 | { | ||
110 | if (! (macroblock_modes & MACROBLOCK_INTRA)) | ||
111 | { | ||
112 | macroblock_modes |= UBITS (bit_buf, 2) << MOTION_TYPE_SHIFT; | ||
113 | DUMPBITS (bit_buf, bits, 2); | ||
114 | } | ||
115 | |||
116 | return macroblock_modes; | ||
117 | } | ||
118 | else if (decoder->frame_pred_frame_dct) | ||
119 | { | ||
120 | /* if (! (macroblock_modes & MACROBLOCK_INTRA)) */ | ||
121 | macroblock_modes |= MC_FRAME << MOTION_TYPE_SHIFT; | ||
122 | return macroblock_modes; | ||
123 | } | ||
124 | else | ||
125 | { | ||
126 | if (macroblock_modes & MACROBLOCK_INTRA) | ||
127 | goto intra; | ||
128 | |||
129 | macroblock_modes |= UBITS (bit_buf, 2) << MOTION_TYPE_SHIFT; | ||
130 | DUMPBITS (bit_buf, bits, 2); | ||
131 | |||
132 | if (macroblock_modes & (MACROBLOCK_INTRA | MACROBLOCK_PATTERN)) | ||
133 | { | ||
134 | intra: | ||
135 | macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; | ||
136 | DUMPBITS (bit_buf, bits, 1); | ||
137 | } | ||
138 | return macroblock_modes; | ||
139 | } | ||
140 | |||
141 | case D_TYPE: | ||
142 | DUMPBITS (bit_buf, bits, 1); | ||
143 | return MACROBLOCK_INTRA; | ||
144 | |||
145 | default: | ||
146 | return 0; | ||
147 | } | ||
148 | #undef bit_buf | ||
149 | #undef bits | ||
150 | #undef bit_ptr | ||
151 | } | ||
152 | |||
153 | static inline void get_quantizer_scale (mpeg2_decoder_t * const decoder) | ||
154 | { | ||
155 | #define bit_buf (decoder->bitstream_buf) | ||
156 | #define bits (decoder->bitstream_bits) | ||
157 | #define bit_ptr (decoder->bitstream_ptr) | ||
158 | |||
159 | int quantizer_scale_code; | ||
160 | |||
161 | quantizer_scale_code = UBITS (bit_buf, 5); | ||
162 | DUMPBITS (bit_buf, bits, 5); | ||
163 | |||
164 | decoder->quantizer_matrix[0] = | ||
165 | decoder->quantizer_prescale[0][quantizer_scale_code]; | ||
166 | |||
167 | decoder->quantizer_matrix[1] = | ||
168 | decoder->quantizer_prescale[1][quantizer_scale_code]; | ||
169 | |||
170 | decoder->quantizer_matrix[2] = | ||
171 | decoder->chroma_quantizer[0][quantizer_scale_code]; | ||
172 | |||
173 | decoder->quantizer_matrix[3] = | ||
174 | decoder->chroma_quantizer[1][quantizer_scale_code]; | ||
175 | #undef bit_buf | ||
176 | #undef bits | ||
177 | #undef bit_ptr | ||
178 | } | ||
179 | |||
180 | static inline int get_motion_delta (mpeg2_decoder_t * const decoder, | ||
181 | const int f_code) | ||
182 | { | ||
183 | #define bit_buf (decoder->bitstream_buf) | ||
184 | #define bits (decoder->bitstream_bits) | ||
185 | #define bit_ptr (decoder->bitstream_ptr) | ||
186 | |||
187 | int delta; | ||
188 | int sign; | ||
189 | const MVtab * tab; | ||
190 | |||
191 | if (bit_buf & 0x80000000) | ||
192 | { | ||
193 | DUMPBITS (bit_buf, bits, 1); | ||
194 | return 0; | ||
195 | } | ||
196 | else if (bit_buf >= 0x0c000000) | ||
197 | { | ||
198 | tab = MV_4 + UBITS (bit_buf, 4); | ||
199 | delta = (tab->delta << f_code) + 1; | ||
200 | bits += tab->len + f_code + 1; | ||
201 | bit_buf <<= tab->len; | ||
202 | |||
203 | sign = SBITS (bit_buf, 1); | ||
204 | bit_buf <<= 1; | ||
205 | |||
206 | if (f_code) | ||
207 | delta += UBITS (bit_buf, f_code); | ||
208 | bit_buf <<= f_code; | ||
209 | |||
210 | return (delta ^ sign) - sign; | ||
211 | } | ||
212 | else | ||
213 | { | ||
214 | tab = MV_10 + UBITS (bit_buf, 10); | ||
215 | delta = (tab->delta << f_code) + 1; | ||
216 | bits += tab->len + 1; | ||
217 | bit_buf <<= tab->len; | ||
218 | |||
219 | sign = SBITS (bit_buf, 1); | ||
220 | bit_buf <<= 1; | ||
221 | |||
222 | if (f_code) | ||
223 | { | ||
224 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
225 | delta += UBITS (bit_buf, f_code); | ||
226 | DUMPBITS (bit_buf, bits, f_code); | ||
227 | } | ||
228 | |||
229 | return (delta ^ sign) - sign; | ||
230 | |||
231 | } | ||
232 | #undef bit_buf | ||
233 | #undef bits | ||
234 | #undef bit_ptr | ||
235 | } | ||
236 | |||
237 | static inline int bound_motion_vector (const int vector, const int f_code) | ||
238 | { | ||
239 | return ((int32_t)vector << (27 - f_code)) >> (27 - f_code); | ||
240 | } | ||
241 | |||
242 | static inline int get_dmv (mpeg2_decoder_t * const decoder) | ||
243 | { | ||
244 | #define bit_buf (decoder->bitstream_buf) | ||
245 | #define bits (decoder->bitstream_bits) | ||
246 | #define bit_ptr (decoder->bitstream_ptr) | ||
247 | |||
248 | const DMVtab * tab; | ||
249 | |||
250 | tab = DMV_2 + UBITS (bit_buf, 2); | ||
251 | DUMPBITS (bit_buf, bits, tab->len); | ||
252 | return tab->dmv; | ||
253 | |||
254 | #undef bit_buf | ||
255 | #undef bits | ||
256 | #undef bit_ptr | ||
257 | } | ||
258 | |||
259 | static inline int get_coded_block_pattern (mpeg2_decoder_t * const decoder) | ||
260 | { | ||
261 | #define bit_buf (decoder->bitstream_buf) | ||
262 | #define bits (decoder->bitstream_bits) | ||
263 | #define bit_ptr (decoder->bitstream_ptr) | ||
264 | |||
265 | const CBPtab * tab; | ||
266 | |||
267 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
268 | |||
269 | if (bit_buf >= 0x20000000) | ||
270 | { | ||
271 | tab = CBP_7 + (UBITS (bit_buf, 7) - 16); | ||
272 | DUMPBITS (bit_buf, bits, tab->len); | ||
273 | return tab->cbp; | ||
274 | } | ||
275 | else | ||
276 | { | ||
277 | tab = CBP_9 + UBITS (bit_buf, 9); | ||
278 | DUMPBITS (bit_buf, bits, tab->len); | ||
279 | return tab->cbp; | ||
280 | } | ||
281 | |||
282 | #undef bit_buf | ||
283 | #undef bits | ||
284 | #undef bit_ptr | ||
285 | } | ||
286 | |||
287 | static inline int get_luma_dc_dct_diff (mpeg2_decoder_t * const decoder) | ||
288 | { | ||
289 | #define bit_buf (decoder->bitstream_buf) | ||
290 | #define bits (decoder->bitstream_bits) | ||
291 | #define bit_ptr (decoder->bitstream_ptr) | ||
292 | |||
293 | const DCtab * tab; | ||
294 | int size; | ||
295 | int dc_diff; | ||
296 | |||
297 | if (bit_buf < 0xf8000000) | ||
298 | { | ||
299 | tab = DC_lum_5 + UBITS (bit_buf, 5); | ||
300 | size = tab->size; | ||
301 | |||
302 | if (size) | ||
303 | { | ||
304 | bits += tab->len + size; | ||
305 | bit_buf <<= tab->len; | ||
306 | dc_diff = | ||
307 | UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); | ||
308 | bit_buf <<= size; | ||
309 | return dc_diff << decoder->intra_dc_precision; | ||
310 | } | ||
311 | else | ||
312 | { | ||
313 | DUMPBITS (bit_buf, bits, 3); | ||
314 | return 0; | ||
315 | } | ||
316 | } | ||
317 | else | ||
318 | { | ||
319 | tab = DC_long + (UBITS (bit_buf, 9) - 0x1e0); | ||
320 | size = tab->size; | ||
321 | DUMPBITS (bit_buf, bits, tab->len); | ||
322 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
323 | dc_diff = UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); | ||
324 | DUMPBITS (bit_buf, bits, size); | ||
325 | return dc_diff << decoder->intra_dc_precision; | ||
326 | } | ||
327 | |||
328 | #undef bit_buf | ||
329 | #undef bits | ||
330 | #undef bit_ptr | ||
331 | } | ||
332 | |||
333 | #if MPEG2_COLOR | ||
334 | static inline int get_chroma_dc_dct_diff (mpeg2_decoder_t * const decoder) | ||
335 | { | ||
336 | #define bit_buf (decoder->bitstream_buf) | ||
337 | #define bits (decoder->bitstream_bits) | ||
338 | #define bit_ptr (decoder->bitstream_ptr) | ||
339 | |||
340 | const DCtab * tab; | ||
341 | int size; | ||
342 | int dc_diff; | ||
343 | |||
344 | if (bit_buf < 0xf8000000) | ||
345 | { | ||
346 | tab = DC_chrom_5 + UBITS (bit_buf, 5); | ||
347 | size = tab->size; | ||
348 | |||
349 | if (size) | ||
350 | { | ||
351 | bits += tab->len + size; | ||
352 | bit_buf <<= tab->len; | ||
353 | dc_diff = | ||
354 | UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); | ||
355 | bit_buf <<= size; | ||
356 | return dc_diff << decoder->intra_dc_precision; | ||
357 | } | ||
358 | else | ||
359 | { | ||
360 | DUMPBITS (bit_buf, bits, 2); | ||
361 | return 0; | ||
362 | } | ||
363 | } | ||
364 | else | ||
365 | { | ||
366 | tab = DC_long + (UBITS (bit_buf, 10) - 0x3e0); | ||
367 | size = tab->size; | ||
368 | DUMPBITS (bit_buf, bits, tab->len + 1); | ||
369 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
370 | dc_diff = UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); | ||
371 | DUMPBITS (bit_buf, bits, size); | ||
372 | return dc_diff << decoder->intra_dc_precision; | ||
373 | } | ||
374 | |||
375 | #undef bit_buf | ||
376 | #undef bits | ||
377 | #undef bit_ptr | ||
378 | } | ||
379 | #endif /* MPEG2_COLOR */ | ||
380 | |||
381 | #define SATURATE(val) \ | ||
382 | do { \ | ||
383 | val <<= 4; \ | ||
384 | if (unlikely (val != (int16_t) val)) \ | ||
385 | val = (SBITS (val, 1) ^ 2047) << 4; \ | ||
386 | } while (0) | ||
387 | |||
388 | static void get_intra_block_B14 (mpeg2_decoder_t * const decoder, | ||
389 | const uint16_t * const quant_matrix) | ||
390 | { | ||
391 | uint32_t bit_buf = decoder->bitstream_buf; | ||
392 | int bits = decoder->bitstream_bits; | ||
393 | const uint8_t * bit_ptr = decoder->bitstream_ptr; | ||
394 | const uint8_t * const scan = decoder->scan; | ||
395 | int16_t * const dest = decoder->DCTblock; | ||
396 | int mismatch = ~dest[0]; | ||
397 | int i = 0; | ||
398 | int j; | ||
399 | int val; | ||
400 | const DCTtab * tab; | ||
401 | |||
402 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
403 | |||
404 | while (1) | ||
405 | { | ||
406 | if (bit_buf >= 0x28000000) | ||
407 | { | ||
408 | tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); | ||
409 | |||
410 | i += tab->run; | ||
411 | if (i >= 64) | ||
412 | break; /* end of block */ | ||
413 | |||
414 | normal_code: | ||
415 | j = scan[i]; | ||
416 | bit_buf <<= tab->len; | ||
417 | bits += tab->len + 1; | ||
418 | val = (tab->level * quant_matrix[j]) >> 4; | ||
419 | |||
420 | /* if (bitstream_get (1)) val = -val; */ | ||
421 | val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); | ||
422 | |||
423 | SATURATE (val); | ||
424 | dest[j] = val; | ||
425 | mismatch ^= val; | ||
426 | |||
427 | bit_buf <<= 1; | ||
428 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
429 | |||
430 | continue; | ||
431 | } | ||
432 | else if (bit_buf >= 0x04000000) | ||
433 | { | ||
434 | tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); | ||
435 | |||
436 | i += tab->run; | ||
437 | if (i < 64) | ||
438 | goto normal_code; | ||
439 | |||
440 | /* escape code */ | ||
441 | |||
442 | i += UBITS (bit_buf << 6, 6) - 64; | ||
443 | if (i >= 64) | ||
444 | break; /* illegal, check needed to avoid buffer overflow */ | ||
445 | |||
446 | j = scan[i]; | ||
447 | |||
448 | DUMPBITS (bit_buf, bits, 12); | ||
449 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
450 | val = (SBITS (bit_buf, 12) * quant_matrix[j]) / 16; | ||
451 | |||
452 | SATURATE (val); | ||
453 | dest[j] = val; | ||
454 | mismatch ^= val; | ||
455 | |||
456 | DUMPBITS (bit_buf, bits, 12); | ||
457 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
458 | |||
459 | continue; | ||
460 | } | ||
461 | else if (bit_buf >= 0x02000000) | ||
462 | { | ||
463 | tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); | ||
464 | i += tab->run; | ||
465 | if (i < 64) | ||
466 | goto normal_code; | ||
467 | } | ||
468 | else if (bit_buf >= 0x00800000) | ||
469 | { | ||
470 | tab = DCT_13 + (UBITS (bit_buf, 13) - 16); | ||
471 | i += tab->run; | ||
472 | if (i < 64) | ||
473 | goto normal_code; | ||
474 | } | ||
475 | else if (bit_buf >= 0x00200000) | ||
476 | { | ||
477 | tab = DCT_15 + (UBITS (bit_buf, 15) - 16); | ||
478 | i += tab->run; | ||
479 | if (i < 64) | ||
480 | goto normal_code; | ||
481 | } | ||
482 | else | ||
483 | { | ||
484 | tab = DCT_16 + UBITS (bit_buf, 16); | ||
485 | bit_buf <<= 16; | ||
486 | GETWORD (bit_buf, bits + 16, bit_ptr); | ||
487 | i += tab->run; | ||
488 | if (i < 64) | ||
489 | goto normal_code; | ||
490 | } | ||
491 | break; /* illegal, check needed to avoid buffer overflow */ | ||
492 | } | ||
493 | |||
494 | dest[63] ^= mismatch & 16; | ||
495 | DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ | ||
496 | decoder->bitstream_buf = bit_buf; | ||
497 | decoder->bitstream_bits = bits; | ||
498 | decoder->bitstream_ptr = bit_ptr; | ||
499 | } | ||
500 | |||
501 | static void get_intra_block_B15 (mpeg2_decoder_t * const decoder, | ||
502 | const uint16_t * const quant_matrix) | ||
503 | { | ||
504 | uint32_t bit_buf = decoder->bitstream_buf; | ||
505 | int bits = decoder->bitstream_bits; | ||
506 | const uint8_t * bit_ptr = decoder->bitstream_ptr; | ||
507 | const uint8_t * const scan = decoder->scan; | ||
508 | int16_t * const dest = decoder->DCTblock; | ||
509 | int mismatch = ~dest[0]; | ||
510 | int i = 0; | ||
511 | int j; | ||
512 | int val; | ||
513 | const DCTtab * tab; | ||
514 | |||
515 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
516 | |||
517 | while (1) | ||
518 | { | ||
519 | if (bit_buf >= 0x04000000) | ||
520 | { | ||
521 | tab = DCT_B15_8 + (UBITS (bit_buf, 8) - 4); | ||
522 | |||
523 | i += tab->run; | ||
524 | |||
525 | if (i < 64) | ||
526 | { | ||
527 | normal_code: | ||
528 | j = scan[i]; | ||
529 | bit_buf <<= tab->len; | ||
530 | bits += tab->len + 1; | ||
531 | val = (tab->level * quant_matrix[j]) >> 4; | ||
532 | |||
533 | /* if (bitstream_get (1)) val = -val; */ | ||
534 | val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); | ||
535 | |||
536 | SATURATE (val); | ||
537 | dest[j] = val; | ||
538 | mismatch ^= val; | ||
539 | |||
540 | bit_buf <<= 1; | ||
541 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
542 | |||
543 | continue; | ||
544 | } | ||
545 | else | ||
546 | { | ||
547 | /* end of block. I commented out this code because if we */ | ||
548 | /* dont exit here we will still exit at the later test :) */ | ||
549 | |||
550 | /* if (i >= 128) break; */ /* end of block */ | ||
551 | |||
552 | /* escape code */ | ||
553 | |||
554 | i += UBITS (bit_buf << 6, 6) - 64; | ||
555 | if (i >= 64) | ||
556 | break; /* illegal, check against buffer overflow */ | ||
557 | |||
558 | j = scan[i]; | ||
559 | |||
560 | DUMPBITS (bit_buf, bits, 12); | ||
561 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
562 | val = (SBITS (bit_buf, 12) * quant_matrix[j]) / 16; | ||
563 | |||
564 | SATURATE (val); | ||
565 | dest[j] = val; | ||
566 | mismatch ^= val; | ||
567 | |||
568 | DUMPBITS (bit_buf, bits, 12); | ||
569 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
570 | |||
571 | continue; | ||
572 | } | ||
573 | } | ||
574 | else if (bit_buf >= 0x02000000) | ||
575 | { | ||
576 | tab = DCT_B15_10 + (UBITS (bit_buf, 10) - 8); | ||
577 | i += tab->run; | ||
578 | if (i < 64) | ||
579 | goto normal_code; | ||
580 | } | ||
581 | else if (bit_buf >= 0x00800000) | ||
582 | { | ||
583 | tab = DCT_13 + (UBITS (bit_buf, 13) - 16); | ||
584 | i += tab->run; | ||
585 | if (i < 64) | ||
586 | goto normal_code; | ||
587 | } | ||
588 | else if (bit_buf >= 0x00200000) | ||
589 | { | ||
590 | tab = DCT_15 + (UBITS (bit_buf, 15) - 16); | ||
591 | i += tab->run; | ||
592 | if (i < 64) | ||
593 | goto normal_code; | ||
594 | } | ||
595 | else | ||
596 | { | ||
597 | tab = DCT_16 + UBITS (bit_buf, 16); | ||
598 | bit_buf <<= 16; | ||
599 | GETWORD (bit_buf, bits + 16, bit_ptr); | ||
600 | i += tab->run; | ||
601 | if (i < 64) | ||
602 | goto normal_code; | ||
603 | } | ||
604 | break; /* illegal, check needed to avoid buffer overflow */ | ||
605 | } | ||
606 | |||
607 | dest[63] ^= mismatch & 16; | ||
608 | DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ | ||
609 | decoder->bitstream_buf = bit_buf; | ||
610 | decoder->bitstream_bits = bits; | ||
611 | decoder->bitstream_ptr = bit_ptr; | ||
612 | } | ||
613 | |||
614 | static int get_non_intra_block (mpeg2_decoder_t * const decoder, | ||
615 | const uint16_t * const quant_matrix) | ||
616 | { | ||
617 | uint32_t bit_buf = decoder->bitstream_buf; | ||
618 | int bits = decoder->bitstream_bits; | ||
619 | const uint8_t * bit_ptr = decoder->bitstream_ptr; | ||
620 | const uint8_t * const scan = decoder->scan; | ||
621 | int16_t * const dest = decoder->DCTblock; | ||
622 | int mismatch = -1; | ||
623 | int i = -1; | ||
624 | int j; | ||
625 | int val; | ||
626 | const DCTtab * tab; | ||
627 | |||
628 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
629 | |||
630 | if (bit_buf >= 0x28000000) | ||
631 | { | ||
632 | tab = DCT_B14DC_5 + (UBITS (bit_buf, 5) - 5); | ||
633 | goto entry_1; | ||
634 | } | ||
635 | else | ||
636 | { | ||
637 | goto entry_2; | ||
638 | } | ||
639 | |||
640 | while (1) | ||
641 | { | ||
642 | if (bit_buf >= 0x28000000) | ||
643 | { | ||
644 | tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); | ||
645 | |||
646 | entry_1: | ||
647 | i += tab->run; | ||
648 | if (i >= 64) | ||
649 | break; /* end of block */ | ||
650 | |||
651 | normal_code: | ||
652 | j = scan[i]; | ||
653 | bit_buf <<= tab->len; | ||
654 | bits += tab->len + 1; | ||
655 | val = ((2 * tab->level + 1) * quant_matrix[j]) >> 5; | ||
656 | |||
657 | /* if (bitstream_get (1)) val = -val; */ | ||
658 | val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); | ||
659 | |||
660 | SATURATE (val); | ||
661 | dest[j] = val; | ||
662 | mismatch ^= val; | ||
663 | |||
664 | bit_buf <<= 1; | ||
665 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
666 | |||
667 | continue; | ||
668 | } | ||
669 | |||
670 | entry_2: | ||
671 | if (bit_buf >= 0x04000000) | ||
672 | { | ||
673 | tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); | ||
674 | |||
675 | i += tab->run; | ||
676 | if (i < 64) | ||
677 | goto normal_code; | ||
678 | |||
679 | /* escape code */ | ||
680 | |||
681 | i += UBITS (bit_buf << 6, 6) - 64; | ||
682 | if (i >= 64) | ||
683 | break; /* illegal, check needed to avoid buffer overflow */ | ||
684 | |||
685 | j = scan[i]; | ||
686 | |||
687 | DUMPBITS (bit_buf, bits, 12); | ||
688 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
689 | val = 2 * (SBITS (bit_buf, 12) + SBITS (bit_buf, 1)) + 1; | ||
690 | val = (val * quant_matrix[j]) / 32; | ||
691 | |||
692 | SATURATE (val); | ||
693 | dest[j] = val; | ||
694 | mismatch ^= val; | ||
695 | |||
696 | DUMPBITS (bit_buf, bits, 12); | ||
697 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
698 | |||
699 | continue; | ||
700 | } | ||
701 | else if (bit_buf >= 0x02000000) | ||
702 | { | ||
703 | tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); | ||
704 | i += tab->run; | ||
705 | if (i < 64) | ||
706 | goto normal_code; | ||
707 | } | ||
708 | else if (bit_buf >= 0x00800000) | ||
709 | { | ||
710 | tab = DCT_13 + (UBITS (bit_buf, 13) - 16); | ||
711 | i += tab->run; | ||
712 | if (i < 64) | ||
713 | goto normal_code; | ||
714 | } | ||
715 | else if (bit_buf >= 0x00200000) | ||
716 | { | ||
717 | tab = DCT_15 + (UBITS (bit_buf, 15) - 16); | ||
718 | i += tab->run; | ||
719 | if (i < 64) | ||
720 | goto normal_code; | ||
721 | } | ||
722 | else | ||
723 | { | ||
724 | tab = DCT_16 + UBITS (bit_buf, 16); | ||
725 | bit_buf <<= 16; | ||
726 | GETWORD (bit_buf, bits + 16, bit_ptr); | ||
727 | i += tab->run; | ||
728 | if (i < 64) | ||
729 | goto normal_code; | ||
730 | } | ||
731 | break; /* illegal, check needed to avoid buffer overflow */ | ||
732 | } | ||
733 | |||
734 | dest[63] ^= mismatch & 16; | ||
735 | DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ | ||
736 | decoder->bitstream_buf = bit_buf; | ||
737 | decoder->bitstream_bits = bits; | ||
738 | decoder->bitstream_ptr = bit_ptr; | ||
739 | return i; | ||
740 | } | ||
741 | |||
742 | static void get_mpeg1_intra_block (mpeg2_decoder_t * const decoder) | ||
743 | { | ||
744 | uint32_t bit_buf = decoder->bitstream_buf; | ||
745 | int bits = decoder->bitstream_bits; | ||
746 | const uint8_t * bit_ptr = decoder->bitstream_ptr; | ||
747 | const uint8_t * const scan = decoder->scan; | ||
748 | const uint16_t * const quant_matrix = decoder->quantizer_matrix[0]; | ||
749 | int16_t * const dest = decoder->DCTblock; | ||
750 | int i = 0; | ||
751 | int j; | ||
752 | int val; | ||
753 | const DCTtab * tab; | ||
754 | |||
755 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
756 | |||
757 | while (1) | ||
758 | { | ||
759 | if (bit_buf >= 0x28000000) | ||
760 | { | ||
761 | tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); | ||
762 | |||
763 | i += tab->run; | ||
764 | if (i >= 64) | ||
765 | break; /* end of block */ | ||
766 | |||
767 | normal_code: | ||
768 | j = scan[i]; | ||
769 | bit_buf <<= tab->len; | ||
770 | bits += tab->len + 1; | ||
771 | val = (tab->level * quant_matrix[j]) >> 4; | ||
772 | |||
773 | /* oddification */ | ||
774 | val = (val - 1) | 1; | ||
775 | |||
776 | /* if (bitstream_get (1)) val = -val; */ | ||
777 | val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); | ||
778 | |||
779 | SATURATE (val); | ||
780 | dest[j] = val; | ||
781 | |||
782 | bit_buf <<= 1; | ||
783 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
784 | |||
785 | continue; | ||
786 | } | ||
787 | else if (bit_buf >= 0x04000000) | ||
788 | { | ||
789 | tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); | ||
790 | |||
791 | i += tab->run; | ||
792 | if (i < 64) | ||
793 | goto normal_code; | ||
794 | |||
795 | /* escape code */ | ||
796 | |||
797 | i += UBITS (bit_buf << 6, 6) - 64; | ||
798 | if (i >= 64) | ||
799 | break; /* illegal, check needed to avoid buffer overflow */ | ||
800 | |||
801 | j = scan[i]; | ||
802 | |||
803 | DUMPBITS (bit_buf, bits, 12); | ||
804 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
805 | val = SBITS (bit_buf, 8); | ||
806 | |||
807 | if (! (val & 0x7f)) | ||
808 | { | ||
809 | DUMPBITS (bit_buf, bits, 8); | ||
810 | val = UBITS (bit_buf, 8) + 2 * val; | ||
811 | } | ||
812 | |||
813 | val = (val * quant_matrix[j]) / 16; | ||
814 | |||
815 | /* oddification */ | ||
816 | val = (val + ~SBITS (val, 1)) | 1; | ||
817 | |||
818 | SATURATE (val); | ||
819 | dest[j] = val; | ||
820 | |||
821 | DUMPBITS (bit_buf, bits, 8); | ||
822 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
823 | |||
824 | continue; | ||
825 | } | ||
826 | else if (bit_buf >= 0x02000000) | ||
827 | { | ||
828 | tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); | ||
829 | i += tab->run; | ||
830 | if (i < 64) | ||
831 | goto normal_code; | ||
832 | } | ||
833 | else if (bit_buf >= 0x00800000) | ||
834 | { | ||
835 | tab = DCT_13 + (UBITS (bit_buf, 13) - 16); | ||
836 | i += tab->run; | ||
837 | if (i < 64) | ||
838 | goto normal_code; | ||
839 | } | ||
840 | else if (bit_buf >= 0x00200000) | ||
841 | { | ||
842 | tab = DCT_15 + (UBITS (bit_buf, 15) - 16); | ||
843 | i += tab->run; | ||
844 | if (i < 64) | ||
845 | goto normal_code; | ||
846 | } | ||
847 | else | ||
848 | { | ||
849 | tab = DCT_16 + UBITS (bit_buf, 16); | ||
850 | bit_buf <<= 16; | ||
851 | GETWORD (bit_buf, bits + 16, bit_ptr); | ||
852 | i += tab->run; | ||
853 | if (i < 64) | ||
854 | goto normal_code; | ||
855 | } | ||
856 | break; /* illegal, check needed to avoid buffer overflow */ | ||
857 | } | ||
858 | |||
859 | DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ | ||
860 | decoder->bitstream_buf = bit_buf; | ||
861 | decoder->bitstream_bits = bits; | ||
862 | decoder->bitstream_ptr = bit_ptr; | ||
863 | } | ||
864 | |||
865 | static int get_mpeg1_non_intra_block (mpeg2_decoder_t * const decoder) | ||
866 | { | ||
867 | uint32_t bit_buf = decoder->bitstream_buf; | ||
868 | int bits = decoder->bitstream_bits; | ||
869 | const uint8_t * bit_ptr = decoder->bitstream_ptr; | ||
870 | const uint8_t * const scan = decoder->scan; | ||
871 | const uint16_t * const quant_matrix = decoder->quantizer_matrix[1]; | ||
872 | int16_t * const dest = decoder->DCTblock; | ||
873 | int i = -1; | ||
874 | int j; | ||
875 | int val; | ||
876 | const DCTtab * tab; | ||
877 | |||
878 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
879 | if (bit_buf >= 0x28000000) | ||
880 | { | ||
881 | tab = DCT_B14DC_5 + (UBITS (bit_buf, 5) - 5); | ||
882 | goto entry_1; | ||
883 | } | ||
884 | else | ||
885 | { | ||
886 | goto entry_2; | ||
887 | } | ||
888 | |||
889 | while (1) | ||
890 | { | ||
891 | if (bit_buf >= 0x28000000) | ||
892 | { | ||
893 | tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); | ||
894 | |||
895 | entry_1: | ||
896 | i += tab->run; | ||
897 | if (i >= 64) | ||
898 | break; /* end of block */ | ||
899 | |||
900 | normal_code: | ||
901 | j = scan[i]; | ||
902 | bit_buf <<= tab->len; | ||
903 | bits += tab->len + 1; | ||
904 | val = ((2 * tab->level + 1) * quant_matrix[j]) >> 5; | ||
905 | |||
906 | /* oddification */ | ||
907 | val = (val - 1) | 1; | ||
908 | |||
909 | /* if (bitstream_get (1)) val = -val; */ | ||
910 | val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); | ||
911 | |||
912 | SATURATE (val); | ||
913 | dest[j] = val; | ||
914 | |||
915 | bit_buf <<= 1; | ||
916 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
917 | |||
918 | continue; | ||
919 | } | ||
920 | |||
921 | entry_2: | ||
922 | if (bit_buf >= 0x04000000) | ||
923 | { | ||
924 | tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); | ||
925 | |||
926 | i += tab->run; | ||
927 | if (i < 64) | ||
928 | goto normal_code; | ||
929 | |||
930 | /* escape code */ | ||
931 | |||
932 | i += UBITS (bit_buf << 6, 6) - 64; | ||
933 | if (i >= 64) | ||
934 | break; /* illegal, check needed to avoid buffer overflow */ | ||
935 | |||
936 | j = scan[i]; | ||
937 | |||
938 | DUMPBITS (bit_buf, bits, 12); | ||
939 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
940 | val = SBITS (bit_buf, 8); | ||
941 | |||
942 | if (! (val & 0x7f)) | ||
943 | { | ||
944 | DUMPBITS (bit_buf, bits, 8); | ||
945 | val = UBITS (bit_buf, 8) + 2 * val; | ||
946 | } | ||
947 | |||
948 | val = 2 * (val + SBITS (val, 1)) + 1; | ||
949 | val = (val * quant_matrix[j]) / 32; | ||
950 | |||
951 | /* oddification */ | ||
952 | val = (val + ~SBITS (val, 1)) | 1; | ||
953 | |||
954 | SATURATE (val); | ||
955 | dest[j] = val; | ||
956 | |||
957 | DUMPBITS (bit_buf, bits, 8); | ||
958 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
959 | |||
960 | continue; | ||
961 | |||
962 | } | ||
963 | else if (bit_buf >= 0x02000000) | ||
964 | { | ||
965 | tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); | ||
966 | i += tab->run; | ||
967 | if (i < 64) | ||
968 | goto normal_code; | ||
969 | } | ||
970 | else if (bit_buf >= 0x00800000) | ||
971 | { | ||
972 | tab = DCT_13 + (UBITS (bit_buf, 13) - 16); | ||
973 | i += tab->run; | ||
974 | if (i < 64) | ||
975 | goto normal_code; | ||
976 | } | ||
977 | else if (bit_buf >= 0x00200000) | ||
978 | { | ||
979 | tab = DCT_15 + (UBITS (bit_buf, 15) - 16); | ||
980 | i += tab->run; | ||
981 | if (i < 64) | ||
982 | goto normal_code; | ||
983 | } | ||
984 | else | ||
985 | { | ||
986 | tab = DCT_16 + UBITS (bit_buf, 16); | ||
987 | bit_buf <<= 16; | ||
988 | GETWORD (bit_buf, bits + 16, bit_ptr); | ||
989 | i += tab->run; | ||
990 | if (i < 64) | ||
991 | goto normal_code; | ||
992 | } | ||
993 | break; /* illegal, check needed to avoid buffer overflow */ | ||
994 | } | ||
995 | |||
996 | DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ | ||
997 | decoder->bitstream_buf = bit_buf; | ||
998 | decoder->bitstream_bits = bits; | ||
999 | decoder->bitstream_ptr = bit_ptr; | ||
1000 | return i; | ||
1001 | } | ||
1002 | |||
1003 | static inline void slice_intra_DCT (mpeg2_decoder_t * const decoder, | ||
1004 | const int cc, | ||
1005 | uint8_t * const dest, const int stride) | ||
1006 | { | ||
1007 | #define bit_buf (decoder->bitstream_buf) | ||
1008 | #define bits (decoder->bitstream_bits) | ||
1009 | #define bit_ptr (decoder->bitstream_ptr) | ||
1010 | |||
1011 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1012 | /* Get the intra DC coefficient and inverse quantize it */ | ||
1013 | if (cc == 0) | ||
1014 | { | ||
1015 | decoder->dc_dct_pred[0] += get_luma_dc_dct_diff (decoder); | ||
1016 | decoder->DCTblock[0] = decoder->dc_dct_pred[0]; | ||
1017 | |||
1018 | } | ||
1019 | #if MPEG2_COLOR | ||
1020 | else | ||
1021 | { | ||
1022 | decoder->dc_dct_pred[cc] += get_chroma_dc_dct_diff (decoder); | ||
1023 | decoder->DCTblock[0] = decoder->dc_dct_pred[cc]; | ||
1024 | } | ||
1025 | #endif | ||
1026 | |||
1027 | if (decoder->mpeg1) | ||
1028 | { | ||
1029 | if (decoder->coding_type != D_TYPE) | ||
1030 | get_mpeg1_intra_block (decoder); | ||
1031 | } | ||
1032 | else if (decoder->intra_vlc_format) | ||
1033 | { | ||
1034 | get_intra_block_B15 (decoder, decoder->quantizer_matrix[cc ? 2 : 0]); | ||
1035 | } | ||
1036 | else | ||
1037 | { | ||
1038 | get_intra_block_B14 (decoder, decoder->quantizer_matrix[cc ? 2 : 0]); | ||
1039 | } | ||
1040 | |||
1041 | mpeg2_idct_copy (decoder->DCTblock, dest, stride); | ||
1042 | |||
1043 | #undef bit_buf | ||
1044 | #undef bits | ||
1045 | #undef bit_ptr | ||
1046 | } | ||
1047 | |||
1048 | static inline void slice_non_intra_DCT (mpeg2_decoder_t * const decoder, | ||
1049 | const int cc, | ||
1050 | uint8_t * const dest, const int stride) | ||
1051 | { | ||
1052 | int last; | ||
1053 | |||
1054 | if (decoder->mpeg1) | ||
1055 | { | ||
1056 | last = get_mpeg1_non_intra_block (decoder); | ||
1057 | } | ||
1058 | else | ||
1059 | { | ||
1060 | last = get_non_intra_block (decoder, | ||
1061 | decoder->quantizer_matrix[cc ? 3 : 1]); | ||
1062 | } | ||
1063 | |||
1064 | mpeg2_idct_add (last, decoder->DCTblock, dest, stride); | ||
1065 | } | ||
1066 | |||
1067 | #if !MPEG2_COLOR | ||
1068 | static void skip_mpeg1_intra_block (mpeg2_decoder_t * const decoder) | ||
1069 | { | ||
1070 | uint32_t bit_buf = decoder->bitstream_buf; | ||
1071 | int bits = decoder->bitstream_bits; | ||
1072 | const uint8_t * bit_ptr = decoder->bitstream_ptr; | ||
1073 | int i = 0; | ||
1074 | const DCTtab * tab; | ||
1075 | |||
1076 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1077 | |||
1078 | while (1) | ||
1079 | { | ||
1080 | if (bit_buf >= 0x28000000) | ||
1081 | { | ||
1082 | tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); | ||
1083 | |||
1084 | i += tab->run; | ||
1085 | if (i >= 64) | ||
1086 | break; /* end of block */ | ||
1087 | |||
1088 | normal_code: | ||
1089 | bit_buf <<= tab->len + 1; | ||
1090 | bits += tab->len + 1; | ||
1091 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1092 | continue; | ||
1093 | } | ||
1094 | else if (bit_buf >= 0x04000000) | ||
1095 | { | ||
1096 | tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); | ||
1097 | |||
1098 | i += tab->run; | ||
1099 | if (i < 64) | ||
1100 | goto normal_code; | ||
1101 | |||
1102 | /* escape code */ | ||
1103 | |||
1104 | i += UBITS (bit_buf << 6, 6) - 64; | ||
1105 | if (i >= 64) | ||
1106 | break; /* illegal, check needed to avoid buffer overflow */ | ||
1107 | |||
1108 | DUMPBITS (bit_buf, bits, 12); | ||
1109 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1110 | |||
1111 | if (!(SBITS (bit_buf, 8) & 0x7f)) | ||
1112 | DUMPBITS (bit_buf, bits, 8); | ||
1113 | |||
1114 | DUMPBITS (bit_buf, bits, 8); | ||
1115 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1116 | |||
1117 | continue; | ||
1118 | } | ||
1119 | else if (bit_buf >= 0x02000000) | ||
1120 | { | ||
1121 | tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); | ||
1122 | i += tab->run; | ||
1123 | if (i < 64) | ||
1124 | goto normal_code; | ||
1125 | } | ||
1126 | else if (bit_buf >= 0x00800000) | ||
1127 | { | ||
1128 | tab = DCT_13 + (UBITS (bit_buf, 13) - 16); | ||
1129 | i += tab->run; | ||
1130 | if (i < 64) | ||
1131 | goto normal_code; | ||
1132 | } | ||
1133 | else if (bit_buf >= 0x00200000) | ||
1134 | { | ||
1135 | tab = DCT_15 + (UBITS (bit_buf, 15) - 16); | ||
1136 | i += tab->run; | ||
1137 | if (i < 64) | ||
1138 | goto normal_code; | ||
1139 | } | ||
1140 | else | ||
1141 | { | ||
1142 | tab = DCT_16 + UBITS (bit_buf, 16); | ||
1143 | bit_buf <<= 16; | ||
1144 | GETWORD (bit_buf, bits + 16, bit_ptr); | ||
1145 | i += tab->run; | ||
1146 | if (i < 64) | ||
1147 | goto normal_code; | ||
1148 | } | ||
1149 | break; /* illegal, check needed to avoid buffer overflow */ | ||
1150 | } | ||
1151 | |||
1152 | DUMPBITS (bit_buf, bits, 2); /* dump end of block code */ | ||
1153 | decoder->bitstream_buf = bit_buf; | ||
1154 | decoder->bitstream_bits = bits; | ||
1155 | decoder->bitstream_ptr = bit_ptr; | ||
1156 | } | ||
1157 | |||
1158 | static void skip_intra_block_B14 (mpeg2_decoder_t * const decoder) | ||
1159 | { | ||
1160 | uint32_t bit_buf = decoder->bitstream_buf; | ||
1161 | int bits = decoder->bitstream_bits; | ||
1162 | const uint8_t * bit_ptr = decoder->bitstream_ptr; | ||
1163 | int i = 0; | ||
1164 | const DCTtab * tab; | ||
1165 | |||
1166 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1167 | |||
1168 | while (1) | ||
1169 | { | ||
1170 | if (bit_buf >= 0x28000000) | ||
1171 | { | ||
1172 | tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); | ||
1173 | |||
1174 | i += tab->run; | ||
1175 | if (i >= 64) | ||
1176 | break; /* end of block */ | ||
1177 | |||
1178 | normal_code: | ||
1179 | bit_buf <<= tab->len + 1; | ||
1180 | bits += tab->len + 1; | ||
1181 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1182 | continue; | ||
1183 | } | ||
1184 | else if (bit_buf >= 0x04000000) | ||
1185 | { | ||
1186 | tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); | ||
1187 | |||
1188 | i += tab->run; | ||
1189 | if (i < 64) | ||
1190 | goto normal_code; | ||
1191 | |||
1192 | /* escape code */ | ||
1193 | |||
1194 | i += UBITS (bit_buf << 6, 6) - 64; | ||
1195 | if (i >= 64) | ||
1196 | break; /* illegal, check needed to avoid buffer overflow */ | ||
1197 | |||
1198 | DUMPBITS (bit_buf, bits, 12); /* Can't dump more than 16 atm */ | ||
1199 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1200 | DUMPBITS (bit_buf, bits, 12); | ||
1201 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1202 | continue; | ||
1203 | } | ||
1204 | else if (bit_buf >= 0x02000000) | ||
1205 | { | ||
1206 | tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); | ||
1207 | i += tab->run; | ||
1208 | if (i < 64) | ||
1209 | goto normal_code; | ||
1210 | } | ||
1211 | else if (bit_buf >= 0x00800000) | ||
1212 | { | ||
1213 | tab = DCT_13 + (UBITS (bit_buf, 13) - 16); | ||
1214 | i += tab->run; | ||
1215 | if (i < 64) | ||
1216 | goto normal_code; | ||
1217 | } | ||
1218 | else if (bit_buf >= 0x00200000) | ||
1219 | { | ||
1220 | tab = DCT_15 + (UBITS (bit_buf, 15) - 16); | ||
1221 | i += tab->run; | ||
1222 | if (i < 64) | ||
1223 | goto normal_code; | ||
1224 | } | ||
1225 | else | ||
1226 | { | ||
1227 | tab = DCT_16 + UBITS (bit_buf, 16); | ||
1228 | bit_buf <<= 16; | ||
1229 | GETWORD (bit_buf, bits + 16, bit_ptr); | ||
1230 | i += tab->run; | ||
1231 | if (i < 64) | ||
1232 | goto normal_code; | ||
1233 | } | ||
1234 | break; /* illegal, check needed to avoid buffer overflow */ | ||
1235 | } | ||
1236 | |||
1237 | DUMPBITS (bit_buf, bits, 2); /* dump end of block code */ | ||
1238 | decoder->bitstream_buf = bit_buf; | ||
1239 | decoder->bitstream_bits = bits; | ||
1240 | decoder->bitstream_ptr = bit_ptr; | ||
1241 | } | ||
1242 | |||
1243 | static void skip_intra_block_B15 (mpeg2_decoder_t * const decoder) | ||
1244 | { | ||
1245 | uint32_t bit_buf = decoder->bitstream_buf; | ||
1246 | int bits = decoder->bitstream_bits; | ||
1247 | const uint8_t * bit_ptr = decoder->bitstream_ptr; | ||
1248 | int i = 0; | ||
1249 | const DCTtab * tab; | ||
1250 | |||
1251 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1252 | |||
1253 | while (1) | ||
1254 | { | ||
1255 | if (bit_buf >= 0x04000000) | ||
1256 | { | ||
1257 | tab = DCT_B15_8 + (UBITS (bit_buf, 8) - 4); | ||
1258 | |||
1259 | i += tab->run; | ||
1260 | |||
1261 | if (i < 64) | ||
1262 | { | ||
1263 | normal_code: | ||
1264 | bit_buf <<= tab->len + 1; | ||
1265 | bits += tab->len + 1; | ||
1266 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1267 | continue; | ||
1268 | } | ||
1269 | else | ||
1270 | { | ||
1271 | /* end of block. I commented out this code because if we */ | ||
1272 | /* dont exit here we will still exit at the later test :) */ | ||
1273 | |||
1274 | /* if (i >= 128) break; */ /* end of block */ | ||
1275 | |||
1276 | /* escape code */ | ||
1277 | |||
1278 | i += UBITS (bit_buf << 6, 6) - 64; | ||
1279 | if (i >= 64) | ||
1280 | break; /* illegal, check against buffer overflow */ | ||
1281 | |||
1282 | DUMPBITS (bit_buf, bits, 12); /* Can't dump more than 16 atm */ | ||
1283 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1284 | DUMPBITS (bit_buf, bits, 12); | ||
1285 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1286 | continue; | ||
1287 | } | ||
1288 | } | ||
1289 | else if (bit_buf >= 0x02000000) | ||
1290 | { | ||
1291 | tab = DCT_B15_10 + (UBITS (bit_buf, 10) - 8); | ||
1292 | i += tab->run; | ||
1293 | if (i < 64) | ||
1294 | goto normal_code; | ||
1295 | } | ||
1296 | else if (bit_buf >= 0x00800000) | ||
1297 | { | ||
1298 | tab = DCT_13 + (UBITS (bit_buf, 13) - 16); | ||
1299 | i += tab->run; | ||
1300 | if (i < 64) | ||
1301 | goto normal_code; | ||
1302 | } | ||
1303 | else if (bit_buf >= 0x00200000) | ||
1304 | { | ||
1305 | tab = DCT_15 + (UBITS (bit_buf, 15) - 16); | ||
1306 | i += tab->run; | ||
1307 | if (i < 64) | ||
1308 | goto normal_code; | ||
1309 | } | ||
1310 | else | ||
1311 | { | ||
1312 | tab = DCT_16 + UBITS (bit_buf, 16); | ||
1313 | bit_buf <<= 16; | ||
1314 | GETWORD (bit_buf, bits + 16, bit_ptr); | ||
1315 | i += tab->run; | ||
1316 | if (i < 64) | ||
1317 | goto normal_code; | ||
1318 | } | ||
1319 | break; /* illegal, check needed to avoid buffer overflow */ | ||
1320 | } | ||
1321 | |||
1322 | DUMPBITS (bit_buf, bits, 4); /* dump end of block code */ | ||
1323 | decoder->bitstream_buf = bit_buf; | ||
1324 | decoder->bitstream_bits = bits; | ||
1325 | decoder->bitstream_ptr = bit_ptr; | ||
1326 | } | ||
1327 | |||
1328 | static void skip_non_intra_block (mpeg2_decoder_t * const decoder) | ||
1329 | { | ||
1330 | uint32_t bit_buf = decoder->bitstream_buf; | ||
1331 | int bits = decoder->bitstream_bits; | ||
1332 | const uint8_t * bit_ptr = decoder->bitstream_ptr; | ||
1333 | int i = -1; | ||
1334 | const DCTtab * tab; | ||
1335 | |||
1336 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1337 | |||
1338 | if (bit_buf >= 0x28000000) | ||
1339 | { | ||
1340 | tab = DCT_B14DC_5 + (UBITS (bit_buf, 5) - 5); | ||
1341 | goto entry_1; | ||
1342 | } | ||
1343 | else | ||
1344 | { | ||
1345 | goto entry_2; | ||
1346 | } | ||
1347 | |||
1348 | while (1) | ||
1349 | { | ||
1350 | if (bit_buf >= 0x28000000) | ||
1351 | { | ||
1352 | tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); | ||
1353 | |||
1354 | entry_1: | ||
1355 | i += tab->run; | ||
1356 | if (i >= 64) | ||
1357 | break; /* end of block */ | ||
1358 | |||
1359 | normal_code: | ||
1360 | bit_buf <<= tab->len + 1; | ||
1361 | bits += tab->len + 1; | ||
1362 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1363 | |||
1364 | continue; | ||
1365 | } | ||
1366 | |||
1367 | entry_2: | ||
1368 | if (bit_buf >= 0x04000000) | ||
1369 | { | ||
1370 | tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); | ||
1371 | |||
1372 | i += tab->run; | ||
1373 | if (i < 64) | ||
1374 | goto normal_code; | ||
1375 | |||
1376 | /* escape code */ | ||
1377 | |||
1378 | i += UBITS (bit_buf << 6, 6) - 64; | ||
1379 | if (i >= 64) | ||
1380 | break; /* illegal, check needed to avoid buffer overflow */ | ||
1381 | |||
1382 | if (decoder->mpeg1) | ||
1383 | { | ||
1384 | DUMPBITS (bit_buf, bits, 12); | ||
1385 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1386 | |||
1387 | if (!(SBITS (bit_buf, 8) & 0x7f)) | ||
1388 | DUMPBITS (bit_buf, bits, 8); | ||
1389 | |||
1390 | DUMPBITS (bit_buf, bits, 8); | ||
1391 | } | ||
1392 | else | ||
1393 | { | ||
1394 | DUMPBITS (bit_buf, bits, 12); | ||
1395 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1396 | DUMPBITS (bit_buf, bits, 12); | ||
1397 | } | ||
1398 | |||
1399 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1400 | continue; | ||
1401 | } | ||
1402 | else if (bit_buf >= 0x02000000) | ||
1403 | { | ||
1404 | tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); | ||
1405 | i += tab->run; | ||
1406 | if (i < 64) | ||
1407 | goto normal_code; | ||
1408 | } | ||
1409 | else if (bit_buf >= 0x00800000) | ||
1410 | { | ||
1411 | tab = DCT_13 + (UBITS (bit_buf, 13) - 16); | ||
1412 | i += tab->run; | ||
1413 | if (i < 64) | ||
1414 | goto normal_code; | ||
1415 | } | ||
1416 | else if (bit_buf >= 0x00200000) | ||
1417 | { | ||
1418 | tab = DCT_15 + (UBITS (bit_buf, 15) - 16); | ||
1419 | i += tab->run; | ||
1420 | if (i < 64) | ||
1421 | goto normal_code; | ||
1422 | } | ||
1423 | else | ||
1424 | { | ||
1425 | tab = DCT_16 + UBITS (bit_buf, 16); | ||
1426 | bit_buf <<= 16; | ||
1427 | GETWORD (bit_buf, bits + 16, bit_ptr); | ||
1428 | i += tab->run; | ||
1429 | if (i < 64) | ||
1430 | goto normal_code; | ||
1431 | } | ||
1432 | break; /* illegal, check needed to avoid buffer overflow */ | ||
1433 | } | ||
1434 | |||
1435 | DUMPBITS (bit_buf, bits, 2); /* dump end of block code */ | ||
1436 | decoder->bitstream_buf = bit_buf; | ||
1437 | decoder->bitstream_bits = bits; | ||
1438 | decoder->bitstream_ptr = bit_ptr; | ||
1439 | } | ||
1440 | |||
1441 | static void skip_chroma_dc_dct_diff (mpeg2_decoder_t * const decoder) | ||
1442 | { | ||
1443 | #define bit_buf (decoder->bitstream_buf) | ||
1444 | #define bits (decoder->bitstream_bits) | ||
1445 | #define bit_ptr (decoder->bitstream_ptr) | ||
1446 | |||
1447 | const DCtab * tab; | ||
1448 | int size; | ||
1449 | |||
1450 | if (bit_buf < 0xf8000000) | ||
1451 | { | ||
1452 | tab = DC_chrom_5 + UBITS (bit_buf, 5); | ||
1453 | size = tab->size; | ||
1454 | |||
1455 | if (size) | ||
1456 | { | ||
1457 | bits += tab->len + size; | ||
1458 | bit_buf <<= tab->len; | ||
1459 | bit_buf <<= size; | ||
1460 | } | ||
1461 | else | ||
1462 | { | ||
1463 | DUMPBITS (bit_buf, bits, 2); | ||
1464 | } | ||
1465 | } | ||
1466 | else | ||
1467 | { | ||
1468 | tab = DC_long + (UBITS (bit_buf, 10) - 0x3e0); | ||
1469 | size = tab->size; | ||
1470 | DUMPBITS (bit_buf, bits, tab->len + 1); | ||
1471 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1472 | DUMPBITS (bit_buf, bits, size); | ||
1473 | } | ||
1474 | |||
1475 | #undef bit_buf | ||
1476 | #undef bits | ||
1477 | #undef bit_ptr | ||
1478 | } | ||
1479 | |||
1480 | static void skip_chroma_non_intra (mpeg2_decoder_t * const decoder, | ||
1481 | uint32_t coded_block_pattern) | ||
1482 | { | ||
1483 | static const uint32_t cbp_mask[3] = | ||
1484 | { | ||
1485 | 0x00000030, | ||
1486 | 0xc0000030, | ||
1487 | 0xfc000030, | ||
1488 | }; | ||
1489 | |||
1490 | uint32_t cbp = coded_block_pattern & | ||
1491 | cbp_mask[MIN((unsigned)decoder->chroma_format, 2u)]; | ||
1492 | |||
1493 | while (cbp) | ||
1494 | { | ||
1495 | skip_non_intra_block (decoder); | ||
1496 | cbp &= (cbp - 1); | ||
1497 | } | ||
1498 | } | ||
1499 | |||
1500 | static void skip_chroma_intra (mpeg2_decoder_t * const decoder) | ||
1501 | { | ||
1502 | #define bit_buf (decoder->bitstream_buf) | ||
1503 | #define bits (decoder->bitstream_bits) | ||
1504 | #define bit_ptr (decoder->bitstream_ptr) | ||
1505 | int i = 2 << decoder->chroma_format; | ||
1506 | |||
1507 | if ((unsigned)i > 8) | ||
1508 | i = 8; | ||
1509 | |||
1510 | while (i-- > 0) | ||
1511 | { | ||
1512 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1513 | |||
1514 | skip_chroma_dc_dct_diff (decoder); | ||
1515 | |||
1516 | if (decoder->mpeg1) | ||
1517 | { | ||
1518 | if (decoder->coding_type != D_TYPE) | ||
1519 | skip_mpeg1_intra_block (decoder); | ||
1520 | } | ||
1521 | else if (decoder->intra_vlc_format) | ||
1522 | { | ||
1523 | skip_intra_block_B15 (decoder); | ||
1524 | } | ||
1525 | else | ||
1526 | { | ||
1527 | skip_intra_block_B14 (decoder); | ||
1528 | } | ||
1529 | } | ||
1530 | |||
1531 | if (decoder->chroma_format == 0 && decoder->coding_type == D_TYPE) | ||
1532 | { | ||
1533 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1534 | DUMPBITS (bit_buf, bits, 1); | ||
1535 | } | ||
1536 | |||
1537 | #undef bit_buf | ||
1538 | #undef bits | ||
1539 | #undef bit_ptr | ||
1540 | } | ||
1541 | #endif /* !MPEG2_COLOR */ | ||
1542 | |||
1543 | #define MOTION_420(table, ref, motion_x, motion_y, size, y) \ | ||
1544 | pos_x = 2 * decoder->offset + motion_x; \ | ||
1545 | pos_y = 2 * decoder->v_offset + motion_y + 2 * y; \ | ||
1546 | \ | ||
1547 | if (unlikely (pos_x > decoder->limit_x)) \ | ||
1548 | { \ | ||
1549 | pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \ | ||
1550 | motion_x = pos_x - 2 * decoder->offset; \ | ||
1551 | } \ | ||
1552 | \ | ||
1553 | if (unlikely (pos_y > decoder->limit_y_ ## size)) \ | ||
1554 | { \ | ||
1555 | pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y_ ## size; \ | ||
1556 | motion_y = pos_y - 2 * decoder->v_offset - 2 * y; \ | ||
1557 | } \ | ||
1558 | \ | ||
1559 | xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \ | ||
1560 | table[xy_half] (decoder->dest[0] + y * decoder->stride + decoder->offset, \ | ||
1561 | ref[0] + (pos_x >> 1) + (pos_y >> 1) * decoder->stride, \ | ||
1562 | decoder->stride, size); \ | ||
1563 | \ | ||
1564 | if (MPEG2_COLOR) \ | ||
1565 | { \ | ||
1566 | motion_x /= 2; \ | ||
1567 | motion_y /= 2; \ | ||
1568 | xy_half = ((motion_y & 1) << 1) | (motion_x & 1); \ | ||
1569 | offset = ((decoder->offset + motion_x) >> 1) + \ | ||
1570 | ((((decoder->v_offset + motion_y) >> 1) + y/2) * \ | ||
1571 | decoder->uv_stride); \ | ||
1572 | \ | ||
1573 | table[4+xy_half] (decoder->dest[1] + y/2 * decoder->uv_stride + \ | ||
1574 | (decoder->offset >> 1), ref[1] + offset, \ | ||
1575 | decoder->uv_stride, size/2); \ | ||
1576 | table[4+xy_half] (decoder->dest[2] + y/2 * decoder->uv_stride + \ | ||
1577 | (decoder->offset >> 1), ref[2] + offset, \ | ||
1578 | decoder->uv_stride, size/2); \ | ||
1579 | } | ||
1580 | |||
1581 | #define MOTION_FIELD_420(table, ref, motion_x, motion_y, \ | ||
1582 | dest_field, op, src_field) \ | ||
1583 | pos_x = 2 * decoder->offset + motion_x; \ | ||
1584 | pos_y = decoder->v_offset + motion_y; \ | ||
1585 | \ | ||
1586 | if (unlikely (pos_x > decoder->limit_x)) \ | ||
1587 | { \ | ||
1588 | pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \ | ||
1589 | motion_x = pos_x - 2 * decoder->offset; \ | ||
1590 | } \ | ||
1591 | \ | ||
1592 | if (unlikely (pos_y > decoder->limit_y)) \ | ||
1593 | { \ | ||
1594 | pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y; \ | ||
1595 | motion_y = pos_y - decoder->v_offset; \ | ||
1596 | } \ | ||
1597 | \ | ||
1598 | xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \ | ||
1599 | table[xy_half] (decoder->dest[0] + dest_field * decoder->stride + \ | ||
1600 | decoder->offset, \ | ||
1601 | (ref[0] + (pos_x >> 1) + \ | ||
1602 | ((pos_y op) + src_field) * decoder->stride), \ | ||
1603 | 2 * decoder->stride, 8); \ | ||
1604 | \ | ||
1605 | if (MPEG2_COLOR) \ | ||
1606 | { \ | ||
1607 | motion_x /= 2; \ | ||
1608 | motion_y /= 2; \ | ||
1609 | xy_half = ((motion_y & 1) << 1) | (motion_x & 1); \ | ||
1610 | offset = ((decoder->offset + motion_x) >> 1) + \ | ||
1611 | (((decoder->v_offset >> 1) + (motion_y op) + src_field) * \ | ||
1612 | decoder->uv_stride); \ | ||
1613 | \ | ||
1614 | table[4+xy_half] (decoder->dest[1] + dest_field * decoder->uv_stride + \ | ||
1615 | (decoder->offset >> 1), ref[1] + offset, \ | ||
1616 | 2 * decoder->uv_stride, 4); \ | ||
1617 | table[4+xy_half] (decoder->dest[2] + dest_field * decoder->uv_stride + \ | ||
1618 | (decoder->offset >> 1), ref[2] + offset, \ | ||
1619 | 2 * decoder->uv_stride, 4); \ | ||
1620 | } | ||
1621 | |||
1622 | #define MOTION_DMV_420(table, ref, motion_x, motion_y) \ | ||
1623 | pos_x = 2 * decoder->offset + motion_x; \ | ||
1624 | pos_y = decoder->v_offset + motion_y; \ | ||
1625 | \ | ||
1626 | if (unlikely (pos_x > decoder->limit_x)) \ | ||
1627 | { \ | ||
1628 | pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \ | ||
1629 | motion_x = pos_x - 2 * decoder->offset; \ | ||
1630 | } \ | ||
1631 | \ | ||
1632 | if (unlikely (pos_y > decoder->limit_y)) \ | ||
1633 | { \ | ||
1634 | pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y; \ | ||
1635 | motion_y = pos_y - decoder->v_offset; \ | ||
1636 | } \ | ||
1637 | \ | ||
1638 | xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \ | ||
1639 | offset = (pos_x >> 1) + (pos_y & ~1) * decoder->stride; \ | ||
1640 | table[xy_half] (decoder->dest[0] + decoder->offset, \ | ||
1641 | ref[0] + offset, 2 * decoder->stride, 8); \ | ||
1642 | table[xy_half] (decoder->dest[0] + decoder->stride + decoder->offset, \ | ||
1643 | ref[0] + decoder->stride + offset, \ | ||
1644 | 2 * decoder->stride, 8); \ | ||
1645 | \ | ||
1646 | if (MPEG2_COLOR) \ | ||
1647 | { \ | ||
1648 | motion_x /= 2; \ | ||
1649 | motion_y /= 2; \ | ||
1650 | xy_half = ((motion_y & 1) << 1) | (motion_x & 1); \ | ||
1651 | offset = ((decoder->offset + motion_x) >> 1) + \ | ||
1652 | (((decoder->v_offset >> 1) + (motion_y & ~1)) * \ | ||
1653 | decoder->uv_stride); \ | ||
1654 | \ | ||
1655 | table[4+xy_half] (decoder->dest[1] + (decoder->offset >> 1), \ | ||
1656 | ref[1] + offset, 2 * decoder->uv_stride, 4); \ | ||
1657 | table[4+xy_half] (decoder->dest[1] + decoder->uv_stride + \ | ||
1658 | (decoder->offset >> 1), \ | ||
1659 | ref[1] + decoder->uv_stride + offset, \ | ||
1660 | 2 * decoder->uv_stride, 4); \ | ||
1661 | table[4+xy_half] (decoder->dest[2] + (decoder->offset >> 1), \ | ||
1662 | ref[2] + offset, 2 * decoder->uv_stride, 4); \ | ||
1663 | table[4+xy_half] (decoder->dest[2] + decoder->uv_stride + \ | ||
1664 | (decoder->offset >> 1), \ | ||
1665 | ref[2] + decoder->uv_stride + offset, \ | ||
1666 | 2 * decoder->uv_stride, 4); \ | ||
1667 | } | ||
1668 | |||
1669 | #define MOTION_ZERO_420(table, ref) \ | ||
1670 | table[0] (decoder->dest[0] + decoder->offset, \ | ||
1671 | (ref[0] + decoder->offset + \ | ||
1672 | decoder->v_offset * decoder->stride), decoder->stride, 16); \ | ||
1673 | \ | ||
1674 | if (MPEG2_COLOR) \ | ||
1675 | { \ | ||
1676 | offset = ((decoder->offset >> 1) + \ | ||
1677 | (decoder->v_offset >> 1) * decoder->uv_stride); \ | ||
1678 | \ | ||
1679 | table[4] (decoder->dest[1] + (decoder->offset >> 1), \ | ||
1680 | ref[1] + offset, decoder->uv_stride, 8); \ | ||
1681 | table[4] (decoder->dest[2] + (decoder->offset >> 1), \ | ||
1682 | ref[2] + offset, decoder->uv_stride, 8); \ | ||
1683 | } | ||
1684 | |||
1685 | #define MOTION_422(table, ref, motion_x, motion_y, size, y) \ | ||
1686 | pos_x = 2 * decoder->offset + motion_x; \ | ||
1687 | pos_y = 2 * decoder->v_offset + motion_y + 2 * y; \ | ||
1688 | \ | ||
1689 | if (unlikely (pos_x > decoder->limit_x)) \ | ||
1690 | { \ | ||
1691 | pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \ | ||
1692 | motion_x = pos_x - 2 * decoder->offset; \ | ||
1693 | } \ | ||
1694 | \ | ||
1695 | if (unlikely (pos_y > decoder->limit_y_ ## size)) \ | ||
1696 | { \ | ||
1697 | pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y_ ## size; \ | ||
1698 | motion_y = pos_y - 2 * decoder->v_offset - 2 * y; \ | ||
1699 | } \ | ||
1700 | \ | ||
1701 | xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \ | ||
1702 | offset = (pos_x >> 1) + (pos_y >> 1) * decoder->stride; \ | ||
1703 | \ | ||
1704 | table[xy_half] (decoder->dest[0] + y * decoder->stride + decoder->offset, \ | ||
1705 | ref[0] + offset, decoder->stride, size); \ | ||
1706 | \ | ||
1707 | if (MPEG2_COLOR) \ | ||
1708 | { \ | ||
1709 | offset = (offset + (motion_x & (motion_x < 0))) >> 1; \ | ||
1710 | motion_x /= 2; \ | ||
1711 | xy_half = ((pos_y & 1) << 1) | (motion_x & 1); \ | ||
1712 | \ | ||
1713 | table[4+xy_half] (decoder->dest[1] + y * decoder->uv_stride + \ | ||
1714 | (decoder->offset >> 1), ref[1] + offset, \ | ||
1715 | decoder->uv_stride, size); \ | ||
1716 | table[4+xy_half] (decoder->dest[2] + y * decoder->uv_stride + \ | ||
1717 | (decoder->offset >> 1), ref[2] + offset, \ | ||
1718 | decoder->uv_stride, size); \ | ||
1719 | } | ||
1720 | |||
1721 | #define MOTION_FIELD_422(table, ref, motion_x, motion_y, \ | ||
1722 | dest_field, op, src_field) \ | ||
1723 | pos_x = 2 * decoder->offset + motion_x; \ | ||
1724 | pos_y = decoder->v_offset + motion_y; \ | ||
1725 | \ | ||
1726 | if (unlikely (pos_x > decoder->limit_x)) \ | ||
1727 | { \ | ||
1728 | pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \ | ||
1729 | motion_x = pos_x - 2 * decoder->offset; \ | ||
1730 | } \ | ||
1731 | \ | ||
1732 | if (unlikely (pos_y > decoder->limit_y)) \ | ||
1733 | { \ | ||
1734 | pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y; \ | ||
1735 | motion_y = pos_y - decoder->v_offset; \ | ||
1736 | } \ | ||
1737 | \ | ||
1738 | xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \ | ||
1739 | offset = (pos_x >> 1) + ((pos_y op) + src_field) * decoder->stride; \ | ||
1740 | \ | ||
1741 | table[xy_half] (decoder->dest[0] + dest_field * decoder->stride + \ | ||
1742 | decoder->offset, ref[0] + offset, \ | ||
1743 | 2 * decoder->stride, 8); \ | ||
1744 | \ | ||
1745 | if (MPEG2_COLOR) \ | ||
1746 | { \ | ||
1747 | offset = (offset + (motion_x & (motion_x < 0))) >> 1; \ | ||
1748 | motion_x /= 2; \ | ||
1749 | xy_half = ((pos_y & 1) << 1) | (motion_x & 1); \ | ||
1750 | \ | ||
1751 | table[4+xy_half] (decoder->dest[1] + dest_field * decoder->uv_stride + \ | ||
1752 | (decoder->offset >> 1), ref[1] + offset, \ | ||
1753 | 2 * decoder->uv_stride, 8); \ | ||
1754 | table[4+xy_half] (decoder->dest[2] + dest_field * decoder->uv_stride + \ | ||
1755 | (decoder->offset >> 1), ref[2] + offset, \ | ||
1756 | 2 * decoder->uv_stride, 8); \ | ||
1757 | } | ||
1758 | |||
1759 | #define MOTION_DMV_422(table, ref, motion_x, motion_y) \ | ||
1760 | pos_x = 2 * decoder->offset + motion_x; \ | ||
1761 | pos_y = decoder->v_offset + motion_y; \ | ||
1762 | \ | ||
1763 | if (unlikely (pos_x > decoder->limit_x)) \ | ||
1764 | { \ | ||
1765 | pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \ | ||
1766 | motion_x = pos_x - 2 * decoder->offset; \ | ||
1767 | } \ | ||
1768 | \ | ||
1769 | if (unlikely (pos_y > decoder->limit_y)) \ | ||
1770 | { \ | ||
1771 | pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y; \ | ||
1772 | motion_y = pos_y - decoder->v_offset; \ | ||
1773 | } \ | ||
1774 | \ | ||
1775 | xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \ | ||
1776 | offset = (pos_x >> 1) + (pos_y & ~1) * decoder->stride; \ | ||
1777 | \ | ||
1778 | table[xy_half] (decoder->dest[0] + decoder->offset, \ | ||
1779 | ref[0] + offset, 2 * decoder->stride, 8); \ | ||
1780 | table[xy_half] (decoder->dest[0] + decoder->stride + decoder->offset, \ | ||
1781 | ref[0] + decoder->stride + offset, \ | ||
1782 | 2 * decoder->stride, 8); \ | ||
1783 | \ | ||
1784 | if (MPEG2_COLOR) \ | ||
1785 | { \ | ||
1786 | offset = (offset + (motion_x & (motion_x < 0))) >> 1; \ | ||
1787 | motion_x /= 2; \ | ||
1788 | xy_half = ((pos_y & 1) << 1) | (motion_x & 1); \ | ||
1789 | \ | ||
1790 | table[4+xy_half] (decoder->dest[1] + (decoder->offset >> 1), \ | ||
1791 | ref[1] + offset, 2 * decoder->uv_stride, 8); \ | ||
1792 | table[4+xy_half] (decoder->dest[1] + decoder->uv_stride + \ | ||
1793 | (decoder->offset >> 1), \ | ||
1794 | ref[1] + decoder->uv_stride + offset, \ | ||
1795 | 2 * decoder->uv_stride, 8); \ | ||
1796 | table[4+xy_half] (decoder->dest[2] + (decoder->offset >> 1), \ | ||
1797 | ref[2] + offset, 2 * decoder->uv_stride, 8); \ | ||
1798 | table[4+xy_half] (decoder->dest[2] + decoder->uv_stride + \ | ||
1799 | (decoder->offset >> 1), \ | ||
1800 | ref[2] + decoder->uv_stride + offset, \ | ||
1801 | 2 * decoder->uv_stride, 8); \ | ||
1802 | } | ||
1803 | |||
1804 | #define MOTION_ZERO_422(table, ref) \ | ||
1805 | offset = decoder->offset + decoder->v_offset * decoder->stride; \ | ||
1806 | table[0] (decoder->dest[0] + decoder->offset, \ | ||
1807 | ref[0] + offset, decoder->stride, 16); \ | ||
1808 | \ | ||
1809 | if (MPEG2_COLOR) \ | ||
1810 | { \ | ||
1811 | offset >>= 1; \ | ||
1812 | table[4] (decoder->dest[1] + (decoder->offset >> 1), \ | ||
1813 | ref[1] + offset, decoder->uv_stride, 16); \ | ||
1814 | table[4] (decoder->dest[2] + (decoder->offset >> 1), \ | ||
1815 | ref[2] + offset, decoder->uv_stride, 16); \ | ||
1816 | } | ||
1817 | |||
1818 | #define MOTION_444(table, ref, motion_x, motion_y, size, y) \ | ||
1819 | pos_x = 2 * decoder->offset + motion_x; \ | ||
1820 | pos_y = 2 * decoder->v_offset + motion_y + 2 * y; \ | ||
1821 | \ | ||
1822 | if (unlikely (pos_x > decoder->limit_x)) \ | ||
1823 | { \ | ||
1824 | pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \ | ||
1825 | motion_x = pos_x - 2 * decoder->offset; \ | ||
1826 | } \ | ||
1827 | \ | ||
1828 | if (unlikely (pos_y > decoder->limit_y_ ## size)) \ | ||
1829 | { \ | ||
1830 | pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y_ ## size; \ | ||
1831 | motion_y = pos_y - 2 * decoder->v_offset - 2 * y; \ | ||
1832 | } \ | ||
1833 | \ | ||
1834 | xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \ | ||
1835 | offset = (pos_x >> 1) + (pos_y >> 1) * decoder->stride; \ | ||
1836 | \ | ||
1837 | table[xy_half] (decoder->dest[0] + y * decoder->stride + decoder->offset, \ | ||
1838 | ref[0] + offset, decoder->stride, size); \ | ||
1839 | \ | ||
1840 | if (MPEG2_COLOR) \ | ||
1841 | { \ | ||
1842 | table[xy_half] (decoder->dest[1] + y * decoder->stride + decoder->offset, \ | ||
1843 | ref[1] + offset, decoder->stride, size); \ | ||
1844 | table[xy_half] (decoder->dest[2] + y * decoder->stride + decoder->offset, \ | ||
1845 | ref[2] + offset, decoder->stride, size); \ | ||
1846 | } | ||
1847 | |||
1848 | #define MOTION_FIELD_444(table, ref, motion_x, motion_y, \ | ||
1849 | dest_field, op, src_field) \ | ||
1850 | pos_x = 2 * decoder->offset + motion_x; \ | ||
1851 | pos_y = decoder->v_offset + motion_y; \ | ||
1852 | \ | ||
1853 | if (unlikely (pos_x > decoder->limit_x)) \ | ||
1854 | { \ | ||
1855 | pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \ | ||
1856 | motion_x = pos_x - 2 * decoder->offset; \ | ||
1857 | } \ | ||
1858 | \ | ||
1859 | if (unlikely (pos_y > decoder->limit_y)) \ | ||
1860 | { \ | ||
1861 | pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y; \ | ||
1862 | motion_y = pos_y - decoder->v_offset; \ | ||
1863 | } \ | ||
1864 | \ | ||
1865 | xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \ | ||
1866 | offset = (pos_x >> 1) + ((pos_y op) + src_field) * decoder->stride; \ | ||
1867 | \ | ||
1868 | table[xy_half] (decoder->dest[0] + dest_field * decoder->stride + \ | ||
1869 | decoder->offset, ref[0] + offset, \ | ||
1870 | 2 * decoder->stride, 8); \ | ||
1871 | \ | ||
1872 | if (MPEG2_COLOR) \ | ||
1873 | { \ | ||
1874 | table[xy_half] (decoder->dest[1] + dest_field * decoder->stride + \ | ||
1875 | decoder->offset, ref[1] + offset, \ | ||
1876 | 2 * decoder->stride, 8); \ | ||
1877 | table[xy_half] (decoder->dest[2] + dest_field * decoder->stride + \ | ||
1878 | decoder->offset, ref[2] + offset, \ | ||
1879 | 2 * decoder->stride, 8); \ | ||
1880 | } | ||
1881 | |||
1882 | #define MOTION_DMV_444(table, ref, motion_x, motion_y) \ | ||
1883 | pos_x = 2 * decoder->offset + motion_x; \ | ||
1884 | pos_y = decoder->v_offset + motion_y; \ | ||
1885 | \ | ||
1886 | if (unlikely (pos_x > decoder->limit_x)) \ | ||
1887 | { \ | ||
1888 | pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \ | ||
1889 | motion_x = pos_x - 2 * decoder->offset; \ | ||
1890 | } \ | ||
1891 | \ | ||
1892 | if (unlikely (pos_y > decoder->limit_y)) \ | ||
1893 | { \ | ||
1894 | pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y; \ | ||
1895 | motion_y = pos_y - decoder->v_offset; \ | ||
1896 | } \ | ||
1897 | \ | ||
1898 | xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \ | ||
1899 | offset = (pos_x >> 1) + (pos_y & ~1) * decoder->stride; \ | ||
1900 | \ | ||
1901 | table[xy_half] (decoder->dest[0] + decoder->offset, \ | ||
1902 | ref[0] + offset, 2 * decoder->stride, 8); \ | ||
1903 | table[xy_half] (decoder->dest[0] + decoder->stride + decoder->offset, \ | ||
1904 | ref[0] + decoder->stride + offset, \ | ||
1905 | 2 * decoder->stride, 8); \ | ||
1906 | \ | ||
1907 | if (MPEG2_COLOR) \ | ||
1908 | { \ | ||
1909 | table[xy_half] (decoder->dest[1] + decoder->offset, \ | ||
1910 | ref[1] + offset, 2 * decoder->stride, 8); \ | ||
1911 | table[xy_half] (decoder->dest[1] + decoder->stride + decoder->offset, \ | ||
1912 | ref[1] + decoder->stride + offset, \ | ||
1913 | 2 * decoder->stride, 8); \ | ||
1914 | table[xy_half] (decoder->dest[2] + decoder->offset, \ | ||
1915 | ref[2] + offset, 2 * decoder->stride, 8); \ | ||
1916 | table[xy_half] (decoder->dest[2] + decoder->stride + decoder->offset, \ | ||
1917 | ref[2] + decoder->stride + offset, \ | ||
1918 | 2 * decoder->stride, 8); \ | ||
1919 | } | ||
1920 | |||
1921 | #define MOTION_ZERO_444(table, ref) \ | ||
1922 | offset = decoder->offset + decoder->v_offset * decoder->stride; \ | ||
1923 | \ | ||
1924 | table[0] (decoder->dest[0] + decoder->offset, \ | ||
1925 | ref[0] + offset, decoder->stride, 16); \ | ||
1926 | \ | ||
1927 | if (MPEG2_COLOR) \ | ||
1928 | { \ | ||
1929 | table[4] (decoder->dest[1] + decoder->offset, \ | ||
1930 | ref[1] + offset, decoder->stride, 16); \ | ||
1931 | table[4] (decoder->dest[2] + decoder->offset, \ | ||
1932 | ref[2] + offset, decoder->stride, 16); \ | ||
1933 | } | ||
1934 | |||
1935 | #define bit_buf (decoder->bitstream_buf) | ||
1936 | #define bits (decoder->bitstream_bits) | ||
1937 | #define bit_ptr (decoder->bitstream_ptr) | ||
1938 | |||
1939 | static void motion_mp1 (mpeg2_decoder_t * const decoder, | ||
1940 | motion_t * const motion, | ||
1941 | mpeg2_mc_fct * const * const table) | ||
1942 | { | ||
1943 | int motion_x, motion_y; | ||
1944 | unsigned int pos_x, pos_y, xy_half, offset; | ||
1945 | |||
1946 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1947 | motion_x = motion->pmv[0][0] + | ||
1948 | (get_motion_delta (decoder, | ||
1949 | motion->f_code[0]) << motion->f_code[1]); | ||
1950 | motion_x = bound_motion_vector (motion_x, | ||
1951 | motion->f_code[0] + motion->f_code[1]); | ||
1952 | motion->pmv[0][0] = motion_x; | ||
1953 | |||
1954 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
1955 | motion_y = motion->pmv[0][1] + | ||
1956 | (get_motion_delta (decoder, | ||
1957 | motion->f_code[0]) << motion->f_code[1]); | ||
1958 | motion_y = bound_motion_vector (motion_y, | ||
1959 | motion->f_code[0] + motion->f_code[1]); | ||
1960 | motion->pmv[0][1] = motion_y; | ||
1961 | |||
1962 | MOTION_420 (table, motion->ref[0], motion_x, motion_y, 16, 0); | ||
1963 | } | ||
1964 | |||
1965 | #define MOTION_FUNCTIONS(FORMAT, MOTION, MOTION_FIELD, \ | ||
1966 | MOTION_DMV, MOTION_ZERO) \ | ||
1967 | \ | ||
1968 | static void motion_fr_frame_##FORMAT (mpeg2_decoder_t * const decoder, \ | ||
1969 | motion_t * const motion, \ | ||
1970 | mpeg2_mc_fct * const * const table) \ | ||
1971 | { \ | ||
1972 | int motion_x, motion_y; \ | ||
1973 | unsigned int pos_x, pos_y, xy_half, offset; \ | ||
1974 | \ | ||
1975 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
1976 | motion_x = motion->pmv[0][0] + get_motion_delta (decoder, \ | ||
1977 | motion->f_code[0]); \ | ||
1978 | motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \ | ||
1979 | motion->pmv[1][0] = motion->pmv[0][0] = motion_x; \ | ||
1980 | \ | ||
1981 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
1982 | motion_y = motion->pmv[0][1] + get_motion_delta (decoder, \ | ||
1983 | motion->f_code[1]); \ | ||
1984 | motion_y = bound_motion_vector (motion_y, motion->f_code[1]); \ | ||
1985 | motion->pmv[1][1] = motion->pmv[0][1] = motion_y; \ | ||
1986 | \ | ||
1987 | MOTION (table, motion->ref[0], motion_x, motion_y, 16, 0); \ | ||
1988 | } \ | ||
1989 | \ | ||
1990 | static void motion_fr_field_##FORMAT (mpeg2_decoder_t * const decoder, \ | ||
1991 | motion_t * const motion, \ | ||
1992 | mpeg2_mc_fct * const * const table) \ | ||
1993 | { \ | ||
1994 | int motion_x, motion_y, field; \ | ||
1995 | unsigned int pos_x, pos_y, xy_half, offset; \ | ||
1996 | \ | ||
1997 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
1998 | field = UBITS (bit_buf, 1); \ | ||
1999 | DUMPBITS (bit_buf, bits, 1); \ | ||
2000 | \ | ||
2001 | motion_x = motion->pmv[0][0] + get_motion_delta (decoder, \ | ||
2002 | motion->f_code[0]); \ | ||
2003 | motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \ | ||
2004 | motion->pmv[0][0] = motion_x; \ | ||
2005 | \ | ||
2006 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
2007 | motion_y = ((motion->pmv[0][1] >> 1) + \ | ||
2008 | get_motion_delta (decoder, motion->f_code[1])); \ | ||
2009 | /* motion_y = bound_motion_vector (motion_y, motion->f_code[1]); */ \ | ||
2010 | motion->pmv[0][1] = motion_y << 1; \ | ||
2011 | \ | ||
2012 | MOTION_FIELD (table, motion->ref[0], motion_x, motion_y, 0, & ~1, field); \ | ||
2013 | \ | ||
2014 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
2015 | field = UBITS (bit_buf, 1); \ | ||
2016 | DUMPBITS (bit_buf, bits, 1); \ | ||
2017 | \ | ||
2018 | motion_x = motion->pmv[1][0] + get_motion_delta (decoder, \ | ||
2019 | motion->f_code[0]); \ | ||
2020 | motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \ | ||
2021 | motion->pmv[1][0] = motion_x; \ | ||
2022 | \ | ||
2023 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
2024 | motion_y = ((motion->pmv[1][1] >> 1) + \ | ||
2025 | get_motion_delta (decoder, motion->f_code[1])); \ | ||
2026 | /* motion_y = bound_motion_vector (motion_y, motion->f_code[1]); */ \ | ||
2027 | motion->pmv[1][1] = motion_y << 1; \ | ||
2028 | \ | ||
2029 | MOTION_FIELD (table, motion->ref[0], motion_x, motion_y, 1, & ~1, field); \ | ||
2030 | } \ | ||
2031 | \ | ||
2032 | static void motion_fr_dmv_##FORMAT (mpeg2_decoder_t * const decoder, \ | ||
2033 | motion_t * const motion, \ | ||
2034 | mpeg2_mc_fct * const * const table) \ | ||
2035 | { \ | ||
2036 | int motion_x, motion_y, dmv_x, dmv_y, m, other_x, other_y; \ | ||
2037 | unsigned int pos_x, pos_y, xy_half, offset; \ | ||
2038 | \ | ||
2039 | (void)table; \ | ||
2040 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
2041 | motion_x = motion->pmv[0][0] + get_motion_delta (decoder, \ | ||
2042 | motion->f_code[0]); \ | ||
2043 | motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \ | ||
2044 | motion->pmv[1][0] = motion->pmv[0][0] = motion_x; \ | ||
2045 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
2046 | dmv_x = get_dmv (decoder); \ | ||
2047 | \ | ||
2048 | motion_y = ((motion->pmv[0][1] >> 1) + \ | ||
2049 | get_motion_delta (decoder, motion->f_code[1])); \ | ||
2050 | /* motion_y = bound_motion_vector (motion_y, motion->f_code[1]); */ \ | ||
2051 | motion->pmv[1][1] = motion->pmv[0][1] = motion_y << 1; \ | ||
2052 | dmv_y = get_dmv (decoder); \ | ||
2053 | \ | ||
2054 | m = decoder->top_field_first ? 1 : 3; \ | ||
2055 | other_x = ((motion_x * m + (motion_x > 0)) >> 1) + dmv_x; \ | ||
2056 | other_y = ((motion_y * m + (motion_y > 0)) >> 1) + dmv_y - 1; \ | ||
2057 | MOTION_FIELD (mpeg2_mc.put, motion->ref[0], other_x, other_y, 0, | 1, 0); \ | ||
2058 | \ | ||
2059 | m = decoder->top_field_first ? 3 : 1; \ | ||
2060 | other_x = ((motion_x * m + (motion_x > 0)) >> 1) + dmv_x; \ | ||
2061 | other_y = ((motion_y * m + (motion_y > 0)) >> 1) + dmv_y + 1; \ | ||
2062 | MOTION_FIELD (mpeg2_mc.put, motion->ref[0], other_x, other_y, 1, & ~1, 0);\ | ||
2063 | \ | ||
2064 | MOTION_DMV (mpeg2_mc.avg, motion->ref[0], motion_x, motion_y); \ | ||
2065 | } \ | ||
2066 | \ | ||
2067 | static void motion_reuse_##FORMAT (mpeg2_decoder_t * const decoder, \ | ||
2068 | motion_t * const motion, \ | ||
2069 | mpeg2_mc_fct * const * const table) \ | ||
2070 | { \ | ||
2071 | int motion_x, motion_y; \ | ||
2072 | unsigned int pos_x, pos_y, xy_half, offset; \ | ||
2073 | \ | ||
2074 | motion_x = motion->pmv[0][0]; \ | ||
2075 | motion_y = motion->pmv[0][1]; \ | ||
2076 | \ | ||
2077 | MOTION (table, motion->ref[0], motion_x, motion_y, 16, 0); \ | ||
2078 | } \ | ||
2079 | \ | ||
2080 | static void motion_zero_##FORMAT (mpeg2_decoder_t * const decoder, \ | ||
2081 | motion_t * const motion, \ | ||
2082 | mpeg2_mc_fct * const * const table) \ | ||
2083 | { \ | ||
2084 | unsigned int offset; \ | ||
2085 | \ | ||
2086 | motion->pmv[0][0] = motion->pmv[0][1] = 0; \ | ||
2087 | motion->pmv[1][0] = motion->pmv[1][1] = 0; \ | ||
2088 | \ | ||
2089 | MOTION_ZERO (table, motion->ref[0]); \ | ||
2090 | } \ | ||
2091 | \ | ||
2092 | static void motion_fi_field_##FORMAT (mpeg2_decoder_t * const decoder, \ | ||
2093 | motion_t * const motion, \ | ||
2094 | mpeg2_mc_fct * const * const table) \ | ||
2095 | { \ | ||
2096 | int motion_x, motion_y; \ | ||
2097 | uint8_t ** ref_field; \ | ||
2098 | unsigned int pos_x, pos_y, xy_half, offset; \ | ||
2099 | \ | ||
2100 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
2101 | ref_field = motion->ref2[UBITS (bit_buf, 1)]; \ | ||
2102 | DUMPBITS (bit_buf, bits, 1); \ | ||
2103 | \ | ||
2104 | motion_x = motion->pmv[0][0] + get_motion_delta (decoder, \ | ||
2105 | motion->f_code[0]); \ | ||
2106 | motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \ | ||
2107 | motion->pmv[1][0] = motion->pmv[0][0] = motion_x; \ | ||
2108 | \ | ||
2109 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
2110 | motion_y = motion->pmv[0][1] + get_motion_delta (decoder, \ | ||
2111 | motion->f_code[1]); \ | ||
2112 | motion_y = bound_motion_vector (motion_y, motion->f_code[1]); \ | ||
2113 | motion->pmv[1][1] = motion->pmv[0][1] = motion_y; \ | ||
2114 | \ | ||
2115 | MOTION (table, ref_field, motion_x, motion_y, 16, 0); \ | ||
2116 | } \ | ||
2117 | \ | ||
2118 | static void motion_fi_16x8_##FORMAT (mpeg2_decoder_t * const decoder, \ | ||
2119 | motion_t * const motion, \ | ||
2120 | mpeg2_mc_fct * const * const table) \ | ||
2121 | { \ | ||
2122 | int motion_x, motion_y; \ | ||
2123 | uint8_t ** ref_field; \ | ||
2124 | unsigned int pos_x, pos_y, xy_half, offset; \ | ||
2125 | \ | ||
2126 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
2127 | ref_field = motion->ref2[UBITS (bit_buf, 1)]; \ | ||
2128 | DUMPBITS (bit_buf, bits, 1); \ | ||
2129 | \ | ||
2130 | motion_x = motion->pmv[0][0] + get_motion_delta (decoder, \ | ||
2131 | motion->f_code[0]); \ | ||
2132 | motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \ | ||
2133 | motion->pmv[0][0] = motion_x; \ | ||
2134 | \ | ||
2135 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
2136 | motion_y = motion->pmv[0][1] + get_motion_delta (decoder, \ | ||
2137 | motion->f_code[1]); \ | ||
2138 | motion_y = bound_motion_vector (motion_y, motion->f_code[1]); \ | ||
2139 | motion->pmv[0][1] = motion_y; \ | ||
2140 | \ | ||
2141 | MOTION (table, ref_field, motion_x, motion_y, 8, 0); \ | ||
2142 | \ | ||
2143 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
2144 | ref_field = motion->ref2[UBITS (bit_buf, 1)]; \ | ||
2145 | DUMPBITS (bit_buf, bits, 1); \ | ||
2146 | \ | ||
2147 | motion_x = motion->pmv[1][0] + get_motion_delta (decoder, \ | ||
2148 | motion->f_code[0]); \ | ||
2149 | motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \ | ||
2150 | motion->pmv[1][0] = motion_x; \ | ||
2151 | \ | ||
2152 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
2153 | motion_y = motion->pmv[1][1] + get_motion_delta (decoder, \ | ||
2154 | motion->f_code[1]); \ | ||
2155 | motion_y = bound_motion_vector (motion_y, motion->f_code[1]); \ | ||
2156 | motion->pmv[1][1] = motion_y; \ | ||
2157 | \ | ||
2158 | MOTION (table, ref_field, motion_x, motion_y, 8, 8); \ | ||
2159 | } \ | ||
2160 | \ | ||
2161 | static void motion_fi_dmv_##FORMAT (mpeg2_decoder_t * const decoder, \ | ||
2162 | motion_t * const motion, \ | ||
2163 | mpeg2_mc_fct * const * const table) \ | ||
2164 | { \ | ||
2165 | int motion_x, motion_y, other_x, other_y; \ | ||
2166 | unsigned int pos_x, pos_y, xy_half, offset; \ | ||
2167 | \ | ||
2168 | (void)table; \ | ||
2169 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
2170 | motion_x = motion->pmv[0][0] + get_motion_delta (decoder, \ | ||
2171 | motion->f_code[0]); \ | ||
2172 | motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \ | ||
2173 | motion->pmv[1][0] = motion->pmv[0][0] = motion_x; \ | ||
2174 | NEEDBITS (bit_buf, bits, bit_ptr); \ | ||
2175 | other_x = ((motion_x + (motion_x > 0)) >> 1) + get_dmv (decoder); \ | ||
2176 | \ | ||
2177 | motion_y = motion->pmv[0][1] + get_motion_delta (decoder, \ | ||
2178 | motion->f_code[1]); \ | ||
2179 | motion_y = bound_motion_vector (motion_y, motion->f_code[1]); \ | ||
2180 | motion->pmv[1][1] = motion->pmv[0][1] = motion_y; \ | ||
2181 | other_y = (((motion_y + (motion_y > 0)) >> 1) + get_dmv (decoder) + \ | ||
2182 | decoder->dmv_offset); \ | ||
2183 | \ | ||
2184 | MOTION (mpeg2_mc.put, motion->ref[0], motion_x, motion_y, 16, 0); \ | ||
2185 | MOTION (mpeg2_mc.avg, motion->ref[1], other_x, other_y, 16, 0); \ | ||
2186 | } \ | ||
2187 | |||
2188 | MOTION_FUNCTIONS (420, MOTION_420, MOTION_FIELD_420, MOTION_DMV_420, | ||
2189 | MOTION_ZERO_420) | ||
2190 | MOTION_FUNCTIONS (422, MOTION_422, MOTION_FIELD_422, MOTION_DMV_422, | ||
2191 | MOTION_ZERO_422) | ||
2192 | MOTION_FUNCTIONS (444, MOTION_444, MOTION_FIELD_444, MOTION_DMV_444, | ||
2193 | MOTION_ZERO_444) | ||
2194 | |||
2195 | /* like motion_frame, but parsing without actual motion compensation */ | ||
2196 | static void motion_fr_conceal (mpeg2_decoder_t * const decoder) | ||
2197 | { | ||
2198 | int tmp; | ||
2199 | |||
2200 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
2201 | tmp = (decoder->f_motion.pmv[0][0] + | ||
2202 | get_motion_delta (decoder, decoder->f_motion.f_code[0])); | ||
2203 | tmp = bound_motion_vector (tmp, decoder->f_motion.f_code[0]); | ||
2204 | decoder->f_motion.pmv[1][0] = decoder->f_motion.pmv[0][0] = tmp; | ||
2205 | |||
2206 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
2207 | tmp = (decoder->f_motion.pmv[0][1] + | ||
2208 | get_motion_delta (decoder, decoder->f_motion.f_code[1])); | ||
2209 | tmp = bound_motion_vector (tmp, decoder->f_motion.f_code[1]); | ||
2210 | decoder->f_motion.pmv[1][1] = decoder->f_motion.pmv[0][1] = tmp; | ||
2211 | |||
2212 | DUMPBITS (bit_buf, bits, 1); /* remove marker_bit */ | ||
2213 | } | ||
2214 | |||
2215 | static void motion_fi_conceal (mpeg2_decoder_t * const decoder) | ||
2216 | { | ||
2217 | int tmp; | ||
2218 | |||
2219 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
2220 | DUMPBITS (bit_buf, bits, 1); /* remove field_select */ | ||
2221 | |||
2222 | tmp = decoder->f_motion.pmv[0][0] + | ||
2223 | get_motion_delta (decoder, decoder->f_motion.f_code[0]); | ||
2224 | tmp = bound_motion_vector (tmp, decoder->f_motion.f_code[0]); | ||
2225 | |||
2226 | decoder->f_motion.pmv[1][0] = | ||
2227 | decoder->f_motion.pmv[0][0] = tmp; | ||
2228 | |||
2229 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
2230 | |||
2231 | tmp = (decoder->f_motion.pmv[0][1] + | ||
2232 | get_motion_delta (decoder, decoder->f_motion.f_code[1])); | ||
2233 | tmp = bound_motion_vector (tmp, decoder->f_motion.f_code[1]); | ||
2234 | |||
2235 | decoder->f_motion.pmv[1][1] = | ||
2236 | decoder->f_motion.pmv[0][1] = tmp; | ||
2237 | |||
2238 | DUMPBITS (bit_buf, bits, 1); /* remove marker_bit */ | ||
2239 | } | ||
2240 | |||
2241 | #undef bit_buf | ||
2242 | #undef bits | ||
2243 | #undef bit_ptr | ||
2244 | |||
2245 | #define MOTION_CALL(routine, direction) \ | ||
2246 | do { \ | ||
2247 | if ((direction) & MACROBLOCK_MOTION_FORWARD) \ | ||
2248 | routine (decoder, &decoder->f_motion, mpeg2_mc.put); \ | ||
2249 | \ | ||
2250 | if ((direction) & MACROBLOCK_MOTION_BACKWARD) \ | ||
2251 | { \ | ||
2252 | routine (decoder, &decoder->b_motion, \ | ||
2253 | ((direction) & MACROBLOCK_MOTION_FORWARD ? \ | ||
2254 | mpeg2_mc.avg : mpeg2_mc.put)); \ | ||
2255 | } \ | ||
2256 | } while (0) | ||
2257 | |||
2258 | #define NEXT_MACROBLOCK \ | ||
2259 | do { \ | ||
2260 | decoder->offset += 16; \ | ||
2261 | \ | ||
2262 | if (decoder->offset == decoder->width) \ | ||
2263 | { \ | ||
2264 | do { /* just so we can use the break statement */ \ | ||
2265 | if (decoder->convert) \ | ||
2266 | { \ | ||
2267 | decoder->convert (decoder->convert_id, decoder->dest, \ | ||
2268 | decoder->v_offset); \ | ||
2269 | if (decoder->coding_type == B_TYPE) \ | ||
2270 | break; \ | ||
2271 | } \ | ||
2272 | \ | ||
2273 | decoder->dest[0] += decoder->slice_stride; \ | ||
2274 | if (MPEG2_COLOR) \ | ||
2275 | { \ | ||
2276 | decoder->dest[1] += decoder->slice_uv_stride; \ | ||
2277 | decoder->dest[2] += decoder->slice_uv_stride; \ | ||
2278 | } \ | ||
2279 | } while (0); \ | ||
2280 | \ | ||
2281 | decoder->v_offset += 16; \ | ||
2282 | \ | ||
2283 | if (decoder->v_offset > decoder->limit_y) \ | ||
2284 | return; \ | ||
2285 | \ | ||
2286 | decoder->offset = 0; \ | ||
2287 | } \ | ||
2288 | } while (0) | ||
2289 | |||
2290 | void mpeg2_init_fbuf (mpeg2_decoder_t * decoder, | ||
2291 | uint8_t * current_fbuf[MPEG2_COMPONENTS], | ||
2292 | uint8_t * forward_fbuf[MPEG2_COMPONENTS], | ||
2293 | uint8_t * backward_fbuf[MPEG2_COMPONENTS]) | ||
2294 | { | ||
2295 | int offset, stride, height, bottom_field; | ||
2296 | |||
2297 | stride = decoder->stride_frame; | ||
2298 | bottom_field = (decoder->picture_structure == BOTTOM_FIELD); | ||
2299 | offset = bottom_field ? stride : 0; | ||
2300 | height = decoder->height; | ||
2301 | |||
2302 | decoder->picture_dest[0] = current_fbuf[0] + offset; | ||
2303 | #if MPEG2_COLOR | ||
2304 | decoder->picture_dest[1] = current_fbuf[1] + (offset >> 1); | ||
2305 | decoder->picture_dest[2] = current_fbuf[2] + (offset >> 1); | ||
2306 | #endif | ||
2307 | |||
2308 | decoder->f_motion.ref[0][0] = forward_fbuf[0] + offset; | ||
2309 | #if MPEG2_COLOR | ||
2310 | decoder->f_motion.ref[0][1] = forward_fbuf[1] + (offset >> 1); | ||
2311 | decoder->f_motion.ref[0][2] = forward_fbuf[2] + (offset >> 1); | ||
2312 | #endif | ||
2313 | |||
2314 | decoder->b_motion.ref[0][0] = backward_fbuf[0] + offset; | ||
2315 | #if MPEG2_COLOR | ||
2316 | decoder->b_motion.ref[0][1] = backward_fbuf[1] + (offset >> 1); | ||
2317 | decoder->b_motion.ref[0][2] = backward_fbuf[2] + (offset >> 1); | ||
2318 | #endif | ||
2319 | |||
2320 | if (decoder->picture_structure != FRAME_PICTURE) | ||
2321 | { | ||
2322 | decoder->dmv_offset = bottom_field ? 1 : -1; | ||
2323 | decoder->f_motion.ref2[0] = decoder->f_motion.ref[bottom_field]; | ||
2324 | decoder->f_motion.ref2[1] = decoder->f_motion.ref[!bottom_field]; | ||
2325 | decoder->b_motion.ref2[0] = decoder->b_motion.ref[bottom_field]; | ||
2326 | decoder->b_motion.ref2[1] = decoder->b_motion.ref[!bottom_field]; | ||
2327 | offset = stride - offset; | ||
2328 | |||
2329 | if (decoder->second_field && (decoder->coding_type != B_TYPE)) | ||
2330 | forward_fbuf = current_fbuf; | ||
2331 | |||
2332 | decoder->f_motion.ref[1][0] = forward_fbuf[0] + offset; | ||
2333 | #if MPEG2_COLOR | ||
2334 | decoder->f_motion.ref[1][1] = forward_fbuf[1] + (offset >> 1); | ||
2335 | decoder->f_motion.ref[1][2] = forward_fbuf[2] + (offset >> 1); | ||
2336 | #endif | ||
2337 | decoder->b_motion.ref[1][0] = backward_fbuf[0] + offset; | ||
2338 | #if MPEG2_COLOR | ||
2339 | decoder->b_motion.ref[1][1] = backward_fbuf[1] + (offset >> 1); | ||
2340 | decoder->b_motion.ref[1][2] = backward_fbuf[2] + (offset >> 1); | ||
2341 | #endif | ||
2342 | stride <<= 1; | ||
2343 | height >>= 1; | ||
2344 | } | ||
2345 | |||
2346 | decoder->stride = stride; | ||
2347 | decoder->slice_stride = 16 * stride; | ||
2348 | #if MPEG2_COLOR | ||
2349 | decoder->uv_stride = stride >> 1; | ||
2350 | decoder->slice_uv_stride = | ||
2351 | decoder->slice_stride >> (2 - decoder->chroma_format); | ||
2352 | #endif | ||
2353 | decoder->limit_x = 2 * decoder->width - 32; | ||
2354 | decoder->limit_y_16 = 2 * height - 32; | ||
2355 | decoder->limit_y_8 = 2 * height - 16; | ||
2356 | decoder->limit_y = height - 16; | ||
2357 | |||
2358 | if (decoder->mpeg1) | ||
2359 | { | ||
2360 | decoder->motion_parser[0] = motion_zero_420; | ||
2361 | decoder->motion_parser[MC_FRAME] = motion_mp1; | ||
2362 | decoder->motion_parser[4] = motion_reuse_420; | ||
2363 | } | ||
2364 | else if (decoder->picture_structure == FRAME_PICTURE) | ||
2365 | { | ||
2366 | if (decoder->chroma_format == 0) | ||
2367 | { | ||
2368 | decoder->motion_parser[0] = motion_zero_420; | ||
2369 | decoder->motion_parser[MC_FIELD] = motion_fr_field_420; | ||
2370 | decoder->motion_parser[MC_FRAME] = motion_fr_frame_420; | ||
2371 | decoder->motion_parser[MC_DMV] = motion_fr_dmv_420; | ||
2372 | decoder->motion_parser[4] = motion_reuse_420; | ||
2373 | } | ||
2374 | else if (decoder->chroma_format == 1) | ||
2375 | { | ||
2376 | decoder->motion_parser[0] = motion_zero_422; | ||
2377 | decoder->motion_parser[MC_FIELD] = motion_fr_field_422; | ||
2378 | decoder->motion_parser[MC_FRAME] = motion_fr_frame_422; | ||
2379 | decoder->motion_parser[MC_DMV] = motion_fr_dmv_422; | ||
2380 | decoder->motion_parser[4] = motion_reuse_422; | ||
2381 | } | ||
2382 | else | ||
2383 | { | ||
2384 | decoder->motion_parser[0] = motion_zero_444; | ||
2385 | decoder->motion_parser[MC_FIELD] = motion_fr_field_444; | ||
2386 | decoder->motion_parser[MC_FRAME] = motion_fr_frame_444; | ||
2387 | decoder->motion_parser[MC_DMV] = motion_fr_dmv_444; | ||
2388 | decoder->motion_parser[4] = motion_reuse_444; | ||
2389 | } | ||
2390 | } | ||
2391 | else | ||
2392 | { | ||
2393 | if (decoder->chroma_format == 0) | ||
2394 | { | ||
2395 | decoder->motion_parser[0] = motion_zero_420; | ||
2396 | decoder->motion_parser[MC_FIELD] = motion_fi_field_420; | ||
2397 | decoder->motion_parser[MC_16X8] = motion_fi_16x8_420; | ||
2398 | decoder->motion_parser[MC_DMV] = motion_fi_dmv_420; | ||
2399 | decoder->motion_parser[4] = motion_reuse_420; | ||
2400 | } | ||
2401 | else if (decoder->chroma_format == 1) | ||
2402 | { | ||
2403 | decoder->motion_parser[0] = motion_zero_422; | ||
2404 | decoder->motion_parser[MC_FIELD] = motion_fi_field_422; | ||
2405 | decoder->motion_parser[MC_16X8] = motion_fi_16x8_422; | ||
2406 | decoder->motion_parser[MC_DMV] = motion_fi_dmv_422; | ||
2407 | decoder->motion_parser[4] = motion_reuse_422; | ||
2408 | } | ||
2409 | else | ||
2410 | { | ||
2411 | decoder->motion_parser[0] = motion_zero_444; | ||
2412 | decoder->motion_parser[MC_FIELD] = motion_fi_field_444; | ||
2413 | decoder->motion_parser[MC_16X8] = motion_fi_16x8_444; | ||
2414 | decoder->motion_parser[MC_DMV] = motion_fi_dmv_444; | ||
2415 | decoder->motion_parser[4] = motion_reuse_444; | ||
2416 | } | ||
2417 | } | ||
2418 | } | ||
2419 | |||
2420 | static inline int slice_init (mpeg2_decoder_t * const decoder, int code) | ||
2421 | { | ||
2422 | #define bit_buf (decoder->bitstream_buf) | ||
2423 | #define bits (decoder->bitstream_bits) | ||
2424 | #define bit_ptr (decoder->bitstream_ptr) | ||
2425 | |||
2426 | int offset; | ||
2427 | const MBAtab * mba; | ||
2428 | |||
2429 | #if MPEG2_COLOR | ||
2430 | decoder->dc_dct_pred[0] = decoder->dc_dct_pred[1] = | ||
2431 | decoder->dc_dct_pred[2] = 16384; | ||
2432 | #else | ||
2433 | decoder->dc_dct_pred[0] = 16384; | ||
2434 | #endif | ||
2435 | |||
2436 | decoder->f_motion.pmv[0][0] = decoder->f_motion.pmv[0][1] = 0; | ||
2437 | decoder->f_motion.pmv[1][0] = decoder->f_motion.pmv[1][1] = 0; | ||
2438 | decoder->b_motion.pmv[0][0] = decoder->b_motion.pmv[0][1] = 0; | ||
2439 | decoder->b_motion.pmv[1][0] = decoder->b_motion.pmv[1][1] = 0; | ||
2440 | |||
2441 | if (decoder->vertical_position_extension) | ||
2442 | { | ||
2443 | code += UBITS (bit_buf, 3) << 7; | ||
2444 | DUMPBITS (bit_buf, bits, 3); | ||
2445 | } | ||
2446 | |||
2447 | decoder->v_offset = (code - 1) * 16; | ||
2448 | offset = 0; | ||
2449 | |||
2450 | if (!(decoder->convert) || decoder->coding_type != B_TYPE) | ||
2451 | { | ||
2452 | offset = (code - 1) * decoder->slice_stride; | ||
2453 | } | ||
2454 | |||
2455 | decoder->dest[0] = decoder->picture_dest[0] + offset; | ||
2456 | #if MPEG2_COLOR | ||
2457 | offset >>= (2 - decoder->chroma_format); | ||
2458 | decoder->dest[1] = decoder->picture_dest[1] + offset; | ||
2459 | decoder->dest[2] = decoder->picture_dest[2] + offset; | ||
2460 | #endif | ||
2461 | |||
2462 | get_quantizer_scale (decoder); | ||
2463 | |||
2464 | /* ignore intra_slice and all the extra data */ | ||
2465 | while (bit_buf & 0x80000000) | ||
2466 | { | ||
2467 | DUMPBITS (bit_buf, bits, 9); | ||
2468 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
2469 | } | ||
2470 | |||
2471 | /* decode initial macroblock address increment */ | ||
2472 | offset = 0; | ||
2473 | while (1) | ||
2474 | { | ||
2475 | if (bit_buf >= 0x08000000) | ||
2476 | { | ||
2477 | mba = MBA_5 + (UBITS (bit_buf, 6) - 2); | ||
2478 | break; | ||
2479 | } | ||
2480 | else if (bit_buf >= 0x01800000) | ||
2481 | { | ||
2482 | mba = MBA_11 + (UBITS (bit_buf, 12) - 24); | ||
2483 | break; | ||
2484 | } | ||
2485 | else | ||
2486 | { | ||
2487 | switch (UBITS (bit_buf, 12)) | ||
2488 | { | ||
2489 | case 8: /* macroblock_escape */ | ||
2490 | offset += 33; | ||
2491 | DUMPBITS (bit_buf, bits, 11); | ||
2492 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
2493 | continue; | ||
2494 | case 15: /* macroblock_stuffing (MPEG1 only) */ | ||
2495 | bit_buf &= 0xfffff; | ||
2496 | DUMPBITS (bit_buf, bits, 11); | ||
2497 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
2498 | continue; | ||
2499 | default: /* error */ | ||
2500 | return 1; | ||
2501 | } | ||
2502 | } | ||
2503 | } | ||
2504 | |||
2505 | DUMPBITS (bit_buf, bits, mba->len + 1); | ||
2506 | decoder->offset = (offset + mba->mba) << 4; | ||
2507 | |||
2508 | while (decoder->offset - decoder->width >= 0) | ||
2509 | { | ||
2510 | decoder->offset -= decoder->width; | ||
2511 | |||
2512 | if (!(decoder->convert) || decoder->coding_type != B_TYPE) | ||
2513 | { | ||
2514 | decoder->dest[0] += decoder->slice_stride; | ||
2515 | #if MPEG2_COLOR | ||
2516 | decoder->dest[1] += decoder->slice_uv_stride; | ||
2517 | decoder->dest[2] += decoder->slice_uv_stride; | ||
2518 | #endif | ||
2519 | } | ||
2520 | |||
2521 | decoder->v_offset += 16; | ||
2522 | } | ||
2523 | |||
2524 | if (decoder->v_offset > decoder->limit_y) | ||
2525 | return 1; | ||
2526 | |||
2527 | return 0; | ||
2528 | |||
2529 | #undef bit_buf | ||
2530 | #undef bits | ||
2531 | #undef bit_ptr | ||
2532 | } | ||
2533 | |||
2534 | void mpeg2_slice (mpeg2_decoder_t * const decoder, const int code, | ||
2535 | const uint8_t * const buffer) | ||
2536 | { | ||
2537 | #define bit_buf (decoder->bitstream_buf) | ||
2538 | #define bits (decoder->bitstream_bits) | ||
2539 | #define bit_ptr (decoder->bitstream_ptr) | ||
2540 | |||
2541 | bitstream_init (decoder, buffer); | ||
2542 | |||
2543 | if (slice_init (decoder, code)) | ||
2544 | return; | ||
2545 | |||
2546 | while (1) | ||
2547 | { | ||
2548 | int macroblock_modes; | ||
2549 | int mba_inc; | ||
2550 | const MBAtab * mba; | ||
2551 | |||
2552 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
2553 | |||
2554 | macroblock_modes = get_macroblock_modes (decoder); | ||
2555 | |||
2556 | /* maybe integrate MACROBLOCK_QUANT test into get_macroblock_modes ? */ | ||
2557 | if (macroblock_modes & MACROBLOCK_QUANT) | ||
2558 | get_quantizer_scale (decoder); | ||
2559 | |||
2560 | if (macroblock_modes & MACROBLOCK_INTRA) | ||
2561 | { | ||
2562 | int DCT_offset, DCT_stride; | ||
2563 | int offset; | ||
2564 | uint8_t * dest_y; | ||
2565 | |||
2566 | if (decoder->concealment_motion_vectors) | ||
2567 | { | ||
2568 | if (decoder->picture_structure == FRAME_PICTURE) | ||
2569 | motion_fr_conceal (decoder); | ||
2570 | else | ||
2571 | motion_fi_conceal (decoder); | ||
2572 | } | ||
2573 | else | ||
2574 | { | ||
2575 | decoder->f_motion.pmv[0][0] = decoder->f_motion.pmv[0][1] = 0; | ||
2576 | decoder->f_motion.pmv[1][0] = decoder->f_motion.pmv[1][1] = 0; | ||
2577 | decoder->b_motion.pmv[0][0] = decoder->b_motion.pmv[0][1] = 0; | ||
2578 | decoder->b_motion.pmv[1][0] = decoder->b_motion.pmv[1][1] = 0; | ||
2579 | } | ||
2580 | |||
2581 | if (macroblock_modes & DCT_TYPE_INTERLACED) | ||
2582 | { | ||
2583 | DCT_offset = decoder->stride; | ||
2584 | DCT_stride = decoder->stride * 2; | ||
2585 | } | ||
2586 | else | ||
2587 | { | ||
2588 | DCT_offset = decoder->stride * 8; | ||
2589 | DCT_stride = decoder->stride; | ||
2590 | } | ||
2591 | |||
2592 | offset = decoder->offset; | ||
2593 | dest_y = decoder->dest[0] + offset; | ||
2594 | slice_intra_DCT (decoder, 0, dest_y, DCT_stride); | ||
2595 | slice_intra_DCT (decoder, 0, dest_y + 8, DCT_stride); | ||
2596 | slice_intra_DCT (decoder, 0, dest_y + DCT_offset, DCT_stride); | ||
2597 | slice_intra_DCT (decoder, 0, dest_y + DCT_offset + 8, DCT_stride); | ||
2598 | |||
2599 | #if MPEG2_COLOR | ||
2600 | if (likely (decoder->chroma_format == 0)) | ||
2601 | { | ||
2602 | slice_intra_DCT (decoder, 1, decoder->dest[1] + (offset >> 1), | ||
2603 | decoder->uv_stride); | ||
2604 | slice_intra_DCT (decoder, 2, decoder->dest[2] + (offset >> 1), | ||
2605 | decoder->uv_stride); | ||
2606 | |||
2607 | if (decoder->coding_type == D_TYPE) | ||
2608 | { | ||
2609 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
2610 | DUMPBITS (bit_buf, bits, 1); | ||
2611 | } | ||
2612 | } | ||
2613 | else if (likely (decoder->chroma_format == 1)) | ||
2614 | { | ||
2615 | uint8_t * dest_u = decoder->dest[1] + (offset >> 1); | ||
2616 | uint8_t * dest_v = decoder->dest[2] + (offset >> 1); | ||
2617 | |||
2618 | DCT_stride >>= 1; | ||
2619 | DCT_offset >>= 1; | ||
2620 | |||
2621 | slice_intra_DCT (decoder, 1, dest_u, DCT_stride); | ||
2622 | slice_intra_DCT (decoder, 2, dest_v, DCT_stride); | ||
2623 | slice_intra_DCT (decoder, 1, dest_u + DCT_offset, DCT_stride); | ||
2624 | slice_intra_DCT (decoder, 2, dest_v + DCT_offset, DCT_stride); | ||
2625 | } | ||
2626 | else | ||
2627 | { | ||
2628 | uint8_t * dest_u = decoder->dest[1] + offset; | ||
2629 | uint8_t * dest_v = decoder->dest[2] + offset; | ||
2630 | |||
2631 | slice_intra_DCT (decoder, 1, dest_u, DCT_stride); | ||
2632 | slice_intra_DCT (decoder, 2, dest_v, DCT_stride); | ||
2633 | slice_intra_DCT (decoder, 1, dest_u + DCT_offset, DCT_stride); | ||
2634 | slice_intra_DCT (decoder, 2, dest_v + DCT_offset, DCT_stride); | ||
2635 | slice_intra_DCT (decoder, 1, dest_u + 8, DCT_stride); | ||
2636 | slice_intra_DCT (decoder, 2, dest_v + 8, DCT_stride); | ||
2637 | slice_intra_DCT (decoder, 1, dest_u + DCT_offset + 8, | ||
2638 | DCT_stride); | ||
2639 | slice_intra_DCT (decoder, 2, dest_v + DCT_offset + 8, | ||
2640 | DCT_stride); | ||
2641 | } | ||
2642 | #else | ||
2643 | skip_chroma_intra(decoder); | ||
2644 | #endif /* MPEG2_COLOR */ | ||
2645 | } | ||
2646 | else | ||
2647 | { | ||
2648 | motion_parser_t * parser; | ||
2649 | |||
2650 | parser = | ||
2651 | decoder->motion_parser[macroblock_modes >> MOTION_TYPE_SHIFT]; | ||
2652 | MOTION_CALL (parser, macroblock_modes); | ||
2653 | |||
2654 | if (macroblock_modes & MACROBLOCK_PATTERN) | ||
2655 | { | ||
2656 | int coded_block_pattern; | ||
2657 | int DCT_offset, DCT_stride; | ||
2658 | |||
2659 | if (macroblock_modes & DCT_TYPE_INTERLACED) | ||
2660 | { | ||
2661 | DCT_offset = decoder->stride; | ||
2662 | DCT_stride = decoder->stride * 2; | ||
2663 | } | ||
2664 | else | ||
2665 | { | ||
2666 | DCT_offset = decoder->stride * 8; | ||
2667 | DCT_stride = decoder->stride; | ||
2668 | } | ||
2669 | |||
2670 | coded_block_pattern = get_coded_block_pattern (decoder); | ||
2671 | |||
2672 | if (likely (decoder->chroma_format == 0)) | ||
2673 | { | ||
2674 | int offset = decoder->offset; | ||
2675 | uint8_t * dest_y = decoder->dest[0] + offset; | ||
2676 | |||
2677 | if (coded_block_pattern & 1) | ||
2678 | slice_non_intra_DCT (decoder, 0, dest_y, DCT_stride); | ||
2679 | |||
2680 | if (coded_block_pattern & 2) | ||
2681 | slice_non_intra_DCT (decoder, 0, dest_y + 8, | ||
2682 | DCT_stride); | ||
2683 | |||
2684 | if (coded_block_pattern & 4) | ||
2685 | slice_non_intra_DCT (decoder, 0, dest_y + DCT_offset, | ||
2686 | DCT_stride); | ||
2687 | |||
2688 | if (coded_block_pattern & 8) | ||
2689 | slice_non_intra_DCT (decoder, 0, | ||
2690 | dest_y + DCT_offset + 8, | ||
2691 | DCT_stride); | ||
2692 | #if MPEG2_COLOR | ||
2693 | if (coded_block_pattern & 16) | ||
2694 | slice_non_intra_DCT (decoder, 1, | ||
2695 | decoder->dest[1] + (offset >> 1), | ||
2696 | decoder->uv_stride); | ||
2697 | |||
2698 | if (coded_block_pattern & 32) | ||
2699 | slice_non_intra_DCT (decoder, 2, | ||
2700 | decoder->dest[2] + (offset >> 1), | ||
2701 | decoder->uv_stride); | ||
2702 | #endif /* MPEG2_COLOR */ | ||
2703 | } | ||
2704 | else if (likely (decoder->chroma_format == 1)) | ||
2705 | { | ||
2706 | int offset; | ||
2707 | uint8_t * dest_y; | ||
2708 | |||
2709 | coded_block_pattern |= bit_buf & (3 << 30); | ||
2710 | DUMPBITS (bit_buf, bits, 2); | ||
2711 | |||
2712 | offset = decoder->offset; | ||
2713 | dest_y = decoder->dest[0] + offset; | ||
2714 | |||
2715 | if (coded_block_pattern & 1) | ||
2716 | slice_non_intra_DCT (decoder, 0, dest_y, DCT_stride); | ||
2717 | |||
2718 | if (coded_block_pattern & 2) | ||
2719 | slice_non_intra_DCT (decoder, 0, dest_y + 8, | ||
2720 | DCT_stride); | ||
2721 | |||
2722 | if (coded_block_pattern & 4) | ||
2723 | slice_non_intra_DCT (decoder, 0, dest_y + DCT_offset, | ||
2724 | DCT_stride); | ||
2725 | |||
2726 | if (coded_block_pattern & 8) | ||
2727 | slice_non_intra_DCT (decoder, 0, | ||
2728 | dest_y + DCT_offset + 8, | ||
2729 | DCT_stride); | ||
2730 | #if MPEG2_COLOR | ||
2731 | DCT_stride >>= 1; | ||
2732 | DCT_offset = (DCT_offset + offset) >> 1; | ||
2733 | |||
2734 | if (coded_block_pattern & 16) | ||
2735 | slice_non_intra_DCT (decoder, 1, | ||
2736 | decoder->dest[1] + (offset >> 1), | ||
2737 | DCT_stride); | ||
2738 | |||
2739 | if (coded_block_pattern & 32) | ||
2740 | slice_non_intra_DCT (decoder, 2, | ||
2741 | decoder->dest[2] + (offset >> 1), | ||
2742 | DCT_stride); | ||
2743 | |||
2744 | if (coded_block_pattern & (2 << 30)) | ||
2745 | slice_non_intra_DCT (decoder, 1, | ||
2746 | decoder->dest[1] + DCT_offset, | ||
2747 | DCT_stride); | ||
2748 | |||
2749 | if (coded_block_pattern & (1 << 30)) | ||
2750 | slice_non_intra_DCT (decoder, 2, | ||
2751 | decoder->dest[2] + DCT_offset, | ||
2752 | DCT_stride); | ||
2753 | #endif /* MPEG2_COLOR */ | ||
2754 | } | ||
2755 | else | ||
2756 | { | ||
2757 | int offset = decoder->offset; | ||
2758 | uint8_t * dest_y = decoder->dest[0] + offset; | ||
2759 | #if MPEG2_COLOR | ||
2760 | uint8_t * dest_u = decoder->dest[1] + offset; | ||
2761 | uint8_t * dest_v = decoder->dest[2] + offset; | ||
2762 | #endif | ||
2763 | coded_block_pattern |= bit_buf & (63 << 26); | ||
2764 | DUMPBITS (bit_buf, bits, 6); | ||
2765 | |||
2766 | if (coded_block_pattern & 1) | ||
2767 | slice_non_intra_DCT (decoder, 0, dest_y, DCT_stride); | ||
2768 | |||
2769 | if (coded_block_pattern & 2) | ||
2770 | slice_non_intra_DCT (decoder, 0, dest_y + 8, | ||
2771 | DCT_stride); | ||
2772 | |||
2773 | if (coded_block_pattern & 4) | ||
2774 | slice_non_intra_DCT (decoder, 0, dest_y + DCT_offset, | ||
2775 | DCT_stride); | ||
2776 | |||
2777 | if (coded_block_pattern & 8) | ||
2778 | slice_non_intra_DCT (decoder, 0, | ||
2779 | dest_y + DCT_offset + 8, | ||
2780 | DCT_stride); | ||
2781 | #if MPEG2_COLOR | ||
2782 | if (coded_block_pattern & 16) | ||
2783 | slice_non_intra_DCT (decoder, 1, dest_u, DCT_stride); | ||
2784 | |||
2785 | if (coded_block_pattern & 32) | ||
2786 | slice_non_intra_DCT (decoder, 2, dest_v, DCT_stride); | ||
2787 | |||
2788 | if (coded_block_pattern & (32 << 26)) | ||
2789 | slice_non_intra_DCT (decoder, 1, dest_u + DCT_offset, | ||
2790 | DCT_stride); | ||
2791 | |||
2792 | if (coded_block_pattern & (16 << 26)) | ||
2793 | slice_non_intra_DCT (decoder, 2, dest_v + DCT_offset, | ||
2794 | DCT_stride); | ||
2795 | |||
2796 | if (coded_block_pattern & (8 << 26)) | ||
2797 | slice_non_intra_DCT (decoder, 1, dest_u + 8, | ||
2798 | DCT_stride); | ||
2799 | |||
2800 | if (coded_block_pattern & (4 << 26)) | ||
2801 | slice_non_intra_DCT (decoder, 2, dest_v + 8, | ||
2802 | DCT_stride); | ||
2803 | |||
2804 | if (coded_block_pattern & (2 << 26)) | ||
2805 | slice_non_intra_DCT (decoder, 1, | ||
2806 | dest_u + DCT_offset + 8, | ||
2807 | DCT_stride); | ||
2808 | |||
2809 | if (coded_block_pattern & (1 << 26)) | ||
2810 | slice_non_intra_DCT (decoder, 2, | ||
2811 | dest_v + DCT_offset + 8, | ||
2812 | DCT_stride); | ||
2813 | #endif /* MPEG2_COLOR */ | ||
2814 | } | ||
2815 | #if !MPEG2_COLOR | ||
2816 | skip_chroma_non_intra(decoder, coded_block_pattern); | ||
2817 | #endif | ||
2818 | } | ||
2819 | |||
2820 | #if MPEG2_COLOR | ||
2821 | decoder->dc_dct_pred[0] = decoder->dc_dct_pred[1] = | ||
2822 | decoder->dc_dct_pred[2] = 16384; | ||
2823 | #else | ||
2824 | decoder->dc_dct_pred[0] = 16384; | ||
2825 | #endif | ||
2826 | } | ||
2827 | |||
2828 | NEXT_MACROBLOCK; | ||
2829 | |||
2830 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
2831 | mba_inc = 0; | ||
2832 | |||
2833 | while (1) | ||
2834 | { | ||
2835 | if (bit_buf >= 0x10000000) | ||
2836 | { | ||
2837 | mba = MBA_5 + (UBITS (bit_buf, 5) - 2); | ||
2838 | break; | ||
2839 | } | ||
2840 | else if (bit_buf >= 0x03000000) | ||
2841 | { | ||
2842 | mba = MBA_11 + (UBITS (bit_buf, 11) - 24); | ||
2843 | break; | ||
2844 | } | ||
2845 | else | ||
2846 | { | ||
2847 | switch (UBITS (bit_buf, 11)) | ||
2848 | { | ||
2849 | case 8: /* macroblock_escape */ | ||
2850 | mba_inc += 33; | ||
2851 | /* pass through */ | ||
2852 | case 15: /* macroblock_stuffing (MPEG1 only) */ | ||
2853 | DUMPBITS (bit_buf, bits, 11); | ||
2854 | NEEDBITS (bit_buf, bits, bit_ptr); | ||
2855 | continue; | ||
2856 | default: /* end of slice, or error */ | ||
2857 | return; | ||
2858 | } | ||
2859 | } | ||
2860 | } | ||
2861 | |||
2862 | DUMPBITS (bit_buf, bits, mba->len); | ||
2863 | mba_inc += mba->mba; | ||
2864 | |||
2865 | if (mba_inc) | ||
2866 | { | ||
2867 | #if MPEG2_COLOR | ||
2868 | decoder->dc_dct_pred[0] = decoder->dc_dct_pred[1] = | ||
2869 | decoder->dc_dct_pred[2] = 16384; | ||
2870 | #else | ||
2871 | decoder->dc_dct_pred[0] = 16384; | ||
2872 | #endif | ||
2873 | if (decoder->coding_type == P_TYPE) | ||
2874 | { | ||
2875 | do | ||
2876 | { | ||
2877 | MOTION_CALL (decoder->motion_parser[0], | ||
2878 | MACROBLOCK_MOTION_FORWARD); | ||
2879 | NEXT_MACROBLOCK; | ||
2880 | } | ||
2881 | while (--mba_inc); | ||
2882 | } | ||
2883 | else | ||
2884 | { | ||
2885 | do | ||
2886 | { | ||
2887 | MOTION_CALL (decoder->motion_parser[4], macroblock_modes); | ||
2888 | NEXT_MACROBLOCK; | ||
2889 | } | ||
2890 | while (--mba_inc); | ||
2891 | } | ||
2892 | } | ||
2893 | } | ||
2894 | |||
2895 | #undef bit_buf | ||
2896 | #undef bits | ||
2897 | #undef bit_ptr | ||
2898 | } | ||
diff --git a/apps/plugins/mpegplayer/libmpeg2/vlc.h b/apps/plugins/mpegplayer/libmpeg2/vlc.h deleted file mode 100644 index d1b6a98cde..0000000000 --- a/apps/plugins/mpegplayer/libmpeg2/vlc.h +++ /dev/null | |||
@@ -1,433 +0,0 @@ | |||
1 | /* | ||
2 | * vlc.h | ||
3 | * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> | ||
4 | * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> | ||
5 | * | ||
6 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
7 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
8 | * | ||
9 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * mpeg2dec is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | * $Id$ | ||
24 | * libmpeg2 sync history: | ||
25 | * 2008-07-01 - CVS revision 1.12 | ||
26 | */ | ||
27 | |||
28 | #define GETWORD(bit_buf, shift, bit_ptr) \ | ||
29 | do { \ | ||
30 | bit_buf |= ((bit_ptr[0] << 8) | bit_ptr[1]) << (shift); \ | ||
31 | bit_ptr += 2; \ | ||
32 | } while (0) | ||
33 | |||
34 | static inline void bitstream_init (mpeg2_decoder_t * decoder, | ||
35 | const uint8_t * start) | ||
36 | { | ||
37 | decoder->bitstream_buf = | ||
38 | (start[0] << 24) | (start[1] << 16) | (start[2] << 8) | start[3]; | ||
39 | decoder->bitstream_ptr = start + 4; | ||
40 | decoder->bitstream_bits = -16; | ||
41 | } | ||
42 | |||
43 | /* make sure that there are at least 16 valid bits in bit_buf */ | ||
44 | #define NEEDBITS(bit_buf, bits, bit_ptr) \ | ||
45 | do { \ | ||
46 | if (unlikely (bits > 0)) { \ | ||
47 | GETWORD (bit_buf, bits, bit_ptr); \ | ||
48 | bits -= 16; \ | ||
49 | } \ | ||
50 | } while (0) | ||
51 | |||
52 | /* remove num valid bits from bit_buf */ | ||
53 | #define DUMPBITS(bit_buf, bits, num) \ | ||
54 | do { \ | ||
55 | bit_buf <<= (num); \ | ||
56 | bits += (num); \ | ||
57 | } while (0) | ||
58 | |||
59 | /* take num bits from the high part of bit_buf and zero extend them */ | ||
60 | #define UBITS(bit_buf,num) (((uint32_t)(bit_buf)) >> (32 - (num))) | ||
61 | |||
62 | /* take num bits from the high part of bit_buf and sign extend them */ | ||
63 | #define SBITS(bit_buf,num) (((int32_t)(bit_buf)) >> (32 - (num))) | ||
64 | |||
65 | typedef struct { | ||
66 | uint8_t modes; | ||
67 | uint8_t len; | ||
68 | } MBtab; | ||
69 | |||
70 | typedef struct { | ||
71 | uint8_t delta; | ||
72 | uint8_t len; | ||
73 | } MVtab; | ||
74 | |||
75 | typedef struct { | ||
76 | int8_t dmv; | ||
77 | uint8_t len; | ||
78 | } DMVtab; | ||
79 | |||
80 | typedef struct { | ||
81 | uint8_t cbp; | ||
82 | uint8_t len; | ||
83 | } CBPtab; | ||
84 | |||
85 | typedef struct { | ||
86 | uint8_t size; | ||
87 | uint8_t len; | ||
88 | } DCtab; | ||
89 | |||
90 | typedef struct { | ||
91 | uint8_t run; | ||
92 | uint8_t level; | ||
93 | uint8_t len; | ||
94 | } DCTtab; | ||
95 | |||
96 | typedef struct { | ||
97 | uint8_t mba; | ||
98 | uint8_t len; | ||
99 | } MBAtab; | ||
100 | |||
101 | |||
102 | #define INTRA MACROBLOCK_INTRA | ||
103 | #define QUANT MACROBLOCK_QUANT | ||
104 | |||
105 | static const MBtab MB_I [] ICONST_ATTR = { | ||
106 | {INTRA|QUANT, 2}, {INTRA, 1} | ||
107 | }; | ||
108 | |||
109 | #define MC MACROBLOCK_MOTION_FORWARD | ||
110 | #define CODED MACROBLOCK_PATTERN | ||
111 | |||
112 | static const MBtab MB_P [] ICONST_ATTR = { | ||
113 | {INTRA|QUANT, 6}, {CODED|QUANT, 5}, {MC|CODED|QUANT, 5}, {INTRA, 5}, | ||
114 | {MC, 3}, {MC, 3}, {MC, 3}, {MC, 3}, | ||
115 | {CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2}, | ||
116 | {CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2}, | ||
117 | {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, | ||
118 | {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, | ||
119 | {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, | ||
120 | {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1} | ||
121 | }; | ||
122 | |||
123 | #define FWD MACROBLOCK_MOTION_FORWARD | ||
124 | #define BWD MACROBLOCK_MOTION_BACKWARD | ||
125 | #define INTER MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD | ||
126 | |||
127 | static const MBtab MB_B [] ICONST_ATTR = { | ||
128 | {0, 6}, {INTRA|QUANT, 6}, | ||
129 | {BWD|CODED|QUANT, 6}, {FWD|CODED|QUANT, 6}, | ||
130 | {INTER|CODED|QUANT, 5}, {INTER|CODED|QUANT, 5}, | ||
131 | {INTRA, 5}, {INTRA, 5}, | ||
132 | {FWD, 4}, {FWD, 4}, {FWD, 4}, {FWD, 4}, | ||
133 | {FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4}, | ||
134 | {BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3}, | ||
135 | {BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3}, | ||
136 | {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, | ||
137 | {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, | ||
138 | {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, | ||
139 | {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, | ||
140 | {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, | ||
141 | {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, | ||
142 | {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, | ||
143 | {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, | ||
144 | {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, | ||
145 | {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2} | ||
146 | }; | ||
147 | |||
148 | #undef INTRA | ||
149 | #undef QUANT | ||
150 | #undef MC | ||
151 | #undef CODED | ||
152 | #undef FWD | ||
153 | #undef BWD | ||
154 | #undef INTER | ||
155 | |||
156 | |||
157 | static const MVtab MV_4 [] ICONST_ATTR = { | ||
158 | { 3, 6}, { 2, 4}, { 1, 3}, { 1, 3}, { 0, 2}, { 0, 2}, { 0, 2}, { 0, 2} | ||
159 | }; | ||
160 | |||
161 | static const MVtab MV_10 [] ICONST_ATTR = { | ||
162 | { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, | ||
163 | { 0,10}, { 0,10}, { 0,10}, { 0,10}, {15,10}, {14,10}, {13,10}, {12,10}, | ||
164 | {11,10}, {10,10}, { 9, 9}, { 9, 9}, { 8, 9}, { 8, 9}, { 7, 9}, { 7, 9}, | ||
165 | { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, | ||
166 | { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, | ||
167 | { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7} | ||
168 | }; | ||
169 | |||
170 | |||
171 | static const DMVtab DMV_2 [] ICONST_ATTR = { | ||
172 | { 0, 1}, { 0, 1}, { 1, 2}, {-1, 2} | ||
173 | }; | ||
174 | |||
175 | |||
176 | static const CBPtab CBP_7 [] ICONST_ATTR = { | ||
177 | {0x11, 7}, {0x12, 7}, {0x14, 7}, {0x18, 7}, | ||
178 | {0x21, 7}, {0x22, 7}, {0x24, 7}, {0x28, 7}, | ||
179 | {0x3f, 6}, {0x3f, 6}, {0x30, 6}, {0x30, 6}, | ||
180 | {0x09, 6}, {0x09, 6}, {0x06, 6}, {0x06, 6}, | ||
181 | {0x1f, 5}, {0x1f, 5}, {0x1f, 5}, {0x1f, 5}, | ||
182 | {0x10, 5}, {0x10, 5}, {0x10, 5}, {0x10, 5}, | ||
183 | {0x2f, 5}, {0x2f, 5}, {0x2f, 5}, {0x2f, 5}, | ||
184 | {0x20, 5}, {0x20, 5}, {0x20, 5}, {0x20, 5}, | ||
185 | {0x07, 5}, {0x07, 5}, {0x07, 5}, {0x07, 5}, | ||
186 | {0x0b, 5}, {0x0b, 5}, {0x0b, 5}, {0x0b, 5}, | ||
187 | {0x0d, 5}, {0x0d, 5}, {0x0d, 5}, {0x0d, 5}, | ||
188 | {0x0e, 5}, {0x0e, 5}, {0x0e, 5}, {0x0e, 5}, | ||
189 | {0x05, 5}, {0x05, 5}, {0x05, 5}, {0x05, 5}, | ||
190 | {0x0a, 5}, {0x0a, 5}, {0x0a, 5}, {0x0a, 5}, | ||
191 | {0x03, 5}, {0x03, 5}, {0x03, 5}, {0x03, 5}, | ||
192 | {0x0c, 5}, {0x0c, 5}, {0x0c, 5}, {0x0c, 5}, | ||
193 | {0x01, 4}, {0x01, 4}, {0x01, 4}, {0x01, 4}, | ||
194 | {0x01, 4}, {0x01, 4}, {0x01, 4}, {0x01, 4}, | ||
195 | {0x02, 4}, {0x02, 4}, {0x02, 4}, {0x02, 4}, | ||
196 | {0x02, 4}, {0x02, 4}, {0x02, 4}, {0x02, 4}, | ||
197 | {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4}, | ||
198 | {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4}, | ||
199 | {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4}, | ||
200 | {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4}, | ||
201 | {0x0f, 3}, {0x0f, 3}, {0x0f, 3}, {0x0f, 3}, | ||
202 | {0x0f, 3}, {0x0f, 3}, {0x0f, 3}, {0x0f, 3}, | ||
203 | {0x0f, 3}, {0x0f, 3}, {0x0f, 3}, {0x0f, 3}, | ||
204 | {0x0f, 3}, {0x0f, 3}, {0x0f, 3}, {0x0f, 3} | ||
205 | }; | ||
206 | |||
207 | static const CBPtab CBP_9 [] ICONST_ATTR = { | ||
208 | {0, 9}, {0x00, 9}, {0x39, 9}, {0x36, 9}, | ||
209 | {0x37, 9}, {0x3b, 9}, {0x3d, 9}, {0x3e, 9}, | ||
210 | {0x17, 8}, {0x17, 8}, {0x1b, 8}, {0x1b, 8}, | ||
211 | {0x1d, 8}, {0x1d, 8}, {0x1e, 8}, {0x1e, 8}, | ||
212 | {0x27, 8}, {0x27, 8}, {0x2b, 8}, {0x2b, 8}, | ||
213 | {0x2d, 8}, {0x2d, 8}, {0x2e, 8}, {0x2e, 8}, | ||
214 | {0x19, 8}, {0x19, 8}, {0x16, 8}, {0x16, 8}, | ||
215 | {0x29, 8}, {0x29, 8}, {0x26, 8}, {0x26, 8}, | ||
216 | {0x35, 8}, {0x35, 8}, {0x3a, 8}, {0x3a, 8}, | ||
217 | {0x33, 8}, {0x33, 8}, {0x3c, 8}, {0x3c, 8}, | ||
218 | {0x15, 8}, {0x15, 8}, {0x1a, 8}, {0x1a, 8}, | ||
219 | {0x13, 8}, {0x13, 8}, {0x1c, 8}, {0x1c, 8}, | ||
220 | {0x25, 8}, {0x25, 8}, {0x2a, 8}, {0x2a, 8}, | ||
221 | {0x23, 8}, {0x23, 8}, {0x2c, 8}, {0x2c, 8}, | ||
222 | {0x31, 8}, {0x31, 8}, {0x32, 8}, {0x32, 8}, | ||
223 | {0x34, 8}, {0x34, 8}, {0x38, 8}, {0x38, 8} | ||
224 | }; | ||
225 | |||
226 | |||
227 | static const DCtab DC_lum_5 [] ICONST_ATTR = { | ||
228 | {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, | ||
229 | {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, | ||
230 | {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, | ||
231 | {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5} | ||
232 | }; | ||
233 | |||
234 | static const DCtab DC_chrom_5 [] ICONST_ATTR = { | ||
235 | {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, | ||
236 | {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, | ||
237 | {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, | ||
238 | {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5} | ||
239 | }; | ||
240 | |||
241 | static const DCtab DC_long [] ICONST_ATTR = { | ||
242 | {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5}, | ||
243 | {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5}, | ||
244 | {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, { 7, 6}, { 7, 6}, | ||
245 | {8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10, 9}, {11, 9} | ||
246 | }; | ||
247 | |||
248 | |||
249 | static const DCTtab DCT_16 [] ICONST_ATTR = { | ||
250 | {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, | ||
251 | {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, | ||
252 | {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, | ||
253 | {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, | ||
254 | { 2,18, 0}, { 2,17, 0}, { 2,16, 0}, { 2,15, 0}, | ||
255 | { 7, 3, 0}, { 17, 2, 0}, { 16, 2, 0}, { 15, 2, 0}, | ||
256 | { 14, 2, 0}, { 13, 2, 0}, { 12, 2, 0}, { 32, 1, 0}, | ||
257 | { 31, 1, 0}, { 30, 1, 0}, { 29, 1, 0}, { 28, 1, 0} | ||
258 | }; | ||
259 | |||
260 | static const DCTtab DCT_15 [] ICONST_ATTR = { | ||
261 | { 1,40,15}, { 1,39,15}, { 1,38,15}, { 1,37,15}, | ||
262 | { 1,36,15}, { 1,35,15}, { 1,34,15}, { 1,33,15}, | ||
263 | { 1,32,15}, { 2,14,15}, { 2,13,15}, { 2,12,15}, | ||
264 | { 2,11,15}, { 2,10,15}, { 2, 9,15}, { 2, 8,15}, | ||
265 | { 1,31,14}, { 1,31,14}, { 1,30,14}, { 1,30,14}, | ||
266 | { 1,29,14}, { 1,29,14}, { 1,28,14}, { 1,28,14}, | ||
267 | { 1,27,14}, { 1,27,14}, { 1,26,14}, { 1,26,14}, | ||
268 | { 1,25,14}, { 1,25,14}, { 1,24,14}, { 1,24,14}, | ||
269 | { 1,23,14}, { 1,23,14}, { 1,22,14}, { 1,22,14}, | ||
270 | { 1,21,14}, { 1,21,14}, { 1,20,14}, { 1,20,14}, | ||
271 | { 1,19,14}, { 1,19,14}, { 1,18,14}, { 1,18,14}, | ||
272 | { 1,17,14}, { 1,17,14}, { 1,16,14}, { 1,16,14} | ||
273 | }; | ||
274 | |||
275 | static const DCTtab DCT_13 [] ICONST_ATTR = { | ||
276 | { 11, 2,13}, { 10, 2,13}, { 6, 3,13}, { 4, 4,13}, | ||
277 | { 3, 5,13}, { 2, 7,13}, { 2, 6,13}, { 1,15,13}, | ||
278 | { 1,14,13}, { 1,13,13}, { 1,12,13}, { 27, 1,13}, | ||
279 | { 26, 1,13}, { 25, 1,13}, { 24, 1,13}, { 23, 1,13}, | ||
280 | { 1,11,12}, { 1,11,12}, { 9, 2,12}, { 9, 2,12}, | ||
281 | { 5, 3,12}, { 5, 3,12}, { 1,10,12}, { 1,10,12}, | ||
282 | { 3, 4,12}, { 3, 4,12}, { 8, 2,12}, { 8, 2,12}, | ||
283 | { 22, 1,12}, { 22, 1,12}, { 21, 1,12}, { 21, 1,12}, | ||
284 | { 1, 9,12}, { 1, 9,12}, { 20, 1,12}, { 20, 1,12}, | ||
285 | { 19, 1,12}, { 19, 1,12}, { 2, 5,12}, { 2, 5,12}, | ||
286 | { 4, 3,12}, { 4, 3,12}, { 1, 8,12}, { 1, 8,12}, | ||
287 | { 7, 2,12}, { 7, 2,12}, { 18, 1,12}, { 18, 1,12} | ||
288 | }; | ||
289 | |||
290 | static const DCTtab DCT_B14_10 [] ICONST_ATTR = { | ||
291 | { 17, 1,10}, { 6, 2,10}, { 1, 7,10}, { 3, 3,10}, | ||
292 | { 2, 4,10}, { 16, 1,10}, { 15, 1,10}, { 5, 2,10} | ||
293 | }; | ||
294 | |||
295 | static const DCTtab DCT_B14_8 [] ICONST_ATTR = { | ||
296 | { 65, 0, 12}, { 65, 0, 12}, { 65, 0, 12}, { 65, 0, 12}, | ||
297 | { 3, 2, 7}, { 3, 2, 7}, { 10, 1, 7}, { 10, 1, 7}, | ||
298 | { 1, 4, 7}, { 1, 4, 7}, { 9, 1, 7}, { 9, 1, 7}, | ||
299 | { 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6}, | ||
300 | { 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6}, | ||
301 | { 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6}, | ||
302 | { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, | ||
303 | { 14, 1, 8}, { 1, 6, 8}, { 13, 1, 8}, { 12, 1, 8}, | ||
304 | { 4, 2, 8}, { 2, 3, 8}, { 1, 5, 8}, { 11, 1, 8} | ||
305 | }; | ||
306 | |||
307 | static const DCTtab DCT_B14AC_5 [] ICONST_ATTR = { | ||
308 | { 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5}, | ||
309 | { 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4}, | ||
310 | { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, | ||
311 | {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, | ||
312 | {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, | ||
313 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
314 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2} | ||
315 | }; | ||
316 | |||
317 | static const DCTtab DCT_B14DC_5 [] ICONST_ATTR = { | ||
318 | { 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5}, | ||
319 | { 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4}, | ||
320 | { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, | ||
321 | { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, | ||
322 | { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, | ||
323 | { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, | ||
324 | { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1} | ||
325 | }; | ||
326 | |||
327 | static const DCTtab DCT_B15_10 [] ICONST_ATTR = { | ||
328 | { 6, 2, 9}, { 6, 2, 9}, { 15, 1, 9}, { 15, 1, 9}, | ||
329 | { 3, 4,10}, { 17, 1,10}, { 16, 1, 9}, { 16, 1, 9} | ||
330 | }; | ||
331 | |||
332 | static const DCTtab DCT_B15_8 [] ICONST_ATTR = { | ||
333 | { 65, 0, 12}, { 65, 0, 12}, { 65, 0, 12}, { 65, 0, 12}, | ||
334 | { 8, 1, 7}, { 8, 1, 7}, { 9, 1, 7}, { 9, 1, 7}, | ||
335 | { 7, 1, 7}, { 7, 1, 7}, { 3, 2, 7}, { 3, 2, 7}, | ||
336 | { 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6}, | ||
337 | { 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6}, | ||
338 | { 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6}, | ||
339 | { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, | ||
340 | { 2, 5, 8}, { 12, 1, 8}, { 1,11, 8}, { 1,10, 8}, | ||
341 | { 14, 1, 8}, { 13, 1, 8}, { 4, 2, 8}, { 2, 4, 8}, | ||
342 | { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, | ||
343 | { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, | ||
344 | { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, | ||
345 | { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, | ||
346 | { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, | ||
347 | { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, | ||
348 | { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, | ||
349 | { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, | ||
350 | { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, | ||
351 | { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, | ||
352 | { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, | ||
353 | { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, | ||
354 | { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, | ||
355 | { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, | ||
356 | {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, | ||
357 | {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, | ||
358 | {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, | ||
359 | {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, | ||
360 | { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, | ||
361 | { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, | ||
362 | { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, | ||
363 | { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, | ||
364 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
365 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
366 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
367 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
368 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
369 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
370 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
371 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
372 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
373 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
374 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
375 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
376 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
377 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
378 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
379 | { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, | ||
380 | { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, | ||
381 | { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, | ||
382 | { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, | ||
383 | { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, | ||
384 | { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, | ||
385 | { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, | ||
386 | { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, | ||
387 | { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, | ||
388 | { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, | ||
389 | { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, | ||
390 | { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, | ||
391 | { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, | ||
392 | { 10, 1, 7}, { 10, 1, 7}, { 2, 3, 7}, { 2, 3, 7}, | ||
393 | { 11, 1, 7}, { 11, 1, 7}, { 1, 8, 7}, { 1, 8, 7}, | ||
394 | { 1, 9, 7}, { 1, 9, 7}, { 1,12, 8}, { 1,13, 8}, | ||
395 | { 3, 3, 8}, { 5, 2, 8}, { 1,14, 8}, { 1,15, 8} | ||
396 | }; | ||
397 | |||
398 | |||
399 | static const MBAtab MBA_5 [] ICONST_ATTR = { | ||
400 | {6, 5}, {5, 5}, {4, 4}, {4, 4}, {3, 4}, {3, 4}, | ||
401 | {2, 3}, {2, 3}, {2, 3}, {2, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, | ||
402 | {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, | ||
403 | {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1} | ||
404 | }; | ||
405 | |||
406 | static const MBAtab MBA_11 [] ICONST_ATTR = { | ||
407 | {32, 11}, {31, 11}, {30, 11}, {29, 11}, | ||
408 | {28, 11}, {27, 11}, {26, 11}, {25, 11}, | ||
409 | {24, 11}, {23, 11}, {22, 11}, {21, 11}, | ||
410 | {20, 10}, {20, 10}, {19, 10}, {19, 10}, | ||
411 | {18, 10}, {18, 10}, {17, 10}, {17, 10}, | ||
412 | {16, 10}, {16, 10}, {15, 10}, {15, 10}, | ||
413 | {14, 8}, {14, 8}, {14, 8}, {14, 8}, | ||
414 | {14, 8}, {14, 8}, {14, 8}, {14, 8}, | ||
415 | {13, 8}, {13, 8}, {13, 8}, {13, 8}, | ||
416 | {13, 8}, {13, 8}, {13, 8}, {13, 8}, | ||
417 | {12, 8}, {12, 8}, {12, 8}, {12, 8}, | ||
418 | {12, 8}, {12, 8}, {12, 8}, {12, 8}, | ||
419 | {11, 8}, {11, 8}, {11, 8}, {11, 8}, | ||
420 | {11, 8}, {11, 8}, {11, 8}, {11, 8}, | ||
421 | {10, 8}, {10, 8}, {10, 8}, {10, 8}, | ||
422 | {10, 8}, {10, 8}, {10, 8}, {10, 8}, | ||
423 | { 9, 8}, { 9, 8}, { 9, 8}, { 9, 8}, | ||
424 | { 9, 8}, { 9, 8}, { 9, 8}, { 9, 8}, | ||
425 | { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, | ||
426 | { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, | ||
427 | { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, | ||
428 | { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, | ||
429 | { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, | ||
430 | { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, | ||
431 | { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, | ||
432 | { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7} | ||
433 | }; | ||
diff --git a/apps/plugins/mpegplayer/mpeg_alloc.h b/apps/plugins/mpegplayer/mpeg_alloc.h deleted file mode 100644 index 9acfbc5dec..0000000000 --- a/apps/plugins/mpegplayer/mpeg_alloc.h +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Michael Sevakis | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef MPEG_ALLOC_H | ||
22 | #define MPEG_ALLOC_H | ||
23 | |||
24 | /* returns the remaining mpeg2 buffer and it's size */ | ||
25 | void * mpeg2_get_buf(size_t *size); | ||
26 | void *mpeg_malloc(size_t size, mpeg2_alloc_t reason); | ||
27 | /* Grabs all the buffer available sans margin */ | ||
28 | void *mpeg_malloc_all(size_t *size_out, mpeg2_alloc_t reason); | ||
29 | /* Initializes the malloc buffer with the given base buffer */ | ||
30 | bool mpeg_alloc_init(unsigned char *buf, size_t mallocsize); | ||
31 | |||
32 | #endif /* MPEG_ALLOC_H */ | ||
diff --git a/apps/plugins/mpegplayer/mpeg_misc.c b/apps/plugins/mpegplayer/mpeg_misc.c deleted file mode 100644 index 31f0644212..0000000000 --- a/apps/plugins/mpegplayer/mpeg_misc.c +++ /dev/null | |||
@@ -1,227 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Miscellaneous helper API definitions | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #include "plugin.h" | ||
24 | #include "mpegplayer.h" | ||
25 | |||
26 | /** Streams **/ | ||
27 | |||
28 | /* Initializes the cursor */ | ||
29 | void stream_scan_init(struct stream_scan *sk) | ||
30 | { | ||
31 | dbuf_l2_init(&sk->l2); | ||
32 | } | ||
33 | |||
34 | /* Ensures direction is -1 or 1 and margin is properly initialized */ | ||
35 | void stream_scan_normalize(struct stream_scan *sk) | ||
36 | { | ||
37 | if (sk->dir >= 0) | ||
38 | { | ||
39 | sk->dir = SSCAN_FORWARD; | ||
40 | sk->margin = sk->len; | ||
41 | } | ||
42 | else if (sk->dir < 0) | ||
43 | { | ||
44 | sk->dir = SSCAN_REVERSE; | ||
45 | sk->margin = 0; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | /* Moves a scan cursor. If amount is positive, the increment is in the scan | ||
50 | * direction, otherwise opposite the scan direction */ | ||
51 | void stream_scan_offset(struct stream_scan *sk, off_t by) | ||
52 | { | ||
53 | off_t bydir = by*sk->dir; | ||
54 | sk->pos += bydir; | ||
55 | sk->margin -= bydir; | ||
56 | sk->len -= by; | ||
57 | } | ||
58 | |||
59 | /** Time helpers **/ | ||
60 | void ts_to_hms(uint32_t pts, struct hms *hms) | ||
61 | { | ||
62 | hms->frac = pts % TS_SECOND; | ||
63 | hms->sec = pts / TS_SECOND; | ||
64 | hms->min = hms->sec / 60; | ||
65 | hms->hrs = hms->min / 60; | ||
66 | hms->sec %= 60; | ||
67 | hms->min %= 60; | ||
68 | } | ||
69 | |||
70 | void hms_format(char *buf, size_t bufsize, struct hms *hms) | ||
71 | { | ||
72 | /* Only display hours if nonzero */ | ||
73 | if (hms->hrs != 0) | ||
74 | { | ||
75 | rb->snprintf(buf, bufsize, "%u:%02u:%02u", | ||
76 | hms->hrs, hms->min, hms->sec); | ||
77 | } | ||
78 | else | ||
79 | { | ||
80 | rb->snprintf(buf, bufsize, "%u:%02u", | ||
81 | hms->min, hms->sec); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | /** Maths **/ | ||
86 | uint32_t muldiv_uint32(uint32_t multiplicand, | ||
87 | uint32_t multiplier, | ||
88 | uint32_t divisor) | ||
89 | { | ||
90 | if (divisor != 0) | ||
91 | { | ||
92 | uint64_t prod = (uint64_t)multiplier*multiplicand + divisor/2; | ||
93 | |||
94 | if ((uint32_t)(prod >> 32) < divisor) | ||
95 | return (uint32_t)(prod / divisor); | ||
96 | } | ||
97 | else if (multiplicand == 0 || multiplier == 0) | ||
98 | { | ||
99 | return 0; /* 0/0 = 0 : yaya */ | ||
100 | } | ||
101 | /* else (> 0) / 0 = UINT32_MAX */ | ||
102 | |||
103 | return UINT32_MAX; /* Saturate */ | ||
104 | } | ||
105 | |||
106 | |||
107 | /** Lists **/ | ||
108 | |||
109 | /* Does the list have any members? */ | ||
110 | bool list_is_empty(void **list) | ||
111 | { | ||
112 | return *list == NULL; | ||
113 | } | ||
114 | |||
115 | /* Is the item inserted into a particular list? */ | ||
116 | bool list_is_member(void **list, void *item) | ||
117 | { | ||
118 | return *rb->find_array_ptr(list, item) != NULL; | ||
119 | } | ||
120 | |||
121 | /* Removes an item from a list - returns true if item was found | ||
122 | * and thus removed. */ | ||
123 | bool list_remove_item(void **list, void *item) | ||
124 | { | ||
125 | return rb->remove_array_ptr(list, item) != -1; | ||
126 | } | ||
127 | |||
128 | /* Adds a list item, insert last, if not already present. */ | ||
129 | void list_add_item(void **list, void *item) | ||
130 | { | ||
131 | void **item_p = rb->find_array_ptr(list, item); | ||
132 | if (*item_p == NULL) | ||
133 | *item_p = item; | ||
134 | } | ||
135 | |||
136 | /* Clears the entire list. */ | ||
137 | void list_clear_all(void **list) | ||
138 | { | ||
139 | while (*list != NULL) | ||
140 | *list++ = NULL; | ||
141 | } | ||
142 | |||
143 | /* Enumerate all items in the array, passing each item in turn to the | ||
144 | * callback as well as the data value. The current item may be safely | ||
145 | * removed. Other changes during enumeration are undefined. The callback | ||
146 | * may return 'false' to stop the enumeration early. */ | ||
147 | void list_enum_items(void **list, | ||
148 | list_enum_callback_t callback, | ||
149 | void* data) | ||
150 | { | ||
151 | for (;;) | ||
152 | { | ||
153 | void *item = *list; | ||
154 | |||
155 | if (item == NULL) | ||
156 | break; | ||
157 | |||
158 | if (callback != NULL && !callback(item, data)) | ||
159 | break; | ||
160 | |||
161 | if (*list == item) | ||
162 | list++; /* Item still there */ | ||
163 | } | ||
164 | } | ||
165 | |||
166 | |||
167 | /** System events **/ | ||
168 | static long mpeg_sysevent_id; | ||
169 | |||
170 | void mpeg_sysevent_clear(void) | ||
171 | { | ||
172 | mpeg_sysevent_id = 0; | ||
173 | } | ||
174 | |||
175 | void mpeg_sysevent_set(void) | ||
176 | { | ||
177 | /* Nonzero and won't invoke anything in default event handler */ | ||
178 | mpeg_sysevent_id = ACTION_STD_CANCEL; | ||
179 | } | ||
180 | |||
181 | long mpeg_sysevent(void) | ||
182 | { | ||
183 | return mpeg_sysevent_id; | ||
184 | } | ||
185 | |||
186 | int mpeg_sysevent_callback(int btn, | ||
187 | const struct menu_item_ex *menu, | ||
188 | struct gui_synclist *this_list) | ||
189 | { | ||
190 | (void) this_list; | ||
191 | switch (btn) | ||
192 | { | ||
193 | case SYS_USB_CONNECTED: | ||
194 | case SYS_POWEROFF: | ||
195 | case SYS_REBOOT: | ||
196 | mpeg_sysevent_id = btn; | ||
197 | return ACTION_STD_CANCEL; | ||
198 | } | ||
199 | |||
200 | return btn; | ||
201 | (void)menu; | ||
202 | } | ||
203 | |||
204 | void mpeg_sysevent_handle(void) | ||
205 | { | ||
206 | long id = mpeg_sysevent(); | ||
207 | if (id != 0) | ||
208 | rb->default_event_handler(id); | ||
209 | } | ||
210 | |||
211 | |||
212 | /** Buttons **/ | ||
213 | |||
214 | int mpeg_button_get(int timeout) | ||
215 | { | ||
216 | int button; | ||
217 | |||
218 | mpeg_sysevent_clear(); | ||
219 | button = timeout == TIMEOUT_BLOCK ? rb->button_get(true) : | ||
220 | rb->button_get_w_tmo(timeout); | ||
221 | |||
222 | /* Produce keyclick */ | ||
223 | rb->keyclick_click(true, button); | ||
224 | |||
225 | return mpeg_sysevent_callback(button, NULL, NULL); | ||
226 | } | ||
227 | |||
diff --git a/apps/plugins/mpegplayer/mpeg_misc.h b/apps/plugins/mpegplayer/mpeg_misc.h deleted file mode 100644 index e04db0e19d..0000000000 --- a/apps/plugins/mpegplayer/mpeg_misc.h +++ /dev/null | |||
@@ -1,258 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Miscellaneous helper API declarations | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #ifndef MPEG_MISC_H | ||
24 | #define MPEG_MISC_H | ||
25 | |||
26 | /* Miscellaneous helpers */ | ||
27 | #ifndef ALIGNED_ATTR | ||
28 | #define ALIGNED_ATTR(x) __attribute__((aligned(x))) | ||
29 | #endif | ||
30 | |||
31 | #include "disk_buf.h" | ||
32 | |||
33 | /* Generic states for when things are too simple to care about naming them */ | ||
34 | enum state_enum | ||
35 | { | ||
36 | STATE0 = 0, | ||
37 | STATE1, | ||
38 | STATE2, | ||
39 | STATE3, | ||
40 | STATE4, | ||
41 | STATE5, | ||
42 | STATE6, | ||
43 | STATE7, | ||
44 | STATE8, | ||
45 | STATE9, | ||
46 | }; | ||
47 | |||
48 | /* Macros for comparing memory bytes to a series of constant bytes in an | ||
49 | efficient manner - evaluate to true if corresponding bytes match */ | ||
50 | #if defined (CPU_ARM) | ||
51 | /* ARM must load 32-bit values at addres % 4 == 0 offsets but this data | ||
52 | isn't aligned nescessarily, so just byte compare */ | ||
53 | #define CMP_3_CONST(_a, _b) \ | ||
54 | ({ int _x; \ | ||
55 | asm volatile ( \ | ||
56 | "ldrb %[x], [%[a], #0] \n" \ | ||
57 | "eors %[x], %[x], %[b0] \n" \ | ||
58 | "ldreqb %[x], [%[a], #1] \n" \ | ||
59 | "eoreqs %[x], %[x], %[b1] \n" \ | ||
60 | "ldreqb %[x], [%[a], #2] \n" \ | ||
61 | "eoreqs %[x], %[x], %[b2] \n" \ | ||
62 | : [x]"=&r"(_x) \ | ||
63 | : [a]"r"(_a), \ | ||
64 | [b0]"i"(((_b) >> 24) & 0xff), \ | ||
65 | [b1]"i"(((_b) >> 16) & 0xff), \ | ||
66 | [b2]"i"(((_b) >> 8) & 0xff) \ | ||
67 | ); \ | ||
68 | _x == 0; }) | ||
69 | |||
70 | #define CMP_4_CONST(_a, _b) \ | ||
71 | ({ int _x; \ | ||
72 | asm volatile ( \ | ||
73 | "ldrb %[x], [%[a], #0] \n" \ | ||
74 | "eors %[x], %[x], %[b0] \n" \ | ||
75 | "ldreqb %[x], [%[a], #1] \n" \ | ||
76 | "eoreqs %[x], %[x], %[b1] \n" \ | ||
77 | "ldreqb %[x], [%[a], #2] \n" \ | ||
78 | "eoreqs %[x], %[x], %[b2] \n" \ | ||
79 | "ldreqb %[x], [%[a], #3] \n" \ | ||
80 | "eoreqs %[x], %[x], %[b3] \n" \ | ||
81 | : [x]"=&r"(_x) \ | ||
82 | : [a]"r"(_a), \ | ||
83 | [b0]"i"(((_b) >> 24) & 0xff), \ | ||
84 | [b1]"i"(((_b) >> 16) & 0xff), \ | ||
85 | [b2]"i"(((_b) >> 8) & 0xff), \ | ||
86 | [b3]"i"(((_b) ) & 0xff) \ | ||
87 | ); \ | ||
88 | _x == 0; }) | ||
89 | |||
90 | #elif defined (CPU_COLDFIRE) | ||
91 | /* Coldfire can just load a 32 bit value at any offset but ASM is not the | ||
92 | best way to integrate this with the C code */ | ||
93 | #define CMP_3_CONST(a, b) \ | ||
94 | (((*(uint32_t *)(a) >> 8) == ((uint32_t)(b) >> 8))) | ||
95 | |||
96 | #define CMP_4_CONST(a, b) \ | ||
97 | ((*(uint32_t *)(a) == (b))) | ||
98 | |||
99 | #else | ||
100 | /* Don't know what this is - use bytewise comparisons */ | ||
101 | #define CMP_3_CONST(a, b) \ | ||
102 | (( ((a)[0] ^ (((b) >> 24) & 0xff)) | \ | ||
103 | ((a)[1] ^ (((b) >> 16) & 0xff)) | \ | ||
104 | ((a)[2] ^ (((b) >> 8) & 0xff)) ) == 0) | ||
105 | |||
106 | #define CMP_4_CONST(a, b) \ | ||
107 | (( ((a)[0] ^ (((b) >> 24) & 0xff)) | \ | ||
108 | ((a)[1] ^ (((b) >> 16) & 0xff)) | \ | ||
109 | ((a)[2] ^ (((b) >> 8) & 0xff)) | \ | ||
110 | ((a)[3] ^ (((b) ) & 0xff)) ) == 0) | ||
111 | #endif /* CPU_* */ | ||
112 | |||
113 | |||
114 | /** Streams **/ | ||
115 | |||
116 | /* Convert PTS/DTS ticks to our clock ticks */ | ||
117 | #define TS_TO_TICKS(pts) ((uint64_t)CLOCK_RATE*(pts) / TS_SECOND) | ||
118 | /* Convert our clock ticks to PTS/DTS ticks */ | ||
119 | #define TICKS_TO_TS(ts) ((uint64_t)TS_SECOND*(ts) / CLOCK_RATE) | ||
120 | /* Convert timecode ticks to our clock ticks */ | ||
121 | #define TC_TO_TICKS(stamp) ((uint64_t)CLOCK_RATE*(stamp) / TC_SECOND) | ||
122 | /* Convert our clock ticks to timecode ticks */ | ||
123 | #define TICKS_TO_TC(stamp) ((uint64_t)TC_SECOND*(stamp) / CLOCK_RATE) | ||
124 | /* Convert timecode ticks to timestamp ticks */ | ||
125 | #define TC_TO_TS(stamp) ((stamp) / 600) | ||
126 | |||
127 | /* | ||
128 | * S = start position, E = end position | ||
129 | * | ||
130 | * pos: | ||
131 | * initialize to search start position (S) | ||
132 | * | ||
133 | * len: | ||
134 | * initialize to = ABS(S-E) | ||
135 | * scanning = remaining bytes in scan direction | ||
136 | * | ||
137 | * dir: | ||
138 | * scan direction; >= 0 == forward, < 0 == reverse | ||
139 | * | ||
140 | * margin: | ||
141 | * amount of data to right of cursor - initialize by stream_scan_normalize | ||
142 | * | ||
143 | * data: | ||
144 | * Extra data used/returned by the function implemented | ||
145 | * | ||
146 | * Forward scan: | ||
147 | * S pos E | ||
148 | * | *<-margin->| dir-> | ||
149 | * | |<--len--->| | ||
150 | * | ||
151 | * Reverse scan: | ||
152 | * E pos S | ||
153 | * |<-len->*<-margin->| <-dir | ||
154 | * | | | | ||
155 | */ | ||
156 | struct stream_scan | ||
157 | { | ||
158 | off_t pos; /* Initial scan position (file offset) */ | ||
159 | ssize_t len; /* Maximum length of scan */ | ||
160 | off_t dir; /* Direction - >= 0; forward, < 0 backward */ | ||
161 | ssize_t margin; /* Used by function to track margin between position and data end */ | ||
162 | intptr_t data; /* */ | ||
163 | struct dbuf_l2_cache l2; | ||
164 | }; | ||
165 | |||
166 | #define SSCAN_REVERSE (-1) | ||
167 | #define SSCAN_FORWARD 1 | ||
168 | |||
169 | /* Initializes the cursor */ | ||
170 | void stream_scan_init(struct stream_scan *sk); | ||
171 | |||
172 | /* Ensures direction is -1 or 1 and margin is properly initialized */ | ||
173 | void stream_scan_normalize(struct stream_scan *sk); | ||
174 | |||
175 | /* Moves a scan cursor. If amount is positive, the increment is in the scan | ||
176 | * direction, otherwise opposite the scan direction */ | ||
177 | void stream_scan_offset(struct stream_scan *sk, off_t by); | ||
178 | |||
179 | /** Time helpers **/ | ||
180 | struct hms | ||
181 | { | ||
182 | unsigned int hrs; | ||
183 | unsigned int min; | ||
184 | unsigned int sec; | ||
185 | unsigned int frac; | ||
186 | }; | ||
187 | |||
188 | void ts_to_hms(uint32_t ts, struct hms *hms); | ||
189 | void hms_format(char *buf, size_t bufsize, struct hms *hms); | ||
190 | |||
191 | /** Maths **/ | ||
192 | |||
193 | /* Moving average */ | ||
194 | #define AVERAGE(var, x, count) \ | ||
195 | ({ typeof (count) _c = (count); \ | ||
196 | ((var) * (_c-1) + (x)) / (_c); }) | ||
197 | |||
198 | /* Multiply two unsigned 32-bit integers yielding a 64-bit result and | ||
199 | * divide by another unsigned 32-bit integer to yield a 32-bit result. | ||
200 | * Rounds to nearest with saturation. */ | ||
201 | uint32_t muldiv_uint32(uint32_t multiplicand, | ||
202 | uint32_t multiplier, | ||
203 | uint32_t divisor); | ||
204 | |||
205 | |||
206 | /** Lists **/ | ||
207 | |||
208 | /* Does the list have any members? */ | ||
209 | bool list_is_empty(void **list); | ||
210 | |||
211 | /* Is the item inserted into a particular list? */ | ||
212 | bool list_is_member(void **list, void *item); | ||
213 | |||
214 | /* Removes an item from a list - returns true if item was found | ||
215 | * and thus removed. */ | ||
216 | bool list_remove_item(void **list, void *item); | ||
217 | |||
218 | /* Adds a list item, insert last, if not already present. */ | ||
219 | void list_add_item(void **list, void *item); | ||
220 | |||
221 | /* Clears the entire list. */ | ||
222 | void list_clear_all(void **list); | ||
223 | |||
224 | /* Enumerate all items in the array. */ | ||
225 | typedef bool (*list_enum_callback_t)(void *item, void* data); | ||
226 | |||
227 | void list_enum_items(void **list, | ||
228 | list_enum_callback_t callback, | ||
229 | void *data); | ||
230 | |||
231 | |||
232 | /** System events **/ | ||
233 | |||
234 | /* Clear event */ | ||
235 | void mpeg_sysevent_clear(void); | ||
236 | |||
237 | /* Set to ACTION_STD_CANCEL */ | ||
238 | void mpeg_sysevent_set(void); | ||
239 | |||
240 | /* Get event code */ | ||
241 | long mpeg_sysevent(void); | ||
242 | |||
243 | /* Call with a system event code and used as menu callback */ | ||
244 | int mpeg_sysevent_callback(int btn, const struct menu_item_ex *menu, | ||
245 | struct gui_synclist *this_list); | ||
246 | |||
247 | /* Handle recorded event */ | ||
248 | void mpeg_sysevent_handle(void); | ||
249 | |||
250 | |||
251 | /** Buttons **/ | ||
252 | |||
253 | /* Get button codes while remembering important events for later | ||
254 | * processing; return of ACTION_STD_CANCEL means plugin should | ||
255 | * abort and handle the event */ | ||
256 | int mpeg_button_get(int timeout); | ||
257 | |||
258 | #endif /* MPEG_MISC_H */ | ||
diff --git a/apps/plugins/mpegplayer/mpeg_parser.c b/apps/plugins/mpegplayer/mpeg_parser.c deleted file mode 100644 index cc57b0c43c..0000000000 --- a/apps/plugins/mpegplayer/mpeg_parser.c +++ /dev/null | |||
@@ -1,1203 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Parser for MPEG streams | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #include "plugin.h" | ||
24 | #include "mpegplayer.h" | ||
25 | |||
26 | struct stream_parser str_parser SHAREDBSS_ATTR; | ||
27 | |||
28 | static void parser_init_state(void) | ||
29 | { | ||
30 | str_parser.last_seek_time = 0; | ||
31 | str_parser.format = STREAM_FMT_UNKNOWN; | ||
32 | str_parser.start_pts = INVALID_TIMESTAMP; | ||
33 | str_parser.end_pts = INVALID_TIMESTAMP; | ||
34 | str_parser.flags = 0; | ||
35 | str_parser.dims.w = 0; | ||
36 | str_parser.dims.h = 0; | ||
37 | } | ||
38 | |||
39 | /* Place the stream in a state to begin parsing - sync will be performed | ||
40 | * first */ | ||
41 | void str_initialize(struct stream *str, off_t pos) | ||
42 | { | ||
43 | /* Initial positions start here */ | ||
44 | str->hdr.win_left = str->hdr.win_right = pos; | ||
45 | /* No packet */ | ||
46 | str->curr_packet = NULL; | ||
47 | /* Pick up parsing from this point in the buffer */ | ||
48 | str->curr_packet_end = disk_buf_offset2ptr(pos); | ||
49 | /* No flags */ | ||
50 | str->pkt_flags = 0; | ||
51 | /* Sync first */ | ||
52 | str->state = SSTATE_SYNC; | ||
53 | } | ||
54 | |||
55 | /* Place the stream in an end of data state */ | ||
56 | void str_end_of_stream(struct stream *str) | ||
57 | { | ||
58 | /* Offsets that prevent this stream from being included in the | ||
59 | * min left/max right window so that no buffering is triggered on | ||
60 | * its behalf. Set right to the min first so a thread reading the | ||
61 | * overall window gets doesn't see this as valid no matter what the | ||
62 | * file length. */ | ||
63 | str->hdr.win_right = OFF_T_MIN; | ||
64 | str->hdr.win_left = OFF_T_MAX; | ||
65 | /* No packets */ | ||
66 | str->curr_packet = str->curr_packet_end = NULL; | ||
67 | /* No flags */ | ||
68 | str->pkt_flags = 0; | ||
69 | /* Fin */ | ||
70 | str->state = SSTATE_END; | ||
71 | } | ||
72 | |||
73 | /* Return a timestamp at address p+offset if the marker bits are in tact */ | ||
74 | static inline uint32_t read_pts(uint8_t *p, off_t offset) | ||
75 | { | ||
76 | return TS_CHECK_MARKERS(p, offset) ? | ||
77 | TS_FROM_HEADER(p, offset) : INVALID_TIMESTAMP; | ||
78 | } | ||
79 | |||
80 | static inline bool validate_timestamp(uint32_t ts) | ||
81 | { | ||
82 | return ts >= str_parser.start_pts && ts <= str_parser.end_pts; | ||
83 | } | ||
84 | |||
85 | /* Find a start code before or after a given position */ | ||
86 | uint8_t * mpeg_parser_scan_start_code(struct stream_scan *sk, uint32_t code) | ||
87 | { | ||
88 | stream_scan_normalize(sk); | ||
89 | |||
90 | if (sk->dir < 0) | ||
91 | { | ||
92 | /* Reverse scan - start with at least the min needed */ | ||
93 | stream_scan_offset(sk, 4); | ||
94 | } | ||
95 | |||
96 | code &= 0xff; /* Only the low byte matters */ | ||
97 | |||
98 | while (sk->len >= 0 && sk->margin >= 4) | ||
99 | { | ||
100 | uint8_t *p; | ||
101 | off_t pos = disk_buf_lseek(sk->pos, SEEK_SET); | ||
102 | ssize_t len = disk_buf_getbuffer_l2(&sk->l2, 4, &p); | ||
103 | |||
104 | if (pos < 0 || len < 4) | ||
105 | break; | ||
106 | |||
107 | if (CMP_3_CONST(p, PACKET_START_CODE_PREFIX) && p[3] == code) | ||
108 | { | ||
109 | return p; | ||
110 | } | ||
111 | |||
112 | stream_scan_offset(sk, 1); | ||
113 | } | ||
114 | |||
115 | return NULL; | ||
116 | } | ||
117 | |||
118 | /* Find a PES packet header for any stream - return stream to which it | ||
119 | * belongs */ | ||
120 | unsigned mpeg_parser_scan_pes(struct stream_scan *sk) | ||
121 | { | ||
122 | stream_scan_normalize(sk); | ||
123 | |||
124 | if (sk->dir < 0) | ||
125 | { | ||
126 | /* Reverse scan - start with at least the min needed */ | ||
127 | stream_scan_offset(sk, 4); | ||
128 | } | ||
129 | |||
130 | while (sk->len >= 0 && sk->margin >= 4) | ||
131 | { | ||
132 | uint8_t *p; | ||
133 | off_t pos = disk_buf_lseek(sk->pos, SEEK_SET); | ||
134 | ssize_t len = disk_buf_getbuffer_l2(&sk->l2, 4, &p); | ||
135 | |||
136 | if (pos < 0 || len < 4) | ||
137 | break; | ||
138 | |||
139 | if (CMP_3_CONST(p, PACKET_START_CODE_PREFIX)) | ||
140 | { | ||
141 | unsigned id = p[3]; | ||
142 | if (id >= 0xb9) | ||
143 | return id; /* PES header */ | ||
144 | /* else some video stream element */ | ||
145 | } | ||
146 | |||
147 | stream_scan_offset(sk, 1); | ||
148 | } | ||
149 | |||
150 | return -1; | ||
151 | } | ||
152 | |||
153 | /* Return the first SCR found from the scan direction */ | ||
154 | uint32_t mpeg_parser_scan_scr(struct stream_scan *sk) | ||
155 | { | ||
156 | uint8_t *p = mpeg_parser_scan_start_code(sk, MPEG_STREAM_PACK_HEADER); | ||
157 | |||
158 | if (p != NULL && sk->margin >= 9) /* 9 bytes total required */ | ||
159 | { | ||
160 | sk->data = 9; | ||
161 | |||
162 | if ((p[4] & 0xc0) == 0x40) /* mpeg-2 */ | ||
163 | { | ||
164 | /* Lookhead p+8 */ | ||
165 | if (MPEG2_CHECK_PACK_SCR_MARKERS(p, 4)) | ||
166 | return MPEG2_PACK_HEADER_SCR(p, 4); | ||
167 | } | ||
168 | else if ((p[4] & 0xf0) == 0x20) /* mpeg-1 */ | ||
169 | { | ||
170 | /* Lookahead p+8 */ | ||
171 | if (TS_CHECK_MARKERS(p, 4)) | ||
172 | return TS_FROM_HEADER(p, 4); | ||
173 | } | ||
174 | /* Weird pack header */ | ||
175 | sk->data = 5; | ||
176 | } | ||
177 | |||
178 | return INVALID_TIMESTAMP; | ||
179 | } | ||
180 | |||
181 | uint32_t mpeg_parser_scan_pts(struct stream_scan *sk, unsigned id) | ||
182 | { | ||
183 | stream_scan_normalize(sk); | ||
184 | |||
185 | if (sk->dir < 0) | ||
186 | { | ||
187 | /* Reverse scan - start with at least the min needed */ | ||
188 | stream_scan_offset(sk, 4); | ||
189 | } | ||
190 | |||
191 | while (sk->len >= 0 && sk->margin >= 4) | ||
192 | { | ||
193 | uint8_t *p; | ||
194 | off_t pos = disk_buf_lseek(sk->pos, SEEK_SET); | ||
195 | ssize_t len = disk_buf_getbuffer_l2(&sk->l2, 30, &p); | ||
196 | |||
197 | if (pos < 0 || len < 4) | ||
198 | break; | ||
199 | |||
200 | if (CMP_3_CONST(p, PACKET_START_CODE_PREFIX) && p[3] == id) | ||
201 | { | ||
202 | uint8_t *h = p; | ||
203 | |||
204 | if (sk->margin < 7) | ||
205 | { | ||
206 | /* Insufficient data */ | ||
207 | } | ||
208 | else if ((h[6] & 0xc0) == 0x80) /* mpeg2 */ | ||
209 | { | ||
210 | if (sk->margin >= 14 && (h[7] & 0x80) != 0x00) | ||
211 | { | ||
212 | sk->data = 14; | ||
213 | return read_pts(h, 9); | ||
214 | } | ||
215 | } | ||
216 | else /* mpeg1 */ | ||
217 | { | ||
218 | ssize_t l = 6; | ||
219 | ssize_t margin = sk->margin; | ||
220 | |||
221 | /* Skip stuffing_byte */ | ||
222 | while (margin > 7 && h[l] == 0xff && ++l <= 22) | ||
223 | --margin; | ||
224 | |||
225 | if (margin >= 7) | ||
226 | { | ||
227 | if ((h[l] & 0xc0) == 0x40) | ||
228 | { | ||
229 | /* Skip STD_buffer_scale and STD_buffer_size */ | ||
230 | margin -= 2; | ||
231 | l += 2; | ||
232 | } | ||
233 | |||
234 | if (margin >= 5) | ||
235 | { | ||
236 | /* Header points to the mpeg1 pes header */ | ||
237 | h += l; | ||
238 | |||
239 | if ((h[0] & 0xe0) == 0x20) | ||
240 | { | ||
241 | /* PTS or PTS_DTS indicated */ | ||
242 | sk->data = (h + 5) - p; | ||
243 | return read_pts(h, 0); | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | /* No PTS present - keep searching for a matching PES header with | ||
249 | * one */ | ||
250 | } | ||
251 | |||
252 | stream_scan_offset(sk, 1); | ||
253 | } | ||
254 | |||
255 | return INVALID_TIMESTAMP; | ||
256 | } | ||
257 | |||
258 | static bool init_video_info(void) | ||
259 | { | ||
260 | DEBUGF("Getting movie size\n"); | ||
261 | |||
262 | /* The decoder handles this in order to initialize its knowledge of the | ||
263 | * movie parameters making seeking easier */ | ||
264 | str_send_msg(&video_str, STREAM_RESET, 0); | ||
265 | if (str_send_msg(&video_str, VIDEO_GET_SIZE, | ||
266 | (intptr_t)&str_parser.dims) != 0) | ||
267 | { | ||
268 | return true; | ||
269 | } | ||
270 | |||
271 | DEBUGF(" failed\n"); | ||
272 | return false; | ||
273 | } | ||
274 | |||
275 | static bool init_times(struct stream *str) | ||
276 | { | ||
277 | struct stream tmp_str; | ||
278 | const ssize_t filesize = disk_buf_filesize(); | ||
279 | const ssize_t max_probe = MIN(512*1024, filesize); | ||
280 | bool found_stream; | ||
281 | |||
282 | /* Simply find the first earliest timestamp - this will be the one | ||
283 | * used when streaming anyway */ | ||
284 | DEBUGF("Finding start_pts: 0x%02x\n", str->id); | ||
285 | |||
286 | found_stream = false; | ||
287 | str->start_pts = INVALID_TIMESTAMP; | ||
288 | str->end_pts = INVALID_TIMESTAMP; | ||
289 | |||
290 | tmp_str.id = str->id; | ||
291 | tmp_str.hdr.pos = 0; | ||
292 | tmp_str.hdr.limit = max_probe; | ||
293 | |||
294 | /* Probe for many for the start because some stamps could be anomalous. | ||
295 | * Video also can also have things out of order. Just see what it's got. | ||
296 | */ | ||
297 | while (1) | ||
298 | { | ||
299 | switch (parser_get_next_data(&tmp_str, STREAM_PM_RANDOM_ACCESS)) | ||
300 | { | ||
301 | case STREAM_DATA_END: | ||
302 | break; | ||
303 | case STREAM_OK: | ||
304 | found_stream = true; | ||
305 | if (tmp_str.pkt_flags & PKT_HAS_TS) | ||
306 | { | ||
307 | if (tmp_str.pts < str->start_pts) | ||
308 | str->start_pts = tmp_str.pts; | ||
309 | } | ||
310 | continue; | ||
311 | } | ||
312 | |||
313 | break; | ||
314 | } | ||
315 | |||
316 | if (!found_stream) | ||
317 | { | ||
318 | DEBUGF(" stream not found:0x%02x\n", str->id); | ||
319 | return false; | ||
320 | } | ||
321 | |||
322 | DEBUGF(" start:%u\n", (unsigned)str->start_pts); | ||
323 | |||
324 | /* Use the decoder thread to perform a synchronized search - no | ||
325 | * decoding should take place but just a simple run through timestamps | ||
326 | * and durations as the decoder would see them. This should give the | ||
327 | * precise time at the end of the last frame for the stream. */ | ||
328 | DEBUGF("Finding end_pts: 0x%02x\n", str->id); | ||
329 | |||
330 | str_parser.parms.sd.time = MAX_TIMESTAMP; | ||
331 | str_parser.parms.sd.sk.pos = filesize - max_probe; | ||
332 | str_parser.parms.sd.sk.len = max_probe; | ||
333 | str_parser.parms.sd.sk.dir = SSCAN_FORWARD; | ||
334 | |||
335 | str_send_msg(str, STREAM_RESET, 0); | ||
336 | |||
337 | if (str_send_msg(str, STREAM_FIND_END_TIME, | ||
338 | (intptr_t)&str_parser.parms.sd) == STREAM_PERFECT_MATCH) | ||
339 | { | ||
340 | str->end_pts = str_parser.parms.sd.time; | ||
341 | DEBUGF(" end:%u\n", (unsigned)str->end_pts); | ||
342 | } | ||
343 | |||
344 | return true; | ||
345 | } | ||
346 | |||
347 | static bool check_times(const struct stream *str) | ||
348 | { | ||
349 | return str->start_pts < str->end_pts && | ||
350 | str->end_pts != INVALID_TIMESTAMP; | ||
351 | } | ||
352 | |||
353 | /* Return the best-fit file offset of a timestamp in the PES where | ||
354 | * timstamp <= time < next timestamp. Will try to return something reasonably | ||
355 | * valid if best-fit could not be made. */ | ||
356 | static off_t mpeg_parser_seek_PTS(uint32_t time, unsigned id) | ||
357 | { | ||
358 | ssize_t pos_left = 0; | ||
359 | ssize_t pos_right = disk_buf.filesize; | ||
360 | ssize_t pos, pos_new; | ||
361 | uint32_t time_left = str_parser.start_pts; | ||
362 | uint32_t time_right = str_parser.end_pts; | ||
363 | uint32_t pts = 0; | ||
364 | uint32_t prevpts = 0; | ||
365 | enum state_enum state = STATE0; | ||
366 | struct stream_scan sk; | ||
367 | |||
368 | stream_scan_init(&sk); | ||
369 | |||
370 | /* Initial estimate taken from average bitrate - later interpolations are | ||
371 | * taken similarly based on the remaining file interval */ | ||
372 | pos_new = muldiv_uint32(time - time_left, pos_right - pos_left, | ||
373 | time_right - time_left) + pos_left; | ||
374 | |||
375 | /* return this estimated position if nothing better comes up */ | ||
376 | pos = pos_new; | ||
377 | |||
378 | DEBUGF("Seeking stream 0x%02x\n", id); | ||
379 | DEBUGF("$$ tl:%u t:%u ct:?? tr:%u\n pl:%ld pn:%ld pr:%ld\n", | ||
380 | (unsigned)time_left, (unsigned)time, (unsigned)time_right, | ||
381 | (long)pos_left, (long)pos_new, (long)pos_right); | ||
382 | |||
383 | sk.dir = SSCAN_REVERSE; | ||
384 | |||
385 | while (state < STATE9) | ||
386 | { | ||
387 | uint32_t currpts; | ||
388 | sk.pos = pos_new; | ||
389 | sk.len = (sk.dir < 0) ? pos_new - pos_left : pos_right - pos_new; | ||
390 | |||
391 | currpts = mpeg_parser_scan_pts(&sk, id); | ||
392 | |||
393 | if (currpts != INVALID_TIMESTAMP) | ||
394 | { | ||
395 | ssize_t pos_adj; /* Adjustment to over or under-estimate */ | ||
396 | |||
397 | /* Found a valid timestamp - see were it lies in relation to | ||
398 | * target */ | ||
399 | if (currpts < time) | ||
400 | { | ||
401 | /* Time at current position is before seek time - move | ||
402 | * forward */ | ||
403 | if (currpts > pts) | ||
404 | { | ||
405 | /* This is less than the desired time but greater than | ||
406 | * the currently seeked one; move the position up */ | ||
407 | pts = currpts; | ||
408 | pos = sk.pos; | ||
409 | } | ||
410 | |||
411 | /* No next timestamp can be sooner */ | ||
412 | pos_left = sk.pos + sk.data; | ||
413 | time_left = currpts; | ||
414 | |||
415 | if (pos_right <= pos_left) | ||
416 | break; /* If the window disappeared - we're done */ | ||
417 | |||
418 | pos_new = muldiv_uint32(time - time_left, | ||
419 | pos_right - pos_left, | ||
420 | time_right - time_left); | ||
421 | /* Point is ahead of us - fudge estimate a bit high */ | ||
422 | pos_adj = pos_new / 10; | ||
423 | |||
424 | if (pos_adj > 512*1024) | ||
425 | pos_adj = 512*1024; | ||
426 | |||
427 | pos_new += pos_left + pos_adj; | ||
428 | |||
429 | if (pos_new >= pos_right) | ||
430 | { | ||
431 | /* Estimate could push too far */ | ||
432 | pos_new = pos_right; | ||
433 | } | ||
434 | |||
435 | state = STATE2; /* Last scan was early */ | ||
436 | sk.dir = SSCAN_REVERSE; | ||
437 | |||
438 | DEBUGF(">> tl:%u t:%u ct:%u tr:%u\n pl:%ld pn:%ld pr:%ld\n", | ||
439 | (unsigned)time_left, (unsigned)time, (unsigned)currpts, | ||
440 | (unsigned)time_right, (long)pos_left, (long)pos_new, | ||
441 | (long)pos_right); | ||
442 | } | ||
443 | else if (currpts > time) | ||
444 | { | ||
445 | /* Time at current position is past seek time - move | ||
446 | backward */ | ||
447 | pos_right = sk.pos; | ||
448 | time_right = currpts; | ||
449 | |||
450 | if (pos_right <= pos_left) | ||
451 | break; /* If the window disappeared - we're done */ | ||
452 | |||
453 | pos_new = muldiv_uint32(time - time_left, | ||
454 | pos_right - pos_left, | ||
455 | time_right - time_left); | ||
456 | /* Overshot the seek point - fudge estimate a bit low */ | ||
457 | pos_adj = pos_new / 10; | ||
458 | |||
459 | if (pos_adj > 512*1024) | ||
460 | pos_adj = 512*1024; | ||
461 | |||
462 | pos_new += pos_left - pos_adj; | ||
463 | |||
464 | state = STATE3; /* Last scan was late */ | ||
465 | sk.dir = SSCAN_REVERSE; | ||
466 | |||
467 | DEBUGF("<< tl:%u t:%u ct:%u tr:%u\n pl:%ld pn:%ld pr:%ld\n", | ||
468 | (unsigned)time_left, (unsigned)time, (unsigned)currpts, | ||
469 | (unsigned)time_right, (long)pos_left, (long)pos_new, | ||
470 | (long)pos_right); | ||
471 | } | ||
472 | else | ||
473 | { | ||
474 | /* Exact match - it happens */ | ||
475 | DEBUGF("|| tl:%u t:%u ct:%u tr:%u\n pl:%ld pn:%ld pr:%ld\n", | ||
476 | (unsigned)time_left, (unsigned)time, (unsigned)currpts, | ||
477 | (unsigned)time_right, (long)pos_left, (long)pos_new, | ||
478 | (long)pos_right); | ||
479 | pts = currpts; | ||
480 | pos = sk.pos; | ||
481 | state = STATE9; | ||
482 | } | ||
483 | } | ||
484 | else | ||
485 | { | ||
486 | /* Nothing found */ | ||
487 | |||
488 | switch (state) | ||
489 | { | ||
490 | case STATE1: | ||
491 | /* We already tried the bruteforce scan and failed again - no | ||
492 | * more stamps could possibly exist in the interval */ | ||
493 | DEBUGF("!! no timestamp 2x\n"); | ||
494 | break; | ||
495 | case STATE0: | ||
496 | /* Hardly likely except at very beginning - just do L->R scan | ||
497 | * to find something */ | ||
498 | DEBUGF("!! no timestamp on first probe: %ld\n", sk.pos); | ||
499 | case STATE2: | ||
500 | case STATE3: | ||
501 | /* Could just be missing timestamps because the interval is | ||
502 | * narrowing down. A large block of data from another stream | ||
503 | * may also be in the midst of our chosen points which could | ||
504 | * cluster at either extreme end. If anything is there, this | ||
505 | * will find it. */ | ||
506 | pos_new = pos_left; | ||
507 | sk.dir = SSCAN_FORWARD; | ||
508 | DEBUGF("?? tl:%u t:%u ct:%u tr:%u\n pl:%ld pn:%ld pr:%ld\n", | ||
509 | (unsigned)time_left, (unsigned)time, (unsigned)currpts, | ||
510 | (unsigned)time_right, (long)pos_left, (long)pos_new, | ||
511 | (long)pos_right); | ||
512 | state = STATE1; | ||
513 | break; | ||
514 | default: | ||
515 | DEBUGF("?? Invalid state: %d\n", state); | ||
516 | } | ||
517 | } | ||
518 | |||
519 | /* Same timestamp twice = quit */ | ||
520 | if (currpts == prevpts) | ||
521 | { | ||
522 | DEBUGF("!! currpts == prevpts (stop)\n"); | ||
523 | state = STATE9; | ||
524 | } | ||
525 | |||
526 | prevpts = currpts; | ||
527 | } | ||
528 | |||
529 | #if defined(DEBUG) || defined(SIMULATOR) | ||
530 | /* The next pts after the seeked-to position should be greater - | ||
531 | * most of the time - frames out of presentation order may muck it | ||
532 | * up a slight bit */ | ||
533 | sk.pos = pos + 1; | ||
534 | sk.len = disk_buf.filesize; | ||
535 | sk.dir = SSCAN_FORWARD; | ||
536 | |||
537 | uint32_t nextpts = mpeg_parser_scan_pts(&sk, id); | ||
538 | DEBUGF("Seek pos:%ld pts:%u t:%u next pts:%u \n", | ||
539 | (long)pos, (unsigned)pts, (unsigned)time, (unsigned)nextpts); | ||
540 | |||
541 | if (pts <= time && time < nextpts) | ||
542 | { | ||
543 | /* Smile - it worked */ | ||
544 | DEBUGF(" :) pts<=time<next pts\n"); | ||
545 | } | ||
546 | else | ||
547 | { | ||
548 | /* See where things ended up */ | ||
549 | if (pts > time) | ||
550 | { | ||
551 | /* Hmm */ | ||
552 | DEBUGF(" :\\ pts>time\n"); | ||
553 | } | ||
554 | if (pts >= nextpts) | ||
555 | { | ||
556 | /* Weird - probably because of encoded order & tends to be right | ||
557 | * anyway if other criteria are met */ | ||
558 | DEBUGF(" :p pts>=next pts\n"); | ||
559 | } | ||
560 | if (time >= nextpts) | ||
561 | { | ||
562 | /* Ugh */ | ||
563 | DEBUGF(" :( time>=nextpts\n"); | ||
564 | } | ||
565 | } | ||
566 | #endif | ||
567 | |||
568 | return pos; | ||
569 | } | ||
570 | |||
571 | static void prepare_audio(uint32_t time) | ||
572 | { | ||
573 | off_t pos; | ||
574 | |||
575 | if (!str_send_msg(&audio_str, STREAM_NEEDS_SYNC, time)) | ||
576 | { | ||
577 | DEBUGF("Audio was ready\n"); | ||
578 | return; | ||
579 | } | ||
580 | |||
581 | pos = mpeg_parser_seek_PTS(time, audio_str.id); | ||
582 | str_send_msg(&audio_str, STREAM_RESET, 0); | ||
583 | |||
584 | str_parser.parms.sd.time = time; | ||
585 | str_parser.parms.sd.sk.pos = pos; | ||
586 | str_parser.parms.sd.sk.len = 1024*1024; | ||
587 | str_parser.parms.sd.sk.dir = SSCAN_FORWARD; | ||
588 | |||
589 | str_send_msg(&audio_str, STREAM_SYNC, (intptr_t)&str_parser.parms.sd); | ||
590 | } | ||
591 | |||
592 | /* This function demuxes the streams and gives the next stream data | ||
593 | * pointer. | ||
594 | * | ||
595 | * STREAM_PM_STREAMING is for operation during playback. If the nescessary | ||
596 | * data and worst-case lookahead margin is not available, the stream is | ||
597 | * registered for notification when the data becomes available. If parsing | ||
598 | * extends beyond the end of the file or the end of stream marker is reached, | ||
599 | * STREAM_DATA_END is returned and the stream state changed to SSTATE_EOS. | ||
600 | * | ||
601 | * STREAM_PM_RANDOM_ACCESS is for operation when not playing such as seeking. | ||
602 | * If the file cache misses for the current position + lookahead, it will be | ||
603 | * loaded from disk. When the specified limit is reached, STREAM_DATA_END is | ||
604 | * returned. | ||
605 | * | ||
606 | * The results from one mode may be used as input to the other. Random access | ||
607 | * requires cooperation amongst threads to avoid evicting another stream's | ||
608 | * data. | ||
609 | */ | ||
610 | static int parse_demux(struct stream *str, enum stream_parse_mode type) | ||
611 | { | ||
612 | #define INC_BUF(offset) \ | ||
613 | ({ off_t _o = (offset); \ | ||
614 | str->hdr.win_right += _o; \ | ||
615 | if ((p += _o) >= disk_buf.end) \ | ||
616 | p -= disk_buf.size; }) | ||
617 | |||
618 | static const int mpeg1_skip_table[16] = | ||
619 | { 0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
620 | |||
621 | uint8_t *p = str->curr_packet_end; | ||
622 | |||
623 | str->pkt_flags = 0; | ||
624 | |||
625 | while (1) | ||
626 | { | ||
627 | uint8_t *header; | ||
628 | unsigned id; | ||
629 | ssize_t length, bytes; | ||
630 | |||
631 | switch (type) | ||
632 | { | ||
633 | case STREAM_PM_STREAMING: | ||
634 | /* Has the end been reached already? */ | ||
635 | switch (str->state) | ||
636 | { | ||
637 | case SSTATE_PARSE: /* Expected case first if no jumptable */ | ||
638 | /* Are we at the end of file? */ | ||
639 | if (str->hdr.win_left < disk_buf.filesize) | ||
640 | break; | ||
641 | str_end_of_stream(str); | ||
642 | return STREAM_DATA_END; | ||
643 | |||
644 | case SSTATE_SYNC: | ||
645 | /* Is sync at the end of file? */ | ||
646 | if (str->hdr.win_right < disk_buf.filesize) | ||
647 | break; | ||
648 | str_end_of_stream(str); | ||
649 | /* Fall-through */ | ||
650 | case SSTATE_END: | ||
651 | return STREAM_DATA_END; | ||
652 | } | ||
653 | |||
654 | if (!disk_buf_is_data_ready(&str->hdr, MIN_BUFAHEAD)) | ||
655 | { | ||
656 | /* This data range is not buffered yet - register stream to | ||
657 | * be notified when it becomes available. Stream is obliged | ||
658 | * to enter a TSTATE_DATA state if it must wait. */ | ||
659 | int res = str_next_data_not_ready(str); | ||
660 | |||
661 | if (res != STREAM_OK) | ||
662 | return res; | ||
663 | } | ||
664 | break; | ||
665 | /* STREAM_PM_STREAMING: */ | ||
666 | |||
667 | case STREAM_PM_RANDOM_ACCESS: | ||
668 | str->hdr.pos = disk_buf_lseek(str->hdr.pos, SEEK_SET); | ||
669 | |||
670 | if (str->hdr.pos < 0 || str->hdr.pos >= str->hdr.limit || | ||
671 | disk_buf_getbuffer(MIN_BUFAHEAD, &p, NULL, NULL) <= 0) | ||
672 | { | ||
673 | str_end_of_stream(str); | ||
674 | return STREAM_DATA_END; | ||
675 | } | ||
676 | |||
677 | str->state = SSTATE_SYNC; | ||
678 | str->hdr.win_left = str->hdr.pos; | ||
679 | str->curr_packet = NULL; | ||
680 | str->curr_packet_end = p; | ||
681 | break; | ||
682 | /* STREAM_PM_RANDOM_ACCESS: */ | ||
683 | } | ||
684 | |||
685 | if (str->state == SSTATE_SYNC) | ||
686 | { | ||
687 | /* Scanning for start code */ | ||
688 | if (!CMP_3_CONST(p, PACKET_START_CODE_PREFIX)) | ||
689 | { | ||
690 | INC_BUF(1); | ||
691 | continue; | ||
692 | } | ||
693 | } | ||
694 | |||
695 | /* Found a start code - enter parse state */ | ||
696 | str->state = SSTATE_PARSE; | ||
697 | |||
698 | /* Pack header, skip it */ | ||
699 | if (CMP_4_CONST(p, PACK_START_CODE)) | ||
700 | { | ||
701 | /* Max lookahead: 14 */ | ||
702 | if ((p[4] & 0xc0) == 0x40) /* mpeg-2 */ | ||
703 | { | ||
704 | /* Max delta: 14 + 7 = 21 */ | ||
705 | /* Skip pack header and any stuffing bytes*/ | ||
706 | bytes = 14 + (p[13] & 7); | ||
707 | } | ||
708 | else if ((p[4] & 0xf0) == 0x20) /* mpeg-1 */ | ||
709 | { | ||
710 | bytes = 12; | ||
711 | } | ||
712 | else /* unknown - skip it */ | ||
713 | { | ||
714 | DEBUGF("weird pack header!\n"); | ||
715 | bytes = 5; | ||
716 | } | ||
717 | |||
718 | INC_BUF(bytes); | ||
719 | } | ||
720 | |||
721 | /* System header, parse and skip it - 6 bytes + size */ | ||
722 | if (CMP_4_CONST(p, SYSTEM_HEADER_START_CODE)) | ||
723 | { | ||
724 | /* Skip start code */ | ||
725 | /* Max Delta = 65535 + 6 = 65541 */ | ||
726 | bytes = 6 + ((p[4] << 8) | p[5]); | ||
727 | INC_BUF(bytes); | ||
728 | } | ||
729 | |||
730 | /* Packet header, parse it */ | ||
731 | if (!CMP_3_CONST(p, PACKET_START_CODE_PREFIX)) | ||
732 | { | ||
733 | /* Problem? Meh...probably not but just a corrupted section. | ||
734 | * Try to resync the parser which will probably succeed. */ | ||
735 | DEBUGF("packet start code prefix not found: 0x%02x\n" | ||
736 | " wl:%lu wr:%lu\n" | ||
737 | " p:%p cp:%p cpe:%p\n" | ||
738 | " dbs:%p dbe:%p dbt:%p\n", | ||
739 | str->id, str->hdr.win_left, str->hdr.win_right, | ||
740 | p, str->curr_packet, str->curr_packet_end, | ||
741 | disk_buf.start, disk_buf.end, disk_buf.tail); | ||
742 | str->state = SSTATE_SYNC; | ||
743 | INC_BUF(1); /* Next byte - this one's no good */ | ||
744 | continue; | ||
745 | } | ||
746 | |||
747 | /* We retrieve basic infos */ | ||
748 | /* Maximum packet length: 6 + 65535 = 65541 */ | ||
749 | id = p[3]; | ||
750 | length = ((p[4] << 8) | p[5]) + 6; | ||
751 | |||
752 | if (id != str->id) | ||
753 | { | ||
754 | switch (id) | ||
755 | { | ||
756 | case MPEG_STREAM_PROGRAM_END: | ||
757 | /* end of stream */ | ||
758 | str_end_of_stream(str); | ||
759 | DEBUGF("MPEG program end: 0x%02x\n", str->id); | ||
760 | return STREAM_DATA_END; | ||
761 | case MPEG_STREAM_PACK_HEADER: | ||
762 | case MPEG_STREAM_SYSTEM_HEADER: | ||
763 | /* These shouldn't be here - no increment or resync | ||
764 | * since we'll pick it up above. */ | ||
765 | continue; | ||
766 | default: | ||
767 | /* It's not the packet we're looking for, skip it */ | ||
768 | INC_BUF(length); | ||
769 | continue; | ||
770 | } | ||
771 | } | ||
772 | |||
773 | /* Ok, it's our packet */ | ||
774 | header = p; | ||
775 | |||
776 | if ((header[6] & 0xc0) == 0x80) /* mpeg2 */ | ||
777 | { | ||
778 | /* Max Lookahead: 18 */ | ||
779 | /* Min length: 9 */ | ||
780 | /* Max length: 9 + 255 = 264 */ | ||
781 | length = 9 + header[8]; | ||
782 | |||
783 | /* header points to the mpeg2 pes header */ | ||
784 | if ((header[7] & 0x80) != 0) | ||
785 | { | ||
786 | /* header has a pts */ | ||
787 | uint32_t pts = read_pts(header, 9); | ||
788 | |||
789 | if (pts != INVALID_TIMESTAMP) | ||
790 | { | ||
791 | str->pts = pts; | ||
792 | #if 0 | ||
793 | /* DTS isn't used for anything since things just get | ||
794 | decoded ASAP but keep the code around */ | ||
795 | if (STREAM_IS_VIDEO(id)) | ||
796 | { | ||
797 | /* Video stream - header may have a dts as well */ | ||
798 | str->dts = pts; | ||
799 | |||
800 | if (header[7] & 0x40) != 0x00) | ||
801 | { | ||
802 | pts = read_pts(header, 14); | ||
803 | if (pts != INVALID_TIMESTAMP) | ||
804 | str->dts = pts; | ||
805 | } | ||
806 | } | ||
807 | #endif | ||
808 | str->pkt_flags |= PKT_HAS_TS; | ||
809 | } | ||
810 | } | ||
811 | } | ||
812 | else /* mpeg1 */ | ||
813 | { | ||
814 | /* Max lookahead: 24 + 2 + 9 = 35 */ | ||
815 | /* Max len_skip: 24 + 2 = 26 */ | ||
816 | /* Min length: 7 */ | ||
817 | /* Max length: 24 + 2 + 9 = 35 */ | ||
818 | off_t len_skip; | ||
819 | uint8_t * ptsbuf; | ||
820 | |||
821 | length = 7; | ||
822 | |||
823 | while (header[length - 1] == 0xff) | ||
824 | { | ||
825 | if (++length > 23) | ||
826 | { | ||
827 | DEBUGF("Too much stuffing" ); | ||
828 | break; | ||
829 | } | ||
830 | } | ||
831 | |||
832 | if ((header[length - 1] & 0xc0) == 0x40) | ||
833 | length += 2; | ||
834 | |||
835 | len_skip = length; | ||
836 | length += mpeg1_skip_table[header[length - 1] >> 4]; | ||
837 | |||
838 | /* Header points to the mpeg1 pes header */ | ||
839 | ptsbuf = header + len_skip; | ||
840 | |||
841 | if ((ptsbuf[-1] & 0xe0) == 0x20 && TS_CHECK_MARKERS(ptsbuf, -1)) | ||
842 | { | ||
843 | /* header has a pts */ | ||
844 | uint32_t pts = read_pts(ptsbuf, -1); | ||
845 | |||
846 | if (pts != INVALID_TIMESTAMP) | ||
847 | { | ||
848 | str->pts = pts; | ||
849 | #if 0 | ||
850 | /* DTS isn't used for anything since things just get | ||
851 | decoded ASAP but keep the code around */ | ||
852 | if (STREAM_IS_VIDEO(id)) | ||
853 | { | ||
854 | /* Video stream - header may have a dts as well */ | ||
855 | str->dts = pts; | ||
856 | |||
857 | if (ptsbuf[-1] & 0xf0) == 0x30) | ||
858 | { | ||
859 | pts = read_pts(ptsbuf, 4); | ||
860 | |||
861 | if (pts != INVALID_TIMESTAMP) | ||
862 | str->dts = pts; | ||
863 | } | ||
864 | } | ||
865 | #endif | ||
866 | str->pkt_flags |= PKT_HAS_TS; | ||
867 | } | ||
868 | } | ||
869 | } | ||
870 | |||
871 | p += length; | ||
872 | /* Max bytes: 6 + 65535 - 7 = 65534 */ | ||
873 | bytes = 6 + (header[4] << 8) + header[5] - length; | ||
874 | |||
875 | str->curr_packet = p; | ||
876 | str->curr_packet_end = p + bytes; | ||
877 | str->hdr.win_left = str->hdr.win_right + length; | ||
878 | str->hdr.win_right = str->hdr.win_left + bytes; | ||
879 | |||
880 | if (str->hdr.win_right > disk_buf.filesize) | ||
881 | { | ||
882 | /* No packet that exceeds end of file can be valid */ | ||
883 | str_end_of_stream(str); | ||
884 | return STREAM_DATA_END; | ||
885 | } | ||
886 | |||
887 | return STREAM_OK; | ||
888 | } /* end while */ | ||
889 | |||
890 | #undef INC_BUF | ||
891 | } | ||
892 | |||
893 | /* This simply reads data from the file one page at a time and returns a | ||
894 | * pointer to it in the buffer. */ | ||
895 | static int parse_elementary(struct stream *str, enum stream_parse_mode type) | ||
896 | { | ||
897 | uint8_t *p; | ||
898 | ssize_t len = 0; | ||
899 | |||
900 | str->pkt_flags = 0; | ||
901 | |||
902 | switch (type) | ||
903 | { | ||
904 | case STREAM_PM_STREAMING: | ||
905 | /* Has the end been reached already? */ | ||
906 | if (str->state == SSTATE_END) | ||
907 | return STREAM_DATA_END; | ||
908 | |||
909 | /* Are we at the end of file? */ | ||
910 | if (str->hdr.win_left >= disk_buf.filesize) | ||
911 | { | ||
912 | str_end_of_stream(str); | ||
913 | return STREAM_DATA_END; | ||
914 | } | ||
915 | |||
916 | if (!disk_buf_is_data_ready(&str->hdr, MIN_BUFAHEAD)) | ||
917 | { | ||
918 | /* This data range is not buffered yet - register stream to | ||
919 | * be notified when it becomes available. Stream is obliged | ||
920 | * to enter a TSTATE_DATA state if it must wait. */ | ||
921 | int res = str_next_data_not_ready(str); | ||
922 | |||
923 | if (res != STREAM_OK) | ||
924 | return res; | ||
925 | } | ||
926 | |||
927 | len = DISK_BUF_PAGE_SIZE; | ||
928 | |||
929 | if ((size_t)(str->hdr.win_right + len) > (size_t)disk_buf.filesize) | ||
930 | len = disk_buf.filesize - str->hdr.win_right; | ||
931 | |||
932 | if (len <= 0) | ||
933 | { | ||
934 | str_end_of_stream(str); | ||
935 | return STREAM_DATA_END; | ||
936 | } | ||
937 | |||
938 | p = str->curr_packet_end; | ||
939 | if (p >= disk_buf.end) | ||
940 | p -= disk_buf.size; | ||
941 | break; | ||
942 | /* STREAM_PM_STREAMING: */ | ||
943 | |||
944 | case STREAM_PM_RANDOM_ACCESS: | ||
945 | str->hdr.pos = disk_buf_lseek(str->hdr.pos, SEEK_SET); | ||
946 | len = disk_buf_getbuffer(DISK_BUF_PAGE_SIZE, &p, NULL, NULL); | ||
947 | |||
948 | if (len <= 0 || str->hdr.pos < 0 || str->hdr.pos >= str->hdr.limit) | ||
949 | { | ||
950 | str_end_of_stream(str); | ||
951 | return STREAM_DATA_END; | ||
952 | } | ||
953 | break; | ||
954 | /* STREAM_PM_RANDOM_ACCESS: */ | ||
955 | } | ||
956 | |||
957 | str->state = SSTATE_PARSE; | ||
958 | str->curr_packet = p; | ||
959 | str->curr_packet_end = p + len; | ||
960 | str->hdr.win_left = str->hdr.win_right; | ||
961 | str->hdr.win_right = str->hdr.win_left + len; | ||
962 | |||
963 | return STREAM_OK; | ||
964 | } | ||
965 | |||
966 | bool parser_prepare_image(uint32_t time) | ||
967 | { | ||
968 | struct stream_scan sk; | ||
969 | int tries; | ||
970 | int result; | ||
971 | |||
972 | stream_scan_init(&sk); | ||
973 | |||
974 | if (!str_send_msg(&video_str, STREAM_NEEDS_SYNC, time)) | ||
975 | { | ||
976 | DEBUGF("Image was ready\n"); | ||
977 | return true; /* Should already have the image */ | ||
978 | } | ||
979 | |||
980 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
981 | rb->cpu_boost(true); /* No interference with trigger_cpu_boost */ | ||
982 | #endif | ||
983 | |||
984 | str_send_msg(&video_str, STREAM_RESET, 0); | ||
985 | |||
986 | sk.pos = parser_can_seek() ? | ||
987 | mpeg_parser_seek_PTS(time, video_str.id) : 0; | ||
988 | sk.len = sk.pos; | ||
989 | sk.dir = SSCAN_REVERSE; | ||
990 | |||
991 | tries = 1; | ||
992 | try_again: | ||
993 | |||
994 | if (mpeg_parser_scan_start_code(&sk, MPEG_START_GOP)) | ||
995 | { | ||
996 | DEBUGF("GOP found at: %ld\n", sk.pos); | ||
997 | |||
998 | unsigned id = mpeg_parser_scan_pes(&sk); | ||
999 | |||
1000 | if (id != video_str.id && sk.pos > 0) | ||
1001 | { | ||
1002 | /* Not part of our stream */ | ||
1003 | DEBUGF(" wrong stream: 0x%02x\n", id); | ||
1004 | goto try_again; | ||
1005 | } | ||
1006 | |||
1007 | /* This will hit the PES header since it's known to be there */ | ||
1008 | uint32_t pts = mpeg_parser_scan_pts(&sk, id); | ||
1009 | |||
1010 | if (pts == INVALID_TIMESTAMP || pts > time) | ||
1011 | { | ||
1012 | DEBUGF(" wrong timestamp: %u\n", (unsigned)pts); | ||
1013 | goto try_again; | ||
1014 | } | ||
1015 | } | ||
1016 | |||
1017 | str_parser.parms.sd.time = time; | ||
1018 | str_parser.parms.sd.sk.pos = MAX(sk.pos, 0); | ||
1019 | str_parser.parms.sd.sk.len = 1024*1024; | ||
1020 | str_parser.parms.sd.sk.dir = SSCAN_FORWARD; | ||
1021 | |||
1022 | DEBUGF("thumb pos:%ld len:%ld\n", str_parser.parms.sd.sk.pos, | ||
1023 | (long)str_parser.parms.sd.sk.len); | ||
1024 | |||
1025 | result = str_send_msg(&video_str, STREAM_SYNC, | ||
1026 | (intptr_t)&str_parser.parms.sd); | ||
1027 | |||
1028 | if (result != STREAM_PERFECT_MATCH) | ||
1029 | { | ||
1030 | /* Two tries should be all that is nescessary to find the exact frame | ||
1031 | * if the first GOP actually started later than the timestamp - the | ||
1032 | * GOP just prior must then start on or earlier. */ | ||
1033 | if (++tries <= 2) | ||
1034 | goto try_again; | ||
1035 | } | ||
1036 | |||
1037 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
1038 | rb->cpu_boost(false); | ||
1039 | #endif | ||
1040 | |||
1041 | return result > STREAM_OK; | ||
1042 | } | ||
1043 | |||
1044 | /* Seek parser to the specified time and return absolute time. | ||
1045 | * No actual hard stuff is performed here. That's done when streaming is | ||
1046 | * about to begin or something from the current position is requested */ | ||
1047 | uint32_t parser_seek_time(uint32_t time) | ||
1048 | { | ||
1049 | if (!parser_can_seek()) | ||
1050 | time = 0; | ||
1051 | else if (time > str_parser.duration) | ||
1052 | time = str_parser.duration; | ||
1053 | |||
1054 | str_parser.last_seek_time = time + str_parser.start_pts; | ||
1055 | return str_parser.last_seek_time; | ||
1056 | } | ||
1057 | |||
1058 | void parser_prepare_streaming(void) | ||
1059 | { | ||
1060 | struct stream_window sw; | ||
1061 | |||
1062 | DEBUGF("parser_prepare_streaming\n"); | ||
1063 | |||
1064 | /* Prepare initial video frame */ | ||
1065 | parser_prepare_image(str_parser.last_seek_time); | ||
1066 | |||
1067 | /* Sync audio stream */ | ||
1068 | if (audio_str.start_pts != INVALID_TIMESTAMP) | ||
1069 | prepare_audio(str_parser.last_seek_time); | ||
1070 | |||
1071 | /* Prequeue some data and set buffer window */ | ||
1072 | if (!stream_get_window(&sw)) | ||
1073 | sw.left = sw.right = disk_buf.filesize; | ||
1074 | |||
1075 | DEBUGF(" swl:%ld swr:%ld\n", sw.left, sw.right); | ||
1076 | |||
1077 | if (sw.right > disk_buf.filesize - 4*MIN_BUFAHEAD) | ||
1078 | sw.right = disk_buf.filesize - 4*MIN_BUFAHEAD; | ||
1079 | |||
1080 | disk_buf_prepare_streaming(sw.left, | ||
1081 | sw.right - sw.left + 4*MIN_BUFAHEAD); | ||
1082 | } | ||
1083 | |||
1084 | int parser_init_stream(void) | ||
1085 | { | ||
1086 | if (disk_buf.in_file < 0) | ||
1087 | return STREAM_ERROR; | ||
1088 | |||
1089 | /* TODO: Actually find which streams are available */ | ||
1090 | audio_str.id = MPEG_STREAM_AUDIO_FIRST; | ||
1091 | video_str.id = MPEG_STREAM_VIDEO_FIRST; | ||
1092 | |||
1093 | /* Try to pull a video PES - if not found, try video init anyway which | ||
1094 | * should succeed if it really is a video-only stream */ | ||
1095 | video_str.hdr.pos = 0; | ||
1096 | video_str.hdr.limit = 256*1024; | ||
1097 | |||
1098 | if (parse_demux(&video_str, STREAM_PM_RANDOM_ACCESS) == STREAM_OK) | ||
1099 | { | ||
1100 | /* Found a video packet - assume program stream */ | ||
1101 | str_parser.format = STREAM_FMT_MPEG_PS; | ||
1102 | str_parser.next_data = parse_demux; | ||
1103 | } | ||
1104 | else | ||
1105 | { | ||
1106 | /* No PES element found - assume video elementary stream */ | ||
1107 | str_parser.format = STREAM_FMT_MPV; | ||
1108 | str_parser.next_data = parse_elementary; | ||
1109 | } | ||
1110 | |||
1111 | if (!init_video_info()) | ||
1112 | { | ||
1113 | /* Cannot determine video size, etc. */ | ||
1114 | parser_init_state(); | ||
1115 | return STREAM_UNSUPPORTED; | ||
1116 | } | ||
1117 | |||
1118 | if (str_parser.format == STREAM_FMT_MPEG_PS) | ||
1119 | { | ||
1120 | /* Initalize start_pts and end_pts with the length (in 45kHz units) of | ||
1121 | * the movie. INVALID_TIMESTAMP if the time could not be determined */ | ||
1122 | if (!init_times(&video_str) || !check_times(&video_str)) | ||
1123 | { | ||
1124 | /* Must have video at least */ | ||
1125 | parser_init_state(); | ||
1126 | return STREAM_UNSUPPORTED; | ||
1127 | } | ||
1128 | |||
1129 | str_parser.flags |= STREAMF_CAN_SEEK; | ||
1130 | |||
1131 | if (init_times(&audio_str)) | ||
1132 | { | ||
1133 | /* Audio will be part of playback pool */ | ||
1134 | stream_add_stream(&audio_str); | ||
1135 | |||
1136 | if (check_times(&audio_str)) | ||
1137 | { | ||
1138 | /* Overall duration is maximum span */ | ||
1139 | str_parser.start_pts = MIN(audio_str.start_pts, video_str.start_pts); | ||
1140 | str_parser.end_pts = MAX(audio_str.end_pts, video_str.end_pts); | ||
1141 | } | ||
1142 | else | ||
1143 | { | ||
1144 | /* Bad times on audio - use video times */ | ||
1145 | str_parser.start_pts = video_str.start_pts; | ||
1146 | str_parser.end_pts = video_str.end_pts; | ||
1147 | |||
1148 | /* Questionable: could use bitrate seek and match video to that */ | ||
1149 | audio_str.start_pts = video_str.start_pts; | ||
1150 | audio_str.end_pts = video_str.end_pts; | ||
1151 | } | ||
1152 | } | ||
1153 | else | ||
1154 | { | ||
1155 | /* No audio stream - use video only */ | ||
1156 | str_parser.start_pts = video_str.start_pts; | ||
1157 | str_parser.end_pts = video_str.end_pts; | ||
1158 | } | ||
1159 | |||
1160 | str_parser.last_seek_time = str_parser.start_pts; | ||
1161 | } | ||
1162 | else | ||
1163 | { | ||
1164 | /* There's no way to handle times on this without a full file | ||
1165 | * scan */ | ||
1166 | audio_str.start_pts = INVALID_TIMESTAMP; | ||
1167 | audio_str.end_pts = INVALID_TIMESTAMP; | ||
1168 | video_str.start_pts = 0; | ||
1169 | video_str.end_pts = INVALID_TIMESTAMP; | ||
1170 | str_parser.start_pts = 0; | ||
1171 | str_parser.end_pts = INVALID_TIMESTAMP; | ||
1172 | } | ||
1173 | |||
1174 | /* Add video to playback pool */ | ||
1175 | stream_add_stream(&video_str); | ||
1176 | |||
1177 | /* Cache duration - it's used very often */ | ||
1178 | str_parser.duration = str_parser.end_pts - str_parser.start_pts; | ||
1179 | |||
1180 | DEBUGF("Movie info:\n" | ||
1181 | " size:%dx%d\n" | ||
1182 | " start:%u\n" | ||
1183 | " end:%u\n" | ||
1184 | " duration:%u\n", | ||
1185 | str_parser.dims.w, str_parser.dims.h, | ||
1186 | (unsigned)str_parser.start_pts, | ||
1187 | (unsigned)str_parser.end_pts, | ||
1188 | (unsigned)str_parser.duration); | ||
1189 | |||
1190 | return STREAM_OK; | ||
1191 | } | ||
1192 | |||
1193 | void parser_close_stream(void) | ||
1194 | { | ||
1195 | stream_remove_streams(); | ||
1196 | parser_init_state(); | ||
1197 | } | ||
1198 | |||
1199 | bool parser_init(void) | ||
1200 | { | ||
1201 | parser_init_state(); | ||
1202 | return true; | ||
1203 | } | ||
diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c deleted file mode 100644 index c904de466d..0000000000 --- a/apps/plugins/mpegplayer/mpeg_settings.c +++ /dev/null | |||
@@ -1,1454 +0,0 @@ | |||
1 | #include "plugin.h" | ||
2 | #include "lib/helper.h" | ||
3 | #include "lib/configfile.h" | ||
4 | |||
5 | #include "mpegplayer.h" | ||
6 | #include "mpeg_settings.h" | ||
7 | |||
8 | struct mpeg_settings settings; | ||
9 | |||
10 | #define THUMB_DELAY (75*HZ/100) | ||
11 | |||
12 | /* button definitions */ | ||
13 | #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ | ||
14 | (CONFIG_KEYPAD == IRIVER_H300_PAD) | ||
15 | #define MPEG_START_TIME_SELECT BUTTON_ON | ||
16 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
17 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
18 | #define MPEG_START_TIME_UP BUTTON_UP | ||
19 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
20 | #define MPEG_START_TIME_EXIT BUTTON_OFF | ||
21 | |||
22 | #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) | ||
23 | #define MPEG_START_TIME_SELECT BUTTON_PLAY | ||
24 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
25 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
26 | #define MPEG_START_TIME_UP BUTTON_UP | ||
27 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
28 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
29 | |||
30 | #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ | ||
31 | (CONFIG_KEYPAD == IPOD_3G_PAD) || \ | ||
32 | (CONFIG_KEYPAD == IPOD_1G2G_PAD) | ||
33 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
34 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
35 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
36 | #define MPEG_START_TIME_UP BUTTON_SCROLL_FWD | ||
37 | #define MPEG_START_TIME_DOWN BUTTON_SCROLL_BACK | ||
38 | #define MPEG_START_TIME_EXIT BUTTON_MENU | ||
39 | |||
40 | #elif CONFIG_KEYPAD == GIGABEAT_PAD | ||
41 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
42 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
43 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
44 | #define MPEG_START_TIME_UP BUTTON_UP | ||
45 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
46 | #define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP | ||
47 | #define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN | ||
48 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
49 | |||
50 | #define MPEG_START_TIME_RC_SELECT (BUTTON_RC_PLAY | BUTTON_REL) | ||
51 | #define MPEG_START_TIME_RC_LEFT BUTTON_RC_REW | ||
52 | #define MPEG_START_TIME_RC_RIGHT BUTTON_RC_FF | ||
53 | #define MPEG_START_TIME_RC_UP BUTTON_RC_VOL_UP | ||
54 | #define MPEG_START_TIME_RC_DOWN BUTTON_RC_VOL_DOWN | ||
55 | #define MPEG_START_TIME_RC_EXIT (BUTTON_RC_PLAY | BUTTON_REPEAT) | ||
56 | |||
57 | #elif CONFIG_KEYPAD == GIGABEAT_S_PAD | ||
58 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
59 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
60 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
61 | #define MPEG_START_TIME_UP BUTTON_UP | ||
62 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
63 | #define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP | ||
64 | #define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN | ||
65 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
66 | |||
67 | #define MPEG_START_TIME_RC_SELECT (BUTTON_RC_PLAY | BUTTON_REL) | ||
68 | #define MPEG_START_TIME_RC_LEFT BUTTON_RC_REW | ||
69 | #define MPEG_START_TIME_RC_RIGHT BUTTON_RC_FF | ||
70 | #define MPEG_START_TIME_RC_UP BUTTON_RC_VOL_UP | ||
71 | #define MPEG_START_TIME_RC_DOWN BUTTON_RC_VOL_DOWN | ||
72 | #define MPEG_START_TIME_RC_EXIT (BUTTON_RC_PLAY | BUTTON_REPEAT) | ||
73 | |||
74 | #elif CONFIG_KEYPAD == IRIVER_H10_PAD | ||
75 | #define MPEG_START_TIME_SELECT BUTTON_PLAY | ||
76 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
77 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
78 | #define MPEG_START_TIME_UP BUTTON_SCROLL_UP | ||
79 | #define MPEG_START_TIME_DOWN BUTTON_SCROLL_DOWN | ||
80 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
81 | |||
82 | #elif (CONFIG_KEYPAD == SANSA_E200_PAD) | ||
83 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
84 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
85 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
86 | #define MPEG_START_TIME_UP BUTTON_UP | ||
87 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
88 | #define MPEG_START_TIME_LEFT2 BUTTON_SCROLL_BACK | ||
89 | #define MPEG_START_TIME_RIGHT2 BUTTON_SCROLL_FWD | ||
90 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
91 | |||
92 | #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD) | ||
93 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
94 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
95 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
96 | #define MPEG_START_TIME_UP BUTTON_UP | ||
97 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
98 | #define MPEG_START_TIME_LEFT2 BUTTON_SCROLL_BACK | ||
99 | #define MPEG_START_TIME_RIGHT2 BUTTON_SCROLL_FWD | ||
100 | #define MPEG_START_TIME_EXIT (BUTTON_HOME|BUTTON_REPEAT) | ||
101 | |||
102 | #elif (CONFIG_KEYPAD == SANSA_C200_PAD) || \ | ||
103 | (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \ | ||
104 | (CONFIG_KEYPAD == SANSA_M200_PAD) | ||
105 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
106 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
107 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
108 | #define MPEG_START_TIME_UP BUTTON_UP | ||
109 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
110 | #define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP | ||
111 | #define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN | ||
112 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
113 | |||
114 | #elif CONFIG_KEYPAD == MROBE500_PAD | ||
115 | #define MPEG_START_TIME_SELECT BUTTON_RC_HEART | ||
116 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
117 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
118 | #define MPEG_START_TIME_UP BUTTON_RC_PLAY | ||
119 | #define MPEG_START_TIME_DOWN BUTTON_RC_DOWN | ||
120 | #define MPEG_START_TIME_LEFT2 BUTTON_RC_VOL_UP | ||
121 | #define MPEG_START_TIME_RIGHT2 BUTTON_RC_VOL_DOWN | ||
122 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
123 | |||
124 | #elif CONFIG_KEYPAD == MROBE100_PAD | ||
125 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
126 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
127 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
128 | #define MPEG_START_TIME_UP BUTTON_UP | ||
129 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
130 | #define MPEG_START_TIME_LEFT2 BUTTON_PLAY | ||
131 | #define MPEG_START_TIME_RIGHT2 BUTTON_MENU | ||
132 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
133 | |||
134 | #elif CONFIG_KEYPAD == IAUDIO_M3_PAD | ||
135 | #define MPEG_START_TIME_SELECT BUTTON_RC_PLAY | ||
136 | #define MPEG_START_TIME_LEFT BUTTON_RC_REW | ||
137 | #define MPEG_START_TIME_RIGHT BUTTON_RC_FF | ||
138 | #define MPEG_START_TIME_UP BUTTON_RC_VOL_UP | ||
139 | #define MPEG_START_TIME_DOWN BUTTON_RC_VOL_DOWN | ||
140 | #define MPEG_START_TIME_EXIT BUTTON_RC_REC | ||
141 | |||
142 | #elif CONFIG_KEYPAD == COWON_D2_PAD | ||
143 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
144 | |||
145 | #elif CONFIG_KEYPAD == CREATIVEZVM_PAD | ||
146 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
147 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
148 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
149 | #define MPEG_START_TIME_UP BUTTON_UP | ||
150 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
151 | #define MPEG_START_TIME_LEFT2 BUTTON_PLAY | ||
152 | #define MPEG_START_TIME_RIGHT2 BUTTON_MENU | ||
153 | #define MPEG_START_TIME_EXIT BUTTON_BACK | ||
154 | |||
155 | #elif (CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD) | ||
156 | #define MPEG_START_TIME_SELECT (BUTTON_PLAY|BUTTON_REL) | ||
157 | #define MPEG_START_TIME_LEFT BUTTON_BACK | ||
158 | #define MPEG_START_TIME_RIGHT BUTTON_MENU | ||
159 | #define MPEG_START_TIME_UP BUTTON_UP | ||
160 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
161 | #define MPEG_START_TIME_EXIT (BUTTON_PLAY|BUTTON_REPEAT) | ||
162 | |||
163 | #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD | ||
164 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
165 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
166 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
167 | #define MPEG_START_TIME_UP BUTTON_UP | ||
168 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
169 | #define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP | ||
170 | #define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN | ||
171 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
172 | |||
173 | #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD | ||
174 | #define MPEG_START_TIME_SELECT BUTTON_PLAY | ||
175 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
176 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
177 | #define MPEG_START_TIME_UP BUTTON_UP | ||
178 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
179 | #define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP | ||
180 | #define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN | ||
181 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
182 | |||
183 | #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD | ||
184 | #define MPEG_START_TIME_SELECT BUTTON_PLAY | ||
185 | #define MPEG_START_TIME_LEFT BUTTON_PREV | ||
186 | #define MPEG_START_TIME_RIGHT BUTTON_NEXT | ||
187 | #define MPEG_START_TIME_UP BUTTON_UP | ||
188 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
189 | #define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP | ||
190 | #define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN | ||
191 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
192 | |||
193 | #elif CONFIG_KEYPAD == ONDAVX747_PAD | ||
194 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
195 | |||
196 | #elif CONFIG_KEYPAD == ONDAVX777_PAD | ||
197 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
198 | |||
199 | #elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) || \ | ||
200 | (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD) | ||
201 | #define MPEG_START_TIME_SELECT BUTTON_PLAY | ||
202 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
203 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
204 | #define MPEG_START_TIME_UP BUTTON_UP | ||
205 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
206 | #define MPEG_START_TIME_EXIT BUTTON_REW | ||
207 | |||
208 | #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD | ||
209 | #define MPEG_START_TIME_SELECT BUTTON_PLAY | ||
210 | #define MPEG_START_TIME_LEFT BUTTON_PREV | ||
211 | #define MPEG_START_TIME_RIGHT BUTTON_NEXT | ||
212 | #define MPEG_START_TIME_UP BUTTON_UP | ||
213 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
214 | #define MPEG_START_TIME_LEFT2 BUTTON_OK | ||
215 | #define MPEG_START_TIME_RIGHT2 BUTTON_CANCEL | ||
216 | #define MPEG_START_TIME_EXIT BUTTON_REC | ||
217 | |||
218 | #elif CONFIG_KEYPAD == MPIO_HD200_PAD | ||
219 | #define MPEG_START_TIME_SELECT BUTTON_FUNC | ||
220 | #define MPEG_START_TIME_LEFT BUTTON_REW | ||
221 | #define MPEG_START_TIME_RIGHT BUTTON_FF | ||
222 | #define MPEG_START_TIME_UP BUTTON_VOL_UP | ||
223 | #define MPEG_START_TIME_DOWN BUTTON_VOL_DOWN | ||
224 | #define MPEG_START_TIME_EXIT BUTTON_REC | ||
225 | |||
226 | #elif CONFIG_KEYPAD == MPIO_HD300_PAD | ||
227 | #define MPEG_START_TIME_SELECT BUTTON_ENTER | ||
228 | #define MPEG_START_TIME_LEFT BUTTON_REW | ||
229 | #define MPEG_START_TIME_RIGHT BUTTON_FF | ||
230 | #define MPEG_START_TIME_UP BUTTON_UP | ||
231 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
232 | #define MPEG_START_TIME_EXIT BUTTON_REC | ||
233 | |||
234 | #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD | ||
235 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
236 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
237 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
238 | #define MPEG_START_TIME_UP BUTTON_UP | ||
239 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
240 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
241 | |||
242 | #elif CONFIG_KEYPAD == SANSA_CONNECT_PAD | ||
243 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
244 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
245 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
246 | #define MPEG_START_TIME_UP BUTTON_UP | ||
247 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
248 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
249 | |||
250 | #elif CONFIG_KEYPAD == SAMSUNG_YPR0_PAD | ||
251 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
252 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
253 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
254 | #define MPEG_START_TIME_UP BUTTON_UP | ||
255 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
256 | #define MPEG_START_TIME_EXIT BUTTON_BACK | ||
257 | |||
258 | #elif (CONFIG_KEYPAD == HM60X_PAD) || (CONFIG_KEYPAD == HM801_PAD) | ||
259 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
260 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
261 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
262 | #define MPEG_START_TIME_UP BUTTON_UP | ||
263 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
264 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
265 | |||
266 | #elif CONFIG_KEYPAD == SONY_NWZ_PAD | ||
267 | #define MPEG_START_TIME_SELECT BUTTON_PLAY | ||
268 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
269 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
270 | #define MPEG_START_TIME_UP BUTTON_UP | ||
271 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
272 | #define MPEG_START_TIME_EXIT BUTTON_BACK | ||
273 | |||
274 | #elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD | ||
275 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
276 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
277 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
278 | #define MPEG_START_TIME_UP BUTTON_UP | ||
279 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
280 | #define MPEG_START_TIME_EXIT BUTTON_BACK | ||
281 | |||
282 | #elif CONFIG_KEYPAD == DX50_PAD | ||
283 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
284 | #define MPEG_START_TIME_SELECT BUTTON_PLAY | ||
285 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
286 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
287 | #define MPEG_START_TIME_UP BUTTON_VOL_UP | ||
288 | #define MPEG_START_TIME_DOWN BUTTON_VOL_DOWN | ||
289 | |||
290 | #elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD | ||
291 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
292 | |||
293 | #elif CONFIG_KEYPAD == AGPTEK_ROCKER_PAD | ||
294 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
295 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
296 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
297 | #define MPEG_START_TIME_UP BUTTON_UP | ||
298 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
299 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
300 | |||
301 | #elif CONFIG_KEYPAD == XDUOO_X3_PAD | ||
302 | #define MPEG_START_TIME_SELECT BUTTON_PLAY | ||
303 | #define MPEG_START_TIME_LEFT BUTTON_PREV | ||
304 | #define MPEG_START_TIME_RIGHT BUTTON_NEXT | ||
305 | #define MPEG_START_TIME_UP BUTTON_HOME | ||
306 | #define MPEG_START_TIME_DOWN BUTTON_OPTION | ||
307 | #define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP | ||
308 | #define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN | ||
309 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
310 | |||
311 | #elif CONFIG_KEYPAD == XDUOO_X3II_PAD || CONFIG_KEYPAD == XDUOO_X20_PAD | ||
312 | #define MPEG_START_TIME_SELECT BUTTON_PLAY | ||
313 | #define MPEG_START_TIME_LEFT BUTTON_PREV | ||
314 | #define MPEG_START_TIME_RIGHT BUTTON_NEXT | ||
315 | #define MPEG_START_TIME_UP BUTTON_HOME | ||
316 | #define MPEG_START_TIME_DOWN BUTTON_OPTION | ||
317 | #define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP | ||
318 | #define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN | ||
319 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
320 | |||
321 | #elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD | ||
322 | #define MPEG_START_TIME_SELECT BUTTON_PLAY | ||
323 | #define MPEG_START_TIME_LEFT BUTTON_PREV | ||
324 | #define MPEG_START_TIME_RIGHT BUTTON_NEXT | ||
325 | #define MPEG_START_TIME_UP BUTTON_HOME | ||
326 | #define MPEG_START_TIME_DOWN BUTTON_OPTION | ||
327 | #define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP | ||
328 | #define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN | ||
329 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
330 | |||
331 | #elif CONFIG_KEYPAD == IHIFI_770_PAD || CONFIG_KEYPAD == IHIFI_800_PAD | ||
332 | #define MPEG_START_TIME_SELECT BUTTON_PLAY | ||
333 | #define MPEG_START_TIME_LEFT BUTTON_HOME | ||
334 | #define MPEG_START_TIME_RIGHT BUTTON_VOL_DOWN | ||
335 | #define MPEG_START_TIME_UP BUTTON_PREV | ||
336 | #define MPEG_START_TIME_DOWN BUTTON_NEXT | ||
337 | #define MPEG_START_TIME_LEFT2 (BUTTON_POWER + BUTTON_HOME) | ||
338 | #define MPEG_START_TIME_RIGHT2 (BUTTON_POWER + BUTTON_VOL_DOWN) | ||
339 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
340 | |||
341 | #elif CONFIG_KEYPAD == EROSQ_PAD | ||
342 | #define MPEG_START_TIME_SELECT BUTTON_PLAY | ||
343 | #define MPEG_START_TIME_LEFT BUTTON_SCROLL_BACK | ||
344 | #define MPEG_START_TIME_RIGHT BUTTON_SCROLL_FWD | ||
345 | #define MPEG_START_TIME_UP BUTTON_PREV | ||
346 | #define MPEG_START_TIME_DOWN BUTTON_NEXT | ||
347 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
348 | |||
349 | #elif CONFIG_KEYPAD == FIIO_M3K_PAD | ||
350 | #define MPEG_START_TIME_SELECT BUTTON_SELECT | ||
351 | #define MPEG_START_TIME_LEFT BUTTON_LEFT | ||
352 | #define MPEG_START_TIME_RIGHT BUTTON_RIGHT | ||
353 | #define MPEG_START_TIME_UP BUTTON_UP | ||
354 | #define MPEG_START_TIME_DOWN BUTTON_DOWN | ||
355 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
356 | |||
357 | #elif CONFIG_KEYPAD == SHANLING_Q1_PAD | ||
358 | #define MPEG_START_TIME_EXIT BUTTON_POWER | ||
359 | |||
360 | #else | ||
361 | #error No keymap defined! | ||
362 | #endif | ||
363 | |||
364 | #ifdef HAVE_TOUCHSCREEN | ||
365 | #ifndef MPEG_START_TIME_SELECT | ||
366 | #define MPEG_START_TIME_SELECT BUTTON_CENTER | ||
367 | #endif | ||
368 | #ifndef MPEG_START_TIME_LEFT | ||
369 | #define MPEG_START_TIME_LEFT BUTTON_MIDLEFT | ||
370 | #endif | ||
371 | #ifndef MPEG_START_TIME_RIGHT | ||
372 | #define MPEG_START_TIME_RIGHT BUTTON_MIDRIGHT | ||
373 | #endif | ||
374 | #ifndef MPEG_START_TIME_UP | ||
375 | #define MPEG_START_TIME_UP BUTTON_TOPMIDDLE | ||
376 | #endif | ||
377 | #ifndef MPEG_START_TIME_DOWN | ||
378 | #define MPEG_START_TIME_DOWN BUTTON_BOTTOMMIDDLE | ||
379 | #endif | ||
380 | #ifndef MPEG_START_TIME_LEFT2 | ||
381 | #define MPEG_START_TIME_LEFT2 BUTTON_TOPRIGHT | ||
382 | #endif | ||
383 | #ifndef MPEG_START_TIME_RIGHT2 | ||
384 | #define MPEG_START_TIME_RIGHT2 BUTTON_TOPLEFT | ||
385 | #endif | ||
386 | #ifndef MPEG_START_TIME_EXIT | ||
387 | #define MPEG_START_TIME_EXIT BUTTON_TOPLEFT | ||
388 | #endif | ||
389 | #endif | ||
390 | |||
391 | static struct configdata config[] = | ||
392 | { | ||
393 | {TYPE_INT, 0, 2, { .int_p = &settings.showfps }, "Show FPS", NULL}, | ||
394 | {TYPE_INT, 0, 2, { .int_p = &settings.limitfps }, "Limit FPS", NULL}, | ||
395 | {TYPE_INT, 0, 2, { .int_p = &settings.skipframes }, "Skip frames", NULL}, | ||
396 | {TYPE_INT, 0, INT_MAX, { .int_p = &settings.resume_count }, "Resume count", | ||
397 | NULL}, | ||
398 | {TYPE_INT, 0, MPEG_RESUME_NUM_OPTIONS, | ||
399 | { .int_p = &settings.resume_options }, "Resume options", NULL}, | ||
400 | #if MPEG_OPTION_DITHERING_ENABLED | ||
401 | {TYPE_INT, 0, INT_MAX, { .int_p = &settings.displayoptions }, | ||
402 | "Display options", NULL}, | ||
403 | #endif | ||
404 | {TYPE_INT, 0, 2, { .int_p = &settings.tone_controls }, "Tone controls", | ||
405 | NULL}, | ||
406 | {TYPE_INT, 0, 2, { .int_p = &settings.channel_modes }, "Channel modes", | ||
407 | NULL}, | ||
408 | {TYPE_INT, 0, 2, { .int_p = &settings.crossfeed }, "Crossfeed", NULL}, | ||
409 | {TYPE_INT, 0, 2, { .int_p = &settings.equalizer }, "Equalizer", NULL}, | ||
410 | {TYPE_INT, 0, 2, { .int_p = &settings.dithering }, "Dithering", NULL}, | ||
411 | {TYPE_INT, 0, 2, { .int_p = &settings.play_mode }, "Play mode", NULL}, | ||
412 | #ifdef HAVE_BACKLIGHT_BRIGHTNESS | ||
413 | {TYPE_INT, -1, INT_MAX, { .int_p = &settings.backlight_brightness }, | ||
414 | "Backlight brightness", NULL}, | ||
415 | #endif | ||
416 | }; | ||
417 | |||
418 | static const struct opt_items noyes[2] = { | ||
419 | { STR(LANG_SET_BOOL_NO) }, | ||
420 | { STR(LANG_SET_BOOL_YES) }, | ||
421 | }; | ||
422 | |||
423 | static const struct opt_items singleall[2] = { | ||
424 | { STR(LANG_SINGLE) }, | ||
425 | { STR(LANG_ALL) }, | ||
426 | }; | ||
427 | |||
428 | static const struct opt_items globaloff[2] = { | ||
429 | { STR(LANG_OFF) }, | ||
430 | { STR(LANG_USE_SOUND_SETTING) }, | ||
431 | }; | ||
432 | |||
433 | static void mpeg_settings(void); | ||
434 | static bool mpeg_set_option(const char* string, | ||
435 | void* variable, | ||
436 | enum optiontype type, | ||
437 | const struct opt_items* options, | ||
438 | int numoptions, | ||
439 | void (*function)(int)) | ||
440 | { | ||
441 | mpeg_sysevent_clear(); | ||
442 | |||
443 | /* This eats SYS_POWEROFF - :\ */ | ||
444 | bool usb = rb->set_option(string, variable, type, options, numoptions, | ||
445 | function); | ||
446 | |||
447 | if (usb) | ||
448 | mpeg_sysevent_set(); | ||
449 | |||
450 | return usb; | ||
451 | } | ||
452 | |||
453 | #ifdef HAVE_BACKLIGHT_BRIGHTNESS /* Only used for this atm */ | ||
454 | static bool mpeg_set_int(const char *string, const char *unit, | ||
455 | int voice_unit, const int *variable, | ||
456 | void (*function)(int), int step, | ||
457 | int min, | ||
458 | int max, | ||
459 | const char* (*formatter)(char*, size_t, int, const char*), | ||
460 | int32_t (*get_talk_id)(int, int)) | ||
461 | { | ||
462 | mpeg_sysevent_clear(); | ||
463 | |||
464 | bool usb = rb->set_int_ex(string, unit, voice_unit, variable, function, | ||
465 | step, min, max, formatter, get_talk_id); | ||
466 | |||
467 | if (usb) | ||
468 | mpeg_sysevent_set(); | ||
469 | |||
470 | return usb; | ||
471 | } | ||
472 | |||
473 | static int32_t backlight_brightness_getlang(int value, int unit) | ||
474 | { | ||
475 | if (value < 0) | ||
476 | return LANG_USE_COMMON_SETTING; | ||
477 | |||
478 | return TALK_ID(value + MIN_BRIGHTNESS_SETTING, unit); | ||
479 | } | ||
480 | |||
481 | void mpeg_backlight_update_brightness(int value) | ||
482 | { | ||
483 | if (value >= 0) | ||
484 | { | ||
485 | value += MIN_BRIGHTNESS_SETTING; | ||
486 | backlight_brightness_set(value); | ||
487 | } | ||
488 | else | ||
489 | { | ||
490 | backlight_brightness_use_setting(); | ||
491 | } | ||
492 | } | ||
493 | |||
494 | static void backlight_brightness_function(int value) | ||
495 | { | ||
496 | mpeg_backlight_update_brightness(value); | ||
497 | } | ||
498 | |||
499 | static const char* backlight_brightness_formatter(char *buf, size_t length, | ||
500 | int value, const char *input) | ||
501 | { | ||
502 | (void)input; | ||
503 | |||
504 | if (value < 0) | ||
505 | return rb->str(LANG_USE_COMMON_SETTING); | ||
506 | else | ||
507 | rb->snprintf(buf, length, "%d", value + MIN_BRIGHTNESS_SETTING); | ||
508 | return buf; | ||
509 | } | ||
510 | #endif /* HAVE_BACKLIGHT_BRIGHTNESS */ | ||
511 | |||
512 | /* Sync a particular audio setting to global or mpegplayer forced off */ | ||
513 | static void sync_audio_setting(int setting, bool global) | ||
514 | { | ||
515 | switch (setting) | ||
516 | { | ||
517 | case MPEG_AUDIO_TONE_CONTROLS: | ||
518 | #ifdef AUDIOHW_HAVE_BASS | ||
519 | rb->sound_set(SOUND_BASS, (global || settings.tone_controls) | ||
520 | ? rb->global_settings->bass | ||
521 | : rb->sound_default(SOUND_BASS)); | ||
522 | #endif | ||
523 | #ifdef AUDIOHW_HAVE_TREBLE | ||
524 | rb->sound_set(SOUND_TREBLE, (global || settings.tone_controls) | ||
525 | ? rb->global_settings->treble | ||
526 | : rb->sound_default(SOUND_TREBLE)); | ||
527 | #endif | ||
528 | |||
529 | #ifdef AUDIOHW_HAVE_EQ | ||
530 | for (int band = 0;; band++) | ||
531 | { | ||
532 | int setting = rb->sound_enum_hw_eq_band_setting(band, AUDIOHW_EQ_GAIN); | ||
533 | |||
534 | if (setting == -1) | ||
535 | break; | ||
536 | |||
537 | rb->sound_set(setting, (global || settings.tone_controls) | ||
538 | ? rb->global_settings->hw_eq_bands[band].gain | ||
539 | : rb->sound_default(setting)); | ||
540 | } | ||
541 | #endif /* AUDIOHW_HAVE_EQ */ | ||
542 | break; | ||
543 | |||
544 | case MPEG_AUDIO_CHANNEL_MODES: | ||
545 | rb->sound_set(SOUND_CHANNELS, (global || settings.channel_modes) | ||
546 | ? rb->global_settings->channel_config | ||
547 | : SOUND_CHAN_STEREO); | ||
548 | break; | ||
549 | |||
550 | case MPEG_AUDIO_CROSSFEED: | ||
551 | rb->dsp_set_crossfeed_type((global || settings.crossfeed) ? | ||
552 | rb->global_settings->crossfeed : | ||
553 | CROSSFEED_TYPE_NONE); | ||
554 | break; | ||
555 | |||
556 | case MPEG_AUDIO_EQUALIZER: | ||
557 | rb->dsp_eq_enable((global || settings.equalizer) ? | ||
558 | rb->global_settings->eq_enabled : false); | ||
559 | break; | ||
560 | |||
561 | case MPEG_AUDIO_DITHERING: | ||
562 | rb->dsp_dither_enable((global || settings.dithering) ? | ||
563 | rb->global_settings->dithering_enabled : false); | ||
564 | break; | ||
565 | } | ||
566 | } | ||
567 | |||
568 | /* Sync all audio settings to global or mpegplayer forced off */ | ||
569 | static void sync_audio_settings(bool global) | ||
570 | { | ||
571 | static const int setting_index[] = | ||
572 | { | ||
573 | MPEG_AUDIO_TONE_CONTROLS, | ||
574 | MPEG_AUDIO_CHANNEL_MODES, | ||
575 | MPEG_AUDIO_CROSSFEED, | ||
576 | MPEG_AUDIO_EQUALIZER, | ||
577 | MPEG_AUDIO_DITHERING, | ||
578 | }; | ||
579 | unsigned i; | ||
580 | |||
581 | for (i = 0; i < ARRAYLEN(setting_index); i++) | ||
582 | { | ||
583 | sync_audio_setting(setting_index[i], global); | ||
584 | } | ||
585 | } | ||
586 | |||
587 | #ifndef HAVE_LCD_COLOR | ||
588 | /* Cheapo splash implementation for the grey surface */ | ||
589 | static void grey_splash(int ticks, const unsigned char *fmt, ...) | ||
590 | { | ||
591 | unsigned char buffer[256]; | ||
592 | int x, y, w, h; | ||
593 | int oldfg, oldmode; | ||
594 | |||
595 | va_list ap; | ||
596 | va_start(ap, fmt); | ||
597 | |||
598 | rb->vsnprintf(buffer, sizeof (buffer), fmt, ap); | ||
599 | |||
600 | va_end(ap); | ||
601 | |||
602 | grey_getstringsize(buffer, &w, &h); | ||
603 | |||
604 | oldfg = grey_get_foreground(); | ||
605 | oldmode = grey_get_drawmode(); | ||
606 | |||
607 | grey_set_drawmode(DRMODE_FG); | ||
608 | grey_set_foreground(GREY_LIGHTGRAY); | ||
609 | |||
610 | x = (LCD_WIDTH - w) / 2; | ||
611 | y = (LCD_HEIGHT - h) / 2; | ||
612 | |||
613 | grey_fillrect(x - 1, y - 1, w + 2, h + 2); | ||
614 | |||
615 | grey_set_foreground(GREY_BLACK); | ||
616 | |||
617 | grey_putsxy(x, y, buffer); | ||
618 | grey_drawrect(x - 2, y - 2, w + 4, h + 4); | ||
619 | |||
620 | grey_set_foreground(oldfg); | ||
621 | grey_set_drawmode(oldmode); | ||
622 | |||
623 | grey_update(); | ||
624 | |||
625 | if (ticks > 0) | ||
626 | rb->sleep(ticks); | ||
627 | } | ||
628 | #endif /* !HAVE_LCD_COLOR */ | ||
629 | |||
630 | static void show_loading(struct vo_rect *rc) | ||
631 | { | ||
632 | int oldmode = mylcd_get_drawmode(); | ||
633 | mylcd_set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID); | ||
634 | mylcd_fillrect(rc->l-1, rc->t-1, rc->r - rc->l + 2, rc->b - rc->t + 2); | ||
635 | mylcd_set_drawmode(oldmode); | ||
636 | mylcd_splash(0, "Loading..."); | ||
637 | } | ||
638 | |||
639 | static void draw_slider(uint32_t range, uint32_t pos, struct vo_rect *rc) | ||
640 | { | ||
641 | #define SLIDER_WIDTH (LCD_WIDTH-SLIDER_LMARGIN-SLIDER_RMARGIN) | ||
642 | #define SLIDER_X SLIDER_LMARGIN | ||
643 | #define SLIDER_Y (LCD_HEIGHT-SLIDER_HEIGHT-SLIDER_BMARGIN) | ||
644 | #define SLIDER_HEIGHT 8 | ||
645 | #define SLIDER_TEXTMARGIN 1 | ||
646 | #define SLIDER_LMARGIN 1 | ||
647 | #define SLIDER_RMARGIN 1 | ||
648 | #define SLIDER_TMARGIN 1 | ||
649 | #define SLIDER_BMARGIN 1 | ||
650 | #define SCREEN_MARGIN 1 | ||
651 | |||
652 | struct hms hms; | ||
653 | char str[32]; | ||
654 | int text_w, text_h, text_y; | ||
655 | |||
656 | /* Put positition on left */ | ||
657 | ts_to_hms(pos, &hms); | ||
658 | hms_format(str, sizeof(str), &hms); | ||
659 | mylcd_getstringsize(str, NULL, &text_h); | ||
660 | text_y = SLIDER_Y - SLIDER_TEXTMARGIN - text_h; | ||
661 | |||
662 | if (rc == NULL) | ||
663 | { | ||
664 | int oldmode = mylcd_get_drawmode(); | ||
665 | mylcd_set_drawmode(DRMODE_BG | DRMODE_INVERSEVID); | ||
666 | mylcd_fillrect(SLIDER_X, text_y, SLIDER_WIDTH, | ||
667 | LCD_HEIGHT - SLIDER_BMARGIN - text_y | ||
668 | - SLIDER_TMARGIN); | ||
669 | mylcd_set_drawmode(oldmode); | ||
670 | |||
671 | mylcd_putsxy(SLIDER_X, text_y, str); | ||
672 | |||
673 | /* Put duration on right */ | ||
674 | ts_to_hms(range, &hms); | ||
675 | hms_format(str, sizeof(str), &hms); | ||
676 | mylcd_getstringsize(str, &text_w, NULL); | ||
677 | |||
678 | mylcd_putsxy(SLIDER_X + SLIDER_WIDTH - text_w, text_y, str); | ||
679 | |||
680 | /* Draw slider */ | ||
681 | mylcd_drawrect(SLIDER_X, SLIDER_Y, SLIDER_WIDTH, SLIDER_HEIGHT); | ||
682 | mylcd_fillrect(SLIDER_X, SLIDER_Y, | ||
683 | muldiv_uint32(pos, SLIDER_WIDTH, range), | ||
684 | SLIDER_HEIGHT); | ||
685 | |||
686 | /* Update screen */ | ||
687 | mylcd_update_rect(SLIDER_X, text_y - SLIDER_TMARGIN, SLIDER_WIDTH, | ||
688 | LCD_HEIGHT - SLIDER_BMARGIN - text_y + SLIDER_TEXTMARGIN); | ||
689 | } | ||
690 | else | ||
691 | { | ||
692 | /* Just return slider rectangle */ | ||
693 | rc->l = SLIDER_X; | ||
694 | rc->t = text_y - SLIDER_TMARGIN; | ||
695 | rc->r = rc->l + SLIDER_WIDTH; | ||
696 | rc->b = rc->t + LCD_HEIGHT - SLIDER_BMARGIN - text_y; | ||
697 | } | ||
698 | } | ||
699 | |||
700 | static bool display_thumb_image(const struct vo_rect *rc) | ||
701 | { | ||
702 | bool retval = true; | ||
703 | unsigned ltgray = MYLCD_LIGHTGRAY; | ||
704 | unsigned dkgray = MYLCD_DARKGRAY; | ||
705 | |||
706 | int oldcolor = mylcd_get_foreground(); | ||
707 | |||
708 | if (!stream_display_thumb(rc)) | ||
709 | { | ||
710 | /* Display "No Frame" and erase any border */ | ||
711 | const char * const str = "No Frame"; | ||
712 | int x, y, w, h; | ||
713 | |||
714 | mylcd_getstringsize(str, &w, &h); | ||
715 | x = (rc->r + rc->l - w) / 2; | ||
716 | y = (rc->b + rc->t - h) / 2; | ||
717 | mylcd_putsxy(x, y, str); | ||
718 | |||
719 | mylcd_update_rect(x, y, w, h); | ||
720 | |||
721 | ltgray = dkgray = mylcd_get_background(); | ||
722 | retval = false; | ||
723 | } | ||
724 | |||
725 | /* Draw a raised border around the frame (or erase if no frame) */ | ||
726 | |||
727 | mylcd_set_foreground(ltgray); | ||
728 | |||
729 | mylcd_hline(rc->l-1, rc->r-1, rc->t-1); | ||
730 | mylcd_vline(rc->l-1, rc->t, rc->b-1); | ||
731 | |||
732 | mylcd_set_foreground(dkgray); | ||
733 | |||
734 | mylcd_hline(rc->l-1, rc->r, rc->b); | ||
735 | mylcd_vline(rc->r, rc->t-1, rc->b); | ||
736 | |||
737 | mylcd_set_foreground(oldcolor); | ||
738 | |||
739 | mylcd_update_rect(rc->l-1, rc->t-1, rc->r - rc->l + 2, 1); | ||
740 | mylcd_update_rect(rc->l-1, rc->t, 1, rc->b - rc->t); | ||
741 | mylcd_update_rect(rc->l-1, rc->b, rc->r - rc->l + 2, 1); | ||
742 | mylcd_update_rect(rc->r, rc->t, 1, rc->b - rc->t); | ||
743 | |||
744 | return retval; | ||
745 | } | ||
746 | |||
747 | /* Add an amount to the specified time - with saturation */ | ||
748 | static uint32_t increment_time(uint32_t val, int32_t amount, uint32_t range) | ||
749 | { | ||
750 | if (amount < 0) | ||
751 | { | ||
752 | uint32_t off = -amount; | ||
753 | if (range > off && val >= off) | ||
754 | val -= off; | ||
755 | else | ||
756 | val = 0; | ||
757 | } | ||
758 | else if (amount > 0) | ||
759 | { | ||
760 | uint32_t off = amount; | ||
761 | if (range > off && val <= range - off) | ||
762 | val += off; | ||
763 | else | ||
764 | val = range; | ||
765 | } | ||
766 | |||
767 | return val; | ||
768 | } | ||
769 | |||
770 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | ||
771 | static void get_start_time_lcd_enable_hook(unsigned short id, void *param) | ||
772 | { | ||
773 | (void)id; | ||
774 | (void)param; | ||
775 | rb->queue_post(rb->button_queue, LCD_ENABLE_EVENT_0, 0); | ||
776 | } | ||
777 | #endif /* HAVE_LCD_ENABLE */ | ||
778 | |||
779 | static int get_start_time(uint32_t duration) | ||
780 | { | ||
781 | int button = 0; | ||
782 | int tmo = TIMEOUT_NOBLOCK; | ||
783 | uint32_t resume_time = settings.resume_time; | ||
784 | struct vo_rect rc_vid, rc_bound; | ||
785 | uint32_t aspect_vid, aspect_bound; | ||
786 | bool sliding = false; | ||
787 | |||
788 | enum state_enum slider_state = STATE0; | ||
789 | |||
790 | mylcd_clear_display(); | ||
791 | mylcd_update(); | ||
792 | |||
793 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | ||
794 | rb->add_event(LCD_EVENT_ACTIVATION, get_start_time_lcd_enable_hook); | ||
795 | #endif | ||
796 | |||
797 | draw_slider(0, 100, &rc_bound); | ||
798 | rc_bound.b = rc_bound.t - SLIDER_TMARGIN; | ||
799 | rc_bound.t = SCREEN_MARGIN; | ||
800 | |||
801 | DEBUGF("rc_bound: %d, %d, %d, %d\n", rc_bound.l, rc_bound.t, | ||
802 | rc_bound.r, rc_bound.b); | ||
803 | |||
804 | rc_vid.l = rc_vid.t = 0; | ||
805 | if (!stream_vo_get_size((struct vo_ext *)&rc_vid.r)) | ||
806 | { | ||
807 | /* Can't get size - fill whole thing */ | ||
808 | rc_vid.r = rc_bound.r - rc_bound.l; | ||
809 | rc_vid.b = rc_bound.b - rc_bound.t; | ||
810 | } | ||
811 | |||
812 | /* Get aspect ratio of bounding rectangle and video in u16.16 */ | ||
813 | aspect_bound = ((rc_bound.r - rc_bound.l) << 16) / | ||
814 | (rc_bound.b - rc_bound.t); | ||
815 | |||
816 | DEBUGF("aspect_bound: %u.%02u\n", (unsigned)(aspect_bound >> 16), | ||
817 | (unsigned)(100*(aspect_bound & 0xffff) >> 16)); | ||
818 | |||
819 | aspect_vid = (rc_vid.r << 16) / rc_vid.b; | ||
820 | |||
821 | DEBUGF("aspect_vid: %u.%02u\n", (unsigned)(aspect_vid >> 16), | ||
822 | (unsigned)(100*(aspect_vid & 0xffff) >> 16)); | ||
823 | |||
824 | if (aspect_vid >= aspect_bound) | ||
825 | { | ||
826 | /* Video proportionally wider than or same as bounding rectangle */ | ||
827 | if (rc_vid.r > rc_bound.r - rc_bound.l) | ||
828 | { | ||
829 | rc_vid.r = rc_bound.r - rc_bound.l; | ||
830 | rc_vid.b = (rc_vid.r << 16) / aspect_vid; | ||
831 | } | ||
832 | /* else already fits */ | ||
833 | } | ||
834 | else | ||
835 | { | ||
836 | /* Video proportionally narrower than bounding rectangle */ | ||
837 | if (rc_vid.b > rc_bound.b - rc_bound.t) | ||
838 | { | ||
839 | rc_vid.b = rc_bound.b - rc_bound.t; | ||
840 | rc_vid.r = (aspect_vid * rc_vid.b) >> 16; | ||
841 | } | ||
842 | /* else already fits */ | ||
843 | } | ||
844 | |||
845 | /* Even width and height >= 2 */ | ||
846 | rc_vid.r = (rc_vid.r < 2) ? 2 : (rc_vid.r & ~1); | ||
847 | rc_vid.b = (rc_vid.b < 2) ? 2 : (rc_vid.b & ~1); | ||
848 | |||
849 | /* Center display in bounding rectangle */ | ||
850 | rc_vid.l = ((rc_bound.l + rc_bound.r) - rc_vid.r) / 2; | ||
851 | rc_vid.r += rc_vid.l; | ||
852 | |||
853 | rc_vid.t = ((rc_bound.t + rc_bound.b) - rc_vid.b) / 2; | ||
854 | rc_vid.b += rc_vid.t; | ||
855 | |||
856 | DEBUGF("rc_vid: %d, %d, %d, %d\n", rc_vid.l, rc_vid.t, | ||
857 | rc_vid.r, rc_vid.b); | ||
858 | |||
859 | #ifndef HAVE_LCD_COLOR | ||
860 | stream_gray_show(true); | ||
861 | #endif | ||
862 | |||
863 | while (slider_state < STATE9) | ||
864 | { | ||
865 | button = mpeg_button_get(tmo); | ||
866 | |||
867 | switch (button) | ||
868 | { | ||
869 | case BUTTON_NONE: | ||
870 | break; | ||
871 | |||
872 | /* Coarse (1 minute) control */ | ||
873 | case MPEG_START_TIME_DOWN: | ||
874 | case MPEG_START_TIME_DOWN | BUTTON_REPEAT: | ||
875 | #ifdef MPEG_START_TIME_RC_DOWN | ||
876 | case MPEG_START_TIME_RC_DOWN: | ||
877 | case MPEG_START_TIME_RC_DOWN | BUTTON_REPEAT: | ||
878 | #endif | ||
879 | resume_time = increment_time(resume_time, -60*TS_SECOND, duration); | ||
880 | slider_state = STATE0; | ||
881 | break; | ||
882 | |||
883 | case MPEG_START_TIME_UP: | ||
884 | case MPEG_START_TIME_UP | BUTTON_REPEAT: | ||
885 | #ifdef MPEG_START_TIME_RC_UP | ||
886 | case MPEG_START_TIME_RC_UP: | ||
887 | case MPEG_START_TIME_RC_UP | BUTTON_REPEAT: | ||
888 | #endif | ||
889 | resume_time = increment_time(resume_time, 60*TS_SECOND, duration); | ||
890 | slider_state = STATE0; | ||
891 | break; | ||
892 | |||
893 | /* Fine (1 second) control */ | ||
894 | case MPEG_START_TIME_LEFT: | ||
895 | case MPEG_START_TIME_LEFT | BUTTON_REPEAT: | ||
896 | #ifdef MPEG_START_TIME_RC_LEFT | ||
897 | case MPEG_START_TIME_RC_LEFT: | ||
898 | case MPEG_START_TIME_RC_LEFT | BUTTON_REPEAT: | ||
899 | #endif | ||
900 | #ifdef MPEG_START_TIME_LEFT2 | ||
901 | case MPEG_START_TIME_LEFT2: | ||
902 | case MPEG_START_TIME_LEFT2 | BUTTON_REPEAT: | ||
903 | #endif | ||
904 | resume_time = increment_time(resume_time, -TS_SECOND, duration); | ||
905 | slider_state = STATE0; | ||
906 | break; | ||
907 | |||
908 | case MPEG_START_TIME_RIGHT: | ||
909 | case MPEG_START_TIME_RIGHT | BUTTON_REPEAT: | ||
910 | #ifdef MPEG_START_TIME_RC_RIGHT | ||
911 | case MPEG_START_TIME_RC_RIGHT: | ||
912 | case MPEG_START_TIME_RC_RIGHT | BUTTON_REPEAT: | ||
913 | #endif | ||
914 | #ifdef MPEG_START_TIME_RIGHT2 | ||
915 | case MPEG_START_TIME_RIGHT2: | ||
916 | case MPEG_START_TIME_RIGHT2 | BUTTON_REPEAT: | ||
917 | #endif | ||
918 | resume_time = increment_time(resume_time, TS_SECOND, duration); | ||
919 | slider_state = STATE0; | ||
920 | break; | ||
921 | |||
922 | case MPEG_START_TIME_SELECT: | ||
923 | #ifdef MPEG_START_TIME_RC_SELECT | ||
924 | case MPEG_START_TIME_RC_SELECT: | ||
925 | #endif | ||
926 | settings.resume_time = resume_time; | ||
927 | button = MPEG_START_SEEK; | ||
928 | slider_state = STATE9; | ||
929 | break; | ||
930 | |||
931 | case MPEG_START_TIME_EXIT: | ||
932 | #ifdef MPEG_START_TIME_RC_EXIT | ||
933 | case MPEG_START_TIME_RC_EXIT: | ||
934 | #endif | ||
935 | button = MPEG_START_EXIT; | ||
936 | slider_state = STATE9; | ||
937 | break; | ||
938 | |||
939 | case ACTION_STD_CANCEL: | ||
940 | button = MPEG_START_QUIT; | ||
941 | slider_state = STATE9; | ||
942 | break; | ||
943 | |||
944 | #ifdef HAVE_LCD_ENABLE | ||
945 | case LCD_ENABLE_EVENT_0: | ||
946 | if (slider_state == STATE2) | ||
947 | display_thumb_image(&rc_vid); | ||
948 | continue; | ||
949 | #endif | ||
950 | |||
951 | default: | ||
952 | rb->default_event_handler(button); | ||
953 | rb->yield(); | ||
954 | continue; | ||
955 | } | ||
956 | |||
957 | switch (slider_state) | ||
958 | { | ||
959 | case STATE0: | ||
960 | if (!sliding) | ||
961 | { | ||
962 | if (rb->global_settings->talk_menu) | ||
963 | { | ||
964 | rb->talk_disable(true); | ||
965 | #ifdef PLUGIN_USE_IRAM | ||
966 | mpegplayer_iram_restore(); | ||
967 | #endif | ||
968 | } | ||
969 | trigger_cpu_boost(); | ||
970 | sliding = true; | ||
971 | } | ||
972 | stream_seek(resume_time, SEEK_SET); | ||
973 | show_loading(&rc_bound); | ||
974 | draw_slider(duration, resume_time, NULL); | ||
975 | slider_state = STATE1; | ||
976 | tmo = THUMB_DELAY; | ||
977 | break; | ||
978 | case STATE1: | ||
979 | display_thumb_image(&rc_vid); | ||
980 | slider_state = STATE2; | ||
981 | tmo = TIMEOUT_BLOCK; | ||
982 | if (sliding) | ||
983 | { | ||
984 | cancel_cpu_boost(); | ||
985 | if (rb->global_settings->talk_menu) | ||
986 | { | ||
987 | #ifdef PLUGIN_USE_IRAM | ||
988 | mpegplayer_iram_preserve(); | ||
989 | #endif | ||
990 | rb->talk_disable(false); | ||
991 | talk_val(resume_time / TS_SECOND, UNIT_TIME, false); | ||
992 | talk_val(resume_time * 100 / duration, UNIT_PERCENT, true); | ||
993 | } | ||
994 | sliding = false; | ||
995 | } | ||
996 | default: | ||
997 | break; | ||
998 | } | ||
999 | |||
1000 | rb->yield(); | ||
1001 | } | ||
1002 | |||
1003 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | ||
1004 | rb->remove_event(LCD_EVENT_ACTIVATION, get_start_time_lcd_enable_hook); | ||
1005 | #endif | ||
1006 | #ifndef HAVE_LCD_COLOR | ||
1007 | stream_gray_show(false); | ||
1008 | grey_clear_display(); | ||
1009 | grey_update(); | ||
1010 | #endif | ||
1011 | |||
1012 | cancel_cpu_boost(); | ||
1013 | |||
1014 | return button; | ||
1015 | } | ||
1016 | |||
1017 | static int show_start_menu(uint32_t duration) | ||
1018 | { | ||
1019 | int selected = 0; | ||
1020 | int result = 0; | ||
1021 | bool menu_quit = false; | ||
1022 | |||
1023 | MENUITEM_STRINGLIST(menu, "Mpegplayer Menu", mpeg_sysevent_callback, | ||
1024 | ID2P(LANG_RESTART_PLAYBACK), | ||
1025 | ID2P(LANG_RESUME_PLAYBACK), | ||
1026 | ID2P(LANG_SET_RESUME_TIME), | ||
1027 | ID2P(LANG_SETTINGS), | ||
1028 | ID2P(LANG_MENU_QUIT)); | ||
1029 | |||
1030 | if (rb->global_settings->talk_menu) | ||
1031 | { | ||
1032 | #ifdef PLUGIN_USE_IRAM | ||
1033 | mpegplayer_iram_preserve(); | ||
1034 | #endif | ||
1035 | rb->talk_disable(false); | ||
1036 | } | ||
1037 | |||
1038 | rb->button_clear_queue(); | ||
1039 | |||
1040 | while (!menu_quit) | ||
1041 | { | ||
1042 | mpeg_sysevent_clear(); | ||
1043 | result = rb->do_menu(&menu, &selected, NULL, false); | ||
1044 | |||
1045 | switch (result) | ||
1046 | { | ||
1047 | case MPEG_START_RESTART: | ||
1048 | settings.resume_time = 0; | ||
1049 | menu_quit = true; | ||
1050 | break; | ||
1051 | |||
1052 | case MPEG_START_RESUME: | ||
1053 | menu_quit = true; | ||
1054 | break; | ||
1055 | |||
1056 | case MPEG_START_SEEK: | ||
1057 | if (!stream_can_seek()) | ||
1058 | { | ||
1059 | rb->splash(HZ, ID2P(LANG_UNAVAILABLE)); | ||
1060 | break; | ||
1061 | } | ||
1062 | |||
1063 | result = get_start_time(duration); | ||
1064 | |||
1065 | if (result != MPEG_START_EXIT) | ||
1066 | menu_quit = true; | ||
1067 | break; | ||
1068 | |||
1069 | case MPEG_START_SETTINGS: | ||
1070 | mpeg_settings(); | ||
1071 | break; | ||
1072 | |||
1073 | default: | ||
1074 | result = MPEG_START_QUIT; | ||
1075 | menu_quit = true; | ||
1076 | break; | ||
1077 | } | ||
1078 | |||
1079 | if (mpeg_sysevent() != 0) | ||
1080 | { | ||
1081 | result = MPEG_START_QUIT; | ||
1082 | menu_quit = true; | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1086 | if (rb->global_settings->talk_menu) | ||
1087 | { | ||
1088 | rb->talk_disable(true); | ||
1089 | #ifdef PLUGIN_USE_IRAM | ||
1090 | mpegplayer_iram_restore(); | ||
1091 | #endif | ||
1092 | } | ||
1093 | |||
1094 | return result; | ||
1095 | } | ||
1096 | |||
1097 | /* Return the desired resume action */ | ||
1098 | int mpeg_start_menu(uint32_t duration) | ||
1099 | { | ||
1100 | mpeg_sysevent_clear(); | ||
1101 | |||
1102 | switch (settings.resume_options) | ||
1103 | { | ||
1104 | case MPEG_RESUME_MENU_IF_INCOMPLETE: | ||
1105 | if (!stream_can_seek() || settings.resume_time == 0) | ||
1106 | { | ||
1107 | case MPEG_RESUME_RESTART: | ||
1108 | settings.resume_time = 0; | ||
1109 | return MPEG_START_RESTART; | ||
1110 | } | ||
1111 | default: | ||
1112 | case MPEG_RESUME_MENU_ALWAYS: | ||
1113 | return show_start_menu(duration); | ||
1114 | case MPEG_RESUME_ALWAYS: | ||
1115 | return MPEG_START_SEEK; | ||
1116 | } | ||
1117 | } | ||
1118 | |||
1119 | int mpeg_menu(void) | ||
1120 | { | ||
1121 | int result; | ||
1122 | |||
1123 | MENUITEM_STRINGLIST(menu, "Mpegplayer Menu", mpeg_sysevent_callback, | ||
1124 | ID2P(LANG_SETTINGS), | ||
1125 | ID2P(LANG_RESUME_PLAYBACK), | ||
1126 | ID2P(LANG_MENU_QUIT)); | ||
1127 | |||
1128 | if (rb->global_settings->talk_menu) | ||
1129 | { | ||
1130 | #ifdef PLUGIN_USE_IRAM | ||
1131 | mpegplayer_iram_preserve(); | ||
1132 | #endif | ||
1133 | rb->talk_disable(false); | ||
1134 | } | ||
1135 | |||
1136 | rb->button_clear_queue(); | ||
1137 | |||
1138 | mpeg_sysevent_clear(); | ||
1139 | |||
1140 | result = rb->do_menu(&menu, NULL, NULL, false); | ||
1141 | |||
1142 | switch (result) | ||
1143 | { | ||
1144 | case MPEG_MENU_SETTINGS: | ||
1145 | mpeg_settings(); | ||
1146 | break; | ||
1147 | |||
1148 | case MPEG_MENU_RESUME: | ||
1149 | break; | ||
1150 | |||
1151 | case MPEG_MENU_QUIT: | ||
1152 | break; | ||
1153 | |||
1154 | default: | ||
1155 | break; | ||
1156 | } | ||
1157 | |||
1158 | if (mpeg_sysevent() != 0) | ||
1159 | result = MPEG_MENU_QUIT; | ||
1160 | |||
1161 | if (rb->global_settings->talk_menu) | ||
1162 | { | ||
1163 | rb->talk_disable(true); | ||
1164 | #ifdef PLUGIN_USE_IRAM | ||
1165 | mpegplayer_iram_restore(); | ||
1166 | #endif | ||
1167 | } | ||
1168 | |||
1169 | return result; | ||
1170 | } | ||
1171 | |||
1172 | static void display_options(void) | ||
1173 | { | ||
1174 | int selected = 0; | ||
1175 | int result; | ||
1176 | bool menu_quit = false; | ||
1177 | |||
1178 | MENUITEM_STRINGLIST(menu, "Display Options", mpeg_sysevent_callback, | ||
1179 | #if MPEG_OPTION_DITHERING_ENABLED | ||
1180 | ID2P(LANG_DITHERING), | ||
1181 | #endif | ||
1182 | ID2P(LANG_DISPLAY_FPS), | ||
1183 | ID2P(LANG_LIMIT_FPS), | ||
1184 | ID2P(LANG_SKIP_FRAMES), | ||
1185 | #ifdef HAVE_BACKLIGHT_BRIGHTNESS | ||
1186 | ID2P(LANG_BACKLIGHT_BRIGHTNESS), | ||
1187 | #endif | ||
1188 | ); | ||
1189 | |||
1190 | rb->button_clear_queue(); | ||
1191 | |||
1192 | while (!menu_quit) | ||
1193 | { | ||
1194 | mpeg_sysevent_clear(); | ||
1195 | result = rb->do_menu(&menu, &selected, NULL, false); | ||
1196 | |||
1197 | switch (result) | ||
1198 | { | ||
1199 | #if MPEG_OPTION_DITHERING_ENABLED | ||
1200 | case MPEG_OPTION_DITHERING: | ||
1201 | result = (settings.displayoptions & LCD_YUV_DITHER) ? 1 : 0; | ||
1202 | mpeg_set_option(rb->str(LANG_DITHERING), &result, INT, noyes, 2, NULL); | ||
1203 | settings.displayoptions = | ||
1204 | (settings.displayoptions & ~LCD_YUV_DITHER) | ||
1205 | | ((result != 0) ? LCD_YUV_DITHER : 0); | ||
1206 | rb->lcd_yuv_set_options(settings.displayoptions); | ||
1207 | break; | ||
1208 | #endif /* MPEG_OPTION_DITHERING_ENABLED */ | ||
1209 | |||
1210 | case MPEG_OPTION_DISPLAY_FPS: | ||
1211 | mpeg_set_option(rb->str(LANG_DISPLAY_FPS), &settings.showfps, INT, | ||
1212 | noyes, 2, NULL); | ||
1213 | break; | ||
1214 | |||
1215 | case MPEG_OPTION_LIMIT_FPS: | ||
1216 | mpeg_set_option(rb->str(LANG_LIMIT_FPS), &settings.limitfps, INT, | ||
1217 | noyes, 2, NULL); | ||
1218 | break; | ||
1219 | |||
1220 | case MPEG_OPTION_SKIP_FRAMES: | ||
1221 | mpeg_set_option(rb->str(LANG_SKIP_FRAMES), &settings.skipframes, INT, | ||
1222 | noyes, 2, NULL); | ||
1223 | break; | ||
1224 | |||
1225 | #ifdef HAVE_BACKLIGHT_BRIGHTNESS | ||
1226 | case MPEG_OPTION_BACKLIGHT_BRIGHTNESS: | ||
1227 | result = settings.backlight_brightness; | ||
1228 | mpeg_backlight_update_brightness(result); | ||
1229 | mpeg_set_int(rb->str(LANG_BACKLIGHT_BRIGHTNESS), NULL, UNIT_INT, &result, | ||
1230 | backlight_brightness_function, 1, -1, | ||
1231 | MAX_BRIGHTNESS_SETTING - MIN_BRIGHTNESS_SETTING, | ||
1232 | backlight_brightness_formatter, | ||
1233 | backlight_brightness_getlang); | ||
1234 | settings.backlight_brightness = result; | ||
1235 | mpeg_backlight_update_brightness(-1); | ||
1236 | break; | ||
1237 | #endif /* HAVE_BACKLIGHT_BRIGHTNESS */ | ||
1238 | |||
1239 | default: | ||
1240 | menu_quit = true; | ||
1241 | break; | ||
1242 | } | ||
1243 | |||
1244 | if (mpeg_sysevent() != 0) | ||
1245 | menu_quit = true; | ||
1246 | } | ||
1247 | } | ||
1248 | |||
1249 | static void audio_options(void) | ||
1250 | { | ||
1251 | int selected = 0; | ||
1252 | int result; | ||
1253 | bool menu_quit = false; | ||
1254 | |||
1255 | MENUITEM_STRINGLIST(menu, "Audio Options", mpeg_sysevent_callback, | ||
1256 | ID2P(LANG_TONE_CONTROLS), | ||
1257 | ID2P(LANG_CHANNEL_CONFIGURATION), | ||
1258 | ID2P(LANG_CROSSFEED), | ||
1259 | ID2P(LANG_EQUALIZER), | ||
1260 | ID2P(LANG_DITHERING)); | ||
1261 | |||
1262 | rb->button_clear_queue(); | ||
1263 | |||
1264 | while (!menu_quit) | ||
1265 | { | ||
1266 | mpeg_sysevent_clear(); | ||
1267 | result = rb->do_menu(&menu, &selected, NULL, false); | ||
1268 | |||
1269 | switch (result) | ||
1270 | { | ||
1271 | case MPEG_AUDIO_TONE_CONTROLS: | ||
1272 | mpeg_set_option(rb->str(LANG_TONE_CONTROLS), &settings.tone_controls, INT, | ||
1273 | globaloff, 2, NULL); | ||
1274 | sync_audio_setting(result, false); | ||
1275 | break; | ||
1276 | |||
1277 | case MPEG_AUDIO_CHANNEL_MODES: | ||
1278 | mpeg_set_option(rb->str(LANG_CHANNEL_CONFIGURATION), &settings.channel_modes, | ||
1279 | INT, globaloff, 2, NULL); | ||
1280 | sync_audio_setting(result, false); | ||
1281 | break; | ||
1282 | |||
1283 | case MPEG_AUDIO_CROSSFEED: | ||
1284 | mpeg_set_option(rb->str(LANG_CROSSFEED), &settings.crossfeed, INT, | ||
1285 | globaloff, 2, NULL); | ||
1286 | sync_audio_setting(result, false); | ||
1287 | break; | ||
1288 | |||
1289 | case MPEG_AUDIO_EQUALIZER: | ||
1290 | mpeg_set_option(rb->str(LANG_EQUALIZER), &settings.equalizer, INT, | ||
1291 | globaloff, 2, NULL); | ||
1292 | sync_audio_setting(result, false); | ||
1293 | break; | ||
1294 | |||
1295 | case MPEG_AUDIO_DITHERING: | ||
1296 | mpeg_set_option(rb->str(LANG_DITHERING), &settings.dithering, INT, | ||
1297 | globaloff, 2, NULL); | ||
1298 | sync_audio_setting(result, false); | ||
1299 | break; | ||
1300 | |||
1301 | default: | ||
1302 | menu_quit = true; | ||
1303 | break; | ||
1304 | } | ||
1305 | |||
1306 | if (mpeg_sysevent() != 0) | ||
1307 | menu_quit = true; | ||
1308 | } | ||
1309 | } | ||
1310 | |||
1311 | static void resume_options(void) | ||
1312 | { | ||
1313 | static const struct opt_items items[MPEG_RESUME_NUM_OPTIONS] = { | ||
1314 | [MPEG_RESUME_MENU_ALWAYS] = | ||
1315 | { STR(LANG_FORCE_START_MENU) }, | ||
1316 | [MPEG_RESUME_MENU_IF_INCOMPLETE] = | ||
1317 | { STR(LANG_CONDITIONAL_START_MENU) }, | ||
1318 | [MPEG_RESUME_ALWAYS] = | ||
1319 | { STR(LANG_AUTO_RESUME) }, | ||
1320 | [MPEG_RESUME_RESTART] = | ||
1321 | { STR(LANG_RESTART_PLAYBACK) }, | ||
1322 | }; | ||
1323 | |||
1324 | mpeg_set_option(rb->str(LANG_MENU_RESUME_OPTIONS), &settings.resume_options, | ||
1325 | INT, items, MPEG_RESUME_NUM_OPTIONS, NULL); | ||
1326 | } | ||
1327 | |||
1328 | static void clear_resume_count(void) | ||
1329 | { | ||
1330 | settings.resume_count = 0; | ||
1331 | configfile_save(SETTINGS_FILENAME, config, ARRAYLEN(config), | ||
1332 | SETTINGS_VERSION); | ||
1333 | } | ||
1334 | |||
1335 | static void mpeg_settings(void) | ||
1336 | { | ||
1337 | int selected = 0; | ||
1338 | int result; | ||
1339 | bool menu_quit = false; | ||
1340 | |||
1341 | MENUITEM_STRINGLIST(menu, "Settings", mpeg_sysevent_callback, | ||
1342 | ID2P(LANG_MENU_DISPLAY_OPTIONS), | ||
1343 | ID2P(LANG_MENU_AUDIO_OPTIONS), | ||
1344 | ID2P(LANG_MENU_RESUME_OPTIONS), | ||
1345 | ID2P(LANG_MENU_PLAY_MODE), | ||
1346 | ID2P(LANG_CLEAR_ALL_RESUMES)); | ||
1347 | |||
1348 | rb->button_clear_queue(); | ||
1349 | |||
1350 | while (!menu_quit) | ||
1351 | { | ||
1352 | mpeg_sysevent_clear(); | ||
1353 | |||
1354 | result = rb->do_menu(&menu, &selected, NULL, false); | ||
1355 | |||
1356 | switch (result) | ||
1357 | { | ||
1358 | case MPEG_SETTING_DISPLAY_SETTINGS: | ||
1359 | display_options(); | ||
1360 | break; | ||
1361 | |||
1362 | case MPEG_SETTING_AUDIO_SETTINGS: | ||
1363 | audio_options(); | ||
1364 | break; | ||
1365 | |||
1366 | case MPEG_SETTING_ENABLE_START_MENU: | ||
1367 | resume_options(); | ||
1368 | break; | ||
1369 | |||
1370 | case MPEG_SETTING_PLAY_MODE: | ||
1371 | mpeg_set_option(rb->str(LANG_MENU_PLAY_MODE), &settings.play_mode, | ||
1372 | INT, singleall, 2, NULL); | ||
1373 | break; | ||
1374 | |||
1375 | case MPEG_SETTING_CLEAR_RESUMES: | ||
1376 | clear_resume_count(); | ||
1377 | break; | ||
1378 | |||
1379 | default: | ||
1380 | menu_quit = true; | ||
1381 | break; | ||
1382 | } | ||
1383 | |||
1384 | if (mpeg_sysevent() != 0) | ||
1385 | menu_quit = true; | ||
1386 | } | ||
1387 | } | ||
1388 | |||
1389 | void init_settings(const char* filename) | ||
1390 | { | ||
1391 | /* Set the default settings */ | ||
1392 | settings.showfps = 0; /* Do not show FPS */ | ||
1393 | settings.limitfps = 1; /* Limit FPS */ | ||
1394 | settings.skipframes = 1; /* Skip frames */ | ||
1395 | settings.play_mode = 0; /* Play single video */ | ||
1396 | settings.resume_options = MPEG_RESUME_MENU_ALWAYS; /* Enable start menu */ | ||
1397 | settings.resume_count = 0; | ||
1398 | #ifdef HAVE_BACKLIGHT_BRIGHTNESS | ||
1399 | settings.backlight_brightness = -1; /* Use default setting */ | ||
1400 | #endif | ||
1401 | #if MPEG_OPTION_DITHERING_ENABLED | ||
1402 | settings.displayoptions = 0; /* No visual effects */ | ||
1403 | #endif | ||
1404 | settings.tone_controls = false; | ||
1405 | settings.channel_modes = false; | ||
1406 | settings.crossfeed = false; | ||
1407 | settings.equalizer = false; | ||
1408 | settings.dithering = false; | ||
1409 | |||
1410 | if (configfile_load(SETTINGS_FILENAME, config, ARRAYLEN(config), | ||
1411 | SETTINGS_MIN_VERSION) < 0) | ||
1412 | { | ||
1413 | /* Generate a new config file with default values */ | ||
1414 | configfile_save(SETTINGS_FILENAME, config, ARRAYLEN(config), | ||
1415 | SETTINGS_VERSION); | ||
1416 | } | ||
1417 | |||
1418 | rb->strlcpy(settings.resume_filename, filename, MAX_PATH); | ||
1419 | |||
1420 | /* get the resume time for the current mpeg if it exists */ | ||
1421 | if ((settings.resume_time = configfile_get_value | ||
1422 | (SETTINGS_FILENAME, filename)) < 0) | ||
1423 | { | ||
1424 | settings.resume_time = 0; | ||
1425 | } | ||
1426 | |||
1427 | #if MPEG_OPTION_DITHERING_ENABLED | ||
1428 | rb->lcd_yuv_set_options(settings.displayoptions); | ||
1429 | #endif | ||
1430 | |||
1431 | /* Set our audio options */ | ||
1432 | sync_audio_settings(false); | ||
1433 | } | ||
1434 | |||
1435 | void save_settings(void) | ||
1436 | { | ||
1437 | unsigned i; | ||
1438 | for (i = 0; i < ARRAYLEN(config); i++) | ||
1439 | { | ||
1440 | configfile_update_entry(SETTINGS_FILENAME, config[i].name, | ||
1441 | *(config[i].int_p)); | ||
1442 | } | ||
1443 | |||
1444 | /* If this was a new resume entry then update the total resume count */ | ||
1445 | if (configfile_update_entry(SETTINGS_FILENAME, settings.resume_filename, | ||
1446 | settings.resume_time) == 0) | ||
1447 | { | ||
1448 | configfile_update_entry(SETTINGS_FILENAME, "Resume count", | ||
1449 | ++settings.resume_count); | ||
1450 | } | ||
1451 | |||
1452 | /* Restore audio options */ | ||
1453 | sync_audio_settings(true); | ||
1454 | } | ||
diff --git a/apps/plugins/mpegplayer/mpeg_settings.h b/apps/plugins/mpegplayer/mpeg_settings.h deleted file mode 100644 index b1704ef707..0000000000 --- a/apps/plugins/mpegplayer/mpeg_settings.h +++ /dev/null | |||
@@ -1,110 +0,0 @@ | |||
1 | |||
2 | #include "plugin.h" | ||
3 | |||
4 | #define SETTINGS_VERSION 5 | ||
5 | #define SETTINGS_MIN_VERSION 1 | ||
6 | #define SETTINGS_FILENAME "mpegplayer.cfg" | ||
7 | |||
8 | #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200) \ | ||
9 | || defined(IRIVER_H10) || defined(COWON_D2) || defined(PHILIPS_HDD1630) \ | ||
10 | || defined(SANSA_FUZE) || defined(SANSA_E200V2) || defined(SANSA_FUZEV2) \ | ||
11 | || defined(TOSHIBA_GIGABEAT_S) || defined(PHILIPS_SA9200) | ||
12 | #define MPEG_OPTION_DITHERING_ENABLED 1 | ||
13 | #endif | ||
14 | |||
15 | #ifndef MPEG_OPTION_DITHERING_ENABLED | ||
16 | #define MPEG_OPTION_DITHERING_ENABLED 0 | ||
17 | #endif | ||
18 | |||
19 | enum mpeg_option_id | ||
20 | { | ||
21 | #if MPEG_OPTION_DITHERING_ENABLED | ||
22 | MPEG_OPTION_DITHERING, | ||
23 | #endif | ||
24 | MPEG_OPTION_DISPLAY_FPS, | ||
25 | MPEG_OPTION_LIMIT_FPS, | ||
26 | MPEG_OPTION_SKIP_FRAMES, | ||
27 | #ifdef HAVE_BACKLIGHT_BRIGHTNESS | ||
28 | MPEG_OPTION_BACKLIGHT_BRIGHTNESS, | ||
29 | #endif | ||
30 | }; | ||
31 | |||
32 | enum mpeg_audio_option_id | ||
33 | { | ||
34 | MPEG_AUDIO_TONE_CONTROLS, | ||
35 | MPEG_AUDIO_CHANNEL_MODES, | ||
36 | MPEG_AUDIO_CROSSFEED, | ||
37 | MPEG_AUDIO_EQUALIZER, | ||
38 | MPEG_AUDIO_DITHERING, | ||
39 | }; | ||
40 | |||
41 | enum mpeg_resume_id | ||
42 | { | ||
43 | MPEG_RESUME_MENU_ALWAYS = 0, | ||
44 | MPEG_RESUME_MENU_IF_INCOMPLETE, | ||
45 | MPEG_RESUME_RESTART, | ||
46 | MPEG_RESUME_ALWAYS, | ||
47 | MPEG_RESUME_NUM_OPTIONS, | ||
48 | }; | ||
49 | |||
50 | enum mpeg_start_id | ||
51 | { | ||
52 | MPEG_START_RESTART, | ||
53 | MPEG_START_RESUME, | ||
54 | MPEG_START_SEEK, | ||
55 | MPEG_START_SETTINGS, | ||
56 | MPEG_START_QUIT, | ||
57 | MPEG_START_EXIT, | ||
58 | }; | ||
59 | |||
60 | enum mpeg_setting_id | ||
61 | { | ||
62 | MPEG_SETTING_DISPLAY_SETTINGS, | ||
63 | MPEG_SETTING_AUDIO_SETTINGS, | ||
64 | MPEG_SETTING_ENABLE_START_MENU, | ||
65 | MPEG_SETTING_PLAY_MODE, | ||
66 | MPEG_SETTING_CLEAR_RESUMES, | ||
67 | }; | ||
68 | |||
69 | enum mpeg_menu_id | ||
70 | { | ||
71 | MPEG_MENU_SETTINGS, | ||
72 | MPEG_MENU_RESUME, | ||
73 | MPEG_MENU_QUIT, | ||
74 | }; | ||
75 | |||
76 | struct mpeg_settings { | ||
77 | int showfps; /* flag to display fps */ | ||
78 | int limitfps; /* flag to limit fps */ | ||
79 | int skipframes; /* flag to skip frames */ | ||
80 | int resume_options; /* type of resume action at start */ | ||
81 | int resume_count; /* total # of resumes in config file */ | ||
82 | int resume_time; /* resume time for current mpeg (in half minutes) */ | ||
83 | char resume_filename[MAX_PATH]; /* filename of current mpeg */ | ||
84 | #if MPEG_OPTION_DITHERING_ENABLED | ||
85 | int displayoptions; | ||
86 | #endif | ||
87 | int play_mode; /* play single file or all files in directory */ | ||
88 | /* Audio options - simple on/off specification */ | ||
89 | int tone_controls; | ||
90 | int channel_modes; | ||
91 | int crossfeed; | ||
92 | int equalizer; | ||
93 | int dithering; | ||
94 | /* Backlight options */ | ||
95 | #ifdef HAVE_BACKLIGHT_BRIGHTNESS | ||
96 | int backlight_brightness; | ||
97 | #endif | ||
98 | }; | ||
99 | |||
100 | extern struct mpeg_settings settings; | ||
101 | |||
102 | int mpeg_start_menu(uint32_t duration); | ||
103 | int mpeg_menu(void); | ||
104 | |||
105 | void init_settings(const char* filename); | ||
106 | void save_settings(void); | ||
107 | |||
108 | #ifdef HAVE_BACKLIGHT_BRIGHTNESS | ||
109 | void mpeg_backlight_update_brightness(int value); | ||
110 | #endif | ||
diff --git a/apps/plugins/mpegplayer/mpeg_stream.h b/apps/plugins/mpegplayer/mpeg_stream.h deleted file mode 100644 index 26fdaf07b4..0000000000 --- a/apps/plugins/mpegplayer/mpeg_stream.h +++ /dev/null | |||
@@ -1,122 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Stream definitions for MPEG | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #ifndef MPEG_STREAM_H | ||
24 | #define MPEG_STREAM_H | ||
25 | |||
26 | /* Codes for various header byte sequences - MSB represents lowest memory | ||
27 | address */ | ||
28 | #define PACKET_START_CODE_PREFIX 0x00000100ul | ||
29 | #define END_CODE 0x000001b9ul | ||
30 | #define PACK_START_CODE 0x000001baul | ||
31 | #define SYSTEM_HEADER_START_CODE 0x000001bbul | ||
32 | |||
33 | /* p = base pointer, b0 - b4 = byte offsets from p */ | ||
34 | /* We only care about the MS 32 bits of the 33 and so the ticks are 45kHz */ | ||
35 | #define TS_FROM_HEADER(p, b0) \ | ||
36 | ((uint32_t)((((p)[(b0)+0] & 0x0e) << 28) | \ | ||
37 | (((p)[(b0)+1] ) << 21) | \ | ||
38 | (((p)[(b0)+2] & 0xfe) << 13) | \ | ||
39 | (((p)[(b0)+3] ) << 6) | \ | ||
40 | (((p)[(b0)+4] ) >> 2))) | ||
41 | |||
42 | #define TS_CHECK_MARKERS(p, b0) \ | ||
43 | (((((p)[(b0)+0] & 0x01) << 2) | \ | ||
44 | (((p)[(b0)+2] & 0x01) << 1) | \ | ||
45 | (((p)[(b0)+4] & 0x01) )) == 0x07) | ||
46 | |||
47 | /* Get the SCR in our 45kHz ticks. Ignore the 9-bit extension */ | ||
48 | #define MPEG2_PACK_HEADER_SCR(p, b0) \ | ||
49 | ((uint32_t)((((p)[(b0)+0] & 0x38) << 26) | \ | ||
50 | (((p)[(b0)+0] & 0x03) << 27) | \ | ||
51 | (((p)[(b0)+1] ) << 19) | \ | ||
52 | (((p)[(b0)+2] & 0xf8) << 11) | \ | ||
53 | (((p)[(b0)+2] & 0x03) << 12) | \ | ||
54 | (((p)[(b0)+3] ) << 4) | \ | ||
55 | (((p)[(b0)+4] ) >> 4))) | ||
56 | |||
57 | #define MPEG2_CHECK_PACK_SCR_MARKERS(ph, b0) \ | ||
58 | (((((ph)[(b0)+0] & 0x04) ) | \ | ||
59 | (((ph)[(b0)+2] & 0x04) >> 1) | \ | ||
60 | (((ph)[(b0)+4] & 0x04) >> 2)) == 0x07) | ||
61 | |||
62 | #define INVALID_TIMESTAMP (~(uint32_t)0) | ||
63 | #define MAX_TIMESTAMP (INVALID_TIMESTAMP-1) | ||
64 | #define TS_SECOND (45000) /* Timestamp ticks per second */ | ||
65 | #define TC_SECOND (27000000) /* MPEG timecode ticks per second */ | ||
66 | |||
67 | /* These values immediately follow the start code prefix '00 00 01' */ | ||
68 | |||
69 | /* Video start codes */ | ||
70 | #define MPEG_START_PICTURE 0x00 | ||
71 | #define MPEG_START_SLICE_FIRST 0x01 | ||
72 | #define MPEG_START_SLICE_LAST 0xaf | ||
73 | #define MPEG_START_RESERVED_1 0xb0 | ||
74 | #define MPEG_START_RESERVED_2 0xb1 | ||
75 | #define MPEG_START_USER_DATA 0xb2 | ||
76 | #define MPEG_START_SEQUENCE_HEADER 0xb3 | ||
77 | #define MPEG_START_SEQUENCE_ERROR 0xb4 | ||
78 | #define MPEG_START_EXTENSION 0xb5 | ||
79 | #define MPEG_START_RESERVED_3 0xb6 | ||
80 | #define MPEG_START_SEQUENCE_END 0xb7 | ||
81 | #define MPEG_START_GOP 0xb8 | ||
82 | |||
83 | /* Stream IDs */ | ||
84 | #define MPEG_STREAM_PROGRAM_END 0xb9 | ||
85 | #define MPEG_STREAM_PACK_HEADER 0xba | ||
86 | #define MPEG_STREAM_SYSTEM_HEADER 0xbb | ||
87 | #define MPEG_STREAM_PROGRAM_STREAM_MAP 0xbc | ||
88 | #define MPEG_STREAM_PRIVATE_1 0xbd | ||
89 | #define MPEG_STREAM_PADDING 0xbe | ||
90 | #define MPEG_STREAM_PRIVATE_2 0xbf | ||
91 | #define MPEG_STREAM_AUDIO_FIRST 0xc0 | ||
92 | #define MPEG_STREAM_AUDIO_LAST 0xcf | ||
93 | #define MPEG_STREAM_VIDEO_FIRST 0xe0 | ||
94 | #define MPEG_STREAM_VIDEO_LAST 0xef | ||
95 | #define MPEG_STREAM_ECM 0xf0 | ||
96 | #define MPEG_STREAM_EMM 0xf1 | ||
97 | /* ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A or | ||
98 | * ISO/IEC 13818-6_DSMCC_stream */ | ||
99 | #define MPEG_STREAM_MISC_1 0xf2 | ||
100 | /* ISO/IEC_13522_stream */ | ||
101 | #define MPEG_STREAM_MISC_2 0xf3 | ||
102 | /* ITU-T Rec. H.222.1 type A - E */ | ||
103 | #define MPEG_STREAM_MISC_3 0xf4 | ||
104 | #define MPEG_STREAM_MISC_4 0xf5 | ||
105 | #define MPEG_STREAM_MISC_5 0xf6 | ||
106 | #define MPEG_STREAM_MISC_6 0xf7 | ||
107 | #define MPEG_STREAM_MISC_7 0xf8 | ||
108 | #define MPEG_STREAM_ANCILLARY 0xf9 | ||
109 | #define MPEG_STREAM_RESERVED_FIRST 0xfa | ||
110 | #define MPEG_STREAM_RESERVED_LAST 0xfe | ||
111 | /* Program stream directory */ | ||
112 | #define MPEG_STREAM_PROGRAM_DIRECTORY 0xff | ||
113 | |||
114 | #define STREAM_IS_AUDIO(s) (((s) & 0xf0) == 0xc0) | ||
115 | #define STREAM_IS_VIDEO(s) (((s) & 0xf0) == 0xe0) | ||
116 | |||
117 | #define MPEG_MAX_PACKET_SIZE (64*1024+16) | ||
118 | |||
119 | /* Largest MPEG audio frame - MPEG1, Layer II, 384kbps, 32kHz, pad */ | ||
120 | #define MPA_MAX_FRAME_SIZE 1729 | ||
121 | |||
122 | #endif /* MPEG_STREAM_H */ | ||
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c deleted file mode 100644 index e66b4df146..0000000000 --- a/apps/plugins/mpegplayer/mpegplayer.c +++ /dev/null | |||
@@ -1,2638 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * mpegplayer main entrypoint and UI implementation | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | /**************************************************************************** | ||
25 | * NOTES: | ||
26 | * | ||
27 | * mpegplayer is structured as follows: | ||
28 | * | ||
29 | * +-->Video Thread-->Video Output-->LCD | ||
30 | * | | ||
31 | * UI-->Stream Manager-->+-->Audio Thread-->PCM buffer--Audio Device | ||
32 | * | | | | (ref. clock) | ||
33 | * | | +-->Buffer Thread | | ||
34 | * Stream Data | | (clock intf./ | ||
35 | * Requests | File Cache drift adj.) | ||
36 | * | Disk I/O | ||
37 | * Stream services | ||
38 | * (timing, etc.) | ||
39 | * | ||
40 | * Thread list: | ||
41 | * 1) The main thread - Handles user input, settings, basic playback control | ||
42 | * and USB connect. | ||
43 | * | ||
44 | * 2) Stream Manager thread - Handles playback state, events from streams | ||
45 | * such as when a stream is finished, stream commands, PCM state. The | ||
46 | * layer in which this thread run also handles arbitration of data | ||
47 | * requests between the streams and the disk buffer. The actual specific | ||
48 | * transport layer code may get moved out to support multiple container | ||
49 | * formats. | ||
50 | * | ||
51 | * 3) Buffer thread - Buffers data in the background, generates notifications | ||
52 | * to streams when their data has been buffered, and watches streams' | ||
53 | * progress to keep data available during playback. Handles synchronous | ||
54 | * random access requests when the file cache is missed. | ||
55 | * | ||
56 | * 4) Video thread (running on the COP for PortalPlayer targets) - Decodes | ||
57 | * the video stream and renders video frames to the LCD. Handles | ||
58 | * miscellaneous video tasks like frame and thumbnail printing. | ||
59 | * | ||
60 | * 5) Audio thread (running on the main CPU to maintain consistency with the | ||
61 | * audio FIQ hander on PP) - Decodes audio frames and places them into | ||
62 | * the PCM buffer for rendering by the audio device. | ||
63 | * | ||
64 | * Streams are neither aware of one another nor care about one another. All | ||
65 | * streams shall have their own thread (unless it is _really_ efficient to | ||
66 | * have a single thread handle a couple minor streams). All coordination of | ||
67 | * the streams is done through the stream manager. The clocking is controlled | ||
68 | * by and exposed by the stream manager to other streams and implemented at | ||
69 | * the PCM level. | ||
70 | * | ||
71 | * Notes about MPEG files: | ||
72 | * | ||
73 | * MPEG System Clock is 27MHz - i.e. 27000000 ticks/second. | ||
74 | * | ||
75 | * FPS is represented in terms of a frame period - this is always an | ||
76 | * integer number of 27MHz ticks. | ||
77 | * | ||
78 | * e.g. 29.97fps (30000/1001) NTSC video has an exact frame period of | ||
79 | * 900900 27MHz ticks. | ||
80 | * | ||
81 | * In libmpeg2, info->sequence->frame_period contains the frame_period. | ||
82 | * | ||
83 | * Working with Rockbox's 100Hz tick, the common frame rates would need | ||
84 | * to be as follows (1): | ||
85 | * | ||
86 | * FPS | 27Mhz | 100Hz | 44.1KHz | 48KHz | ||
87 | * --------|----------------------------------------------------------- | ||
88 | * 10* | 2700000 | 10 | 4410 | 4800 | ||
89 | * 12* | 2250000 | 8.3333 | 3675 | 4000 | ||
90 | * 15* | 1800000 | 6.6667 | 2940 | 3200 | ||
91 | * 23.9760 | 1126125 | 4.170833333 | 1839.3375 | 2002 | ||
92 | * 24 | 1125000 | 4.166667 | 1837.5 | 2000 | ||
93 | * 25 | 1080000 | 4 | 1764 | 1920 | ||
94 | * 29.9700 | 900900 | 3.336667 | 1471,47 | 1601.6 | ||
95 | * 30 | 900000 | 3.333333 | 1470 | 1600 | ||
96 | * | ||
97 | * *Unofficial framerates | ||
98 | * | ||
99 | * (1) But we don't really care since the audio clock is used anyway and has | ||
100 | * very fine resolution ;-) | ||
101 | *****************************************************************************/ | ||
102 | #include "plugin.h" | ||
103 | #include "mpegplayer.h" | ||
104 | #include "lib/helper.h" | ||
105 | #include "mpeg_settings.h" | ||
106 | #include "video_out.h" | ||
107 | #include "stream_thread.h" | ||
108 | #include "stream_mgr.h" | ||
109 | |||
110 | |||
111 | /* button definitions */ | ||
112 | #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) | ||
113 | #define MPEG_MENU BUTTON_MODE | ||
114 | #define MPEG_STOP BUTTON_OFF | ||
115 | #define MPEG_PAUSE BUTTON_ON | ||
116 | #define MPEG_VOLDOWN BUTTON_DOWN | ||
117 | #define MPEG_VOLUP BUTTON_UP | ||
118 | #define MPEG_RW BUTTON_LEFT | ||
119 | #define MPEG_FF BUTTON_RIGHT | ||
120 | |||
121 | #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ | ||
122 | (CONFIG_KEYPAD == IPOD_1G2G_PAD) | ||
123 | #define MPEG_MENU BUTTON_MENU | ||
124 | #define MPEG_PAUSE (BUTTON_PLAY | BUTTON_REL) | ||
125 | #define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT) | ||
126 | #define MPEG_VOLDOWN BUTTON_SCROLL_BACK | ||
127 | #define MPEG_VOLUP BUTTON_SCROLL_FWD | ||
128 | #define MPEG_RW BUTTON_LEFT | ||
129 | #define MPEG_FF BUTTON_RIGHT | ||
130 | |||
131 | #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD | ||
132 | #define MPEG_MENU (BUTTON_REC | BUTTON_REL) | ||
133 | #define MPEG_STOP BUTTON_POWER | ||
134 | #define MPEG_PAUSE BUTTON_PLAY | ||
135 | #define MPEG_VOLDOWN BUTTON_DOWN | ||
136 | #define MPEG_VOLUP BUTTON_UP | ||
137 | #define MPEG_RW BUTTON_LEFT | ||
138 | #define MPEG_FF BUTTON_RIGHT | ||
139 | |||
140 | #elif CONFIG_KEYPAD == GIGABEAT_PAD | ||
141 | #define MPEG_MENU BUTTON_MENU | ||
142 | #define MPEG_STOP BUTTON_POWER | ||
143 | #define MPEG_PAUSE BUTTON_SELECT | ||
144 | #define MPEG_PAUSE2 BUTTON_A | ||
145 | #define MPEG_VOLDOWN BUTTON_LEFT | ||
146 | #define MPEG_VOLUP BUTTON_RIGHT | ||
147 | #define MPEG_VOLDOWN2 BUTTON_VOL_DOWN | ||
148 | #define MPEG_VOLUP2 BUTTON_VOL_UP | ||
149 | #define MPEG_RW BUTTON_UP | ||
150 | #define MPEG_FF BUTTON_DOWN | ||
151 | |||
152 | #define MPEG_RC_MENU BUTTON_RC_DSP | ||
153 | #define MPEG_RC_STOP (BUTTON_RC_PLAY | BUTTON_REPEAT) | ||
154 | #define MPEG_RC_PAUSE (BUTTON_RC_PLAY | BUTTON_REL) | ||
155 | #define MPEG_RC_VOLDOWN BUTTON_RC_VOL_DOWN | ||
156 | #define MPEG_RC_VOLUP BUTTON_RC_VOL_UP | ||
157 | #define MPEG_RC_RW BUTTON_RC_REW | ||
158 | #define MPEG_RC_FF BUTTON_RC_FF | ||
159 | |||
160 | #elif CONFIG_KEYPAD == GIGABEAT_S_PAD | ||
161 | #define MPEG_MENU BUTTON_MENU | ||
162 | #define MPEG_STOP BUTTON_POWER | ||
163 | #define MPEG_PAUSE BUTTON_SELECT | ||
164 | #define MPEG_PAUSE2 BUTTON_PLAY | ||
165 | #define MPEG_VOLDOWN BUTTON_LEFT | ||
166 | #define MPEG_VOLUP BUTTON_RIGHT | ||
167 | #define MPEG_VOLDOWN2 BUTTON_VOL_DOWN | ||
168 | #define MPEG_VOLUP2 BUTTON_VOL_UP | ||
169 | #define MPEG_RW BUTTON_UP | ||
170 | #define MPEG_RW2 BUTTON_PREV | ||
171 | #define MPEG_FF BUTTON_DOWN | ||
172 | #define MPEG_FF2 BUTTON_NEXT | ||
173 | #define MPEG_SHOW_OSD BUTTON_BACK | ||
174 | |||
175 | #define MPEG_RC_MENU BUTTON_RC_DSP | ||
176 | #define MPEG_RC_STOP (BUTTON_RC_PLAY | BUTTON_REPEAT) | ||
177 | #define MPEG_RC_PAUSE (BUTTON_RC_PLAY | BUTTON_REL) | ||
178 | #define MPEG_RC_VOLDOWN BUTTON_RC_VOL_DOWN | ||
179 | #define MPEG_RC_VOLUP BUTTON_RC_VOL_UP | ||
180 | #define MPEG_RC_RW BUTTON_RC_REW | ||
181 | #define MPEG_RC_FF BUTTON_RC_FF | ||
182 | |||
183 | #elif CONFIG_KEYPAD == IRIVER_H10_PAD | ||
184 | #define MPEG_MENU BUTTON_LEFT | ||
185 | #define MPEG_STOP BUTTON_POWER | ||
186 | #define MPEG_PAUSE BUTTON_PLAY | ||
187 | #define MPEG_VOLDOWN BUTTON_SCROLL_DOWN | ||
188 | #define MPEG_VOLUP BUTTON_SCROLL_UP | ||
189 | #define MPEG_RW BUTTON_REW | ||
190 | #define MPEG_FF BUTTON_FF | ||
191 | |||
192 | #elif CONFIG_KEYPAD == SANSA_E200_PAD | ||
193 | #define MPEG_MENU BUTTON_SELECT | ||
194 | #define MPEG_STOP BUTTON_POWER | ||
195 | #define MPEG_PAUSE BUTTON_RIGHT | ||
196 | #define MPEG_VOLDOWN BUTTON_SCROLL_BACK | ||
197 | #define MPEG_VOLUP BUTTON_SCROLL_FWD | ||
198 | #define MPEG_RW BUTTON_UP | ||
199 | #define MPEG_FF BUTTON_DOWN | ||
200 | |||
201 | #elif CONFIG_KEYPAD == SANSA_FUZE_PAD | ||
202 | #define MPEG_MENU BUTTON_SELECT | ||
203 | #define MPEG_STOP (BUTTON_HOME|BUTTON_REPEAT) | ||
204 | #define MPEG_PAUSE BUTTON_UP | ||
205 | #define MPEG_VOLDOWN BUTTON_SCROLL_BACK | ||
206 | #define MPEG_VOLUP BUTTON_SCROLL_FWD | ||
207 | #define MPEG_RW BUTTON_LEFT | ||
208 | #define MPEG_FF BUTTON_RIGHT | ||
209 | |||
210 | |||
211 | #elif CONFIG_KEYPAD == SANSA_C200_PAD || \ | ||
212 | CONFIG_KEYPAD == SANSA_CLIP_PAD || \ | ||
213 | CONFIG_KEYPAD == SANSA_M200_PAD | ||
214 | #define MPEG_MENU BUTTON_SELECT | ||
215 | #define MPEG_STOP BUTTON_POWER | ||
216 | #define MPEG_PAUSE BUTTON_UP | ||
217 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
218 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
219 | #define MPEG_RW BUTTON_LEFT | ||
220 | #define MPEG_FF BUTTON_RIGHT | ||
221 | |||
222 | #elif CONFIG_KEYPAD == MROBE500_PAD | ||
223 | #define MPEG_STOP BUTTON_POWER | ||
224 | |||
225 | #define MPEG_RC_MENU BUTTON_RC_HEART | ||
226 | #define MPEG_RC_STOP BUTTON_RC_DOWN | ||
227 | #define MPEG_RC_PAUSE BUTTON_RC_PLAY | ||
228 | #define MPEG_RC_VOLDOWN BUTTON_RC_VOL_DOWN | ||
229 | #define MPEG_RC_VOLUP BUTTON_RC_VOL_UP | ||
230 | #define MPEG_RC_RW BUTTON_RC_REW | ||
231 | #define MPEG_RC_FF BUTTON_RC_FF | ||
232 | |||
233 | #elif CONFIG_KEYPAD == MROBE100_PAD | ||
234 | #define MPEG_MENU BUTTON_MENU | ||
235 | #define MPEG_STOP BUTTON_POWER | ||
236 | #define MPEG_PAUSE BUTTON_PLAY | ||
237 | #define MPEG_VOLDOWN BUTTON_DOWN | ||
238 | #define MPEG_VOLUP BUTTON_UP | ||
239 | #define MPEG_RW BUTTON_LEFT | ||
240 | #define MPEG_FF BUTTON_RIGHT | ||
241 | |||
242 | #elif CONFIG_KEYPAD == IAUDIO_M3_PAD | ||
243 | #define MPEG_MENU BUTTON_RC_MENU | ||
244 | #define MPEG_STOP BUTTON_RC_REC | ||
245 | #define MPEG_PAUSE BUTTON_RC_PLAY | ||
246 | #define MPEG_VOLDOWN BUTTON_RC_VOL_DOWN | ||
247 | #define MPEG_VOLUP BUTTON_RC_VOL_UP | ||
248 | #define MPEG_RW BUTTON_RC_REW | ||
249 | #define MPEG_FF BUTTON_RC_FF | ||
250 | |||
251 | #elif CONFIG_KEYPAD == COWON_D2_PAD | ||
252 | #define MPEG_MENU (BUTTON_MENU|BUTTON_REL) | ||
253 | //#define MPEG_STOP BUTTON_POWER | ||
254 | #define MPEG_VOLDOWN BUTTON_MINUS | ||
255 | #define MPEG_VOLUP BUTTON_PLUS | ||
256 | |||
257 | #elif CONFIG_KEYPAD == CREATIVEZVM_PAD | ||
258 | #define MPEG_MENU BUTTON_MENU | ||
259 | #define MPEG_STOP BUTTON_BACK | ||
260 | #define MPEG_PAUSE BUTTON_PLAY | ||
261 | #define MPEG_VOLDOWN BUTTON_UP | ||
262 | #define MPEG_VOLUP BUTTON_DOWN | ||
263 | #define MPEG_RW BUTTON_LEFT | ||
264 | #define MPEG_FF BUTTON_RIGHT | ||
265 | |||
266 | #elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD | ||
267 | #define MPEG_MENU BUTTON_MENU | ||
268 | #define MPEG_STOP (BUTTON_PLAY|BUTTON_REPEAT) | ||
269 | #define MPEG_PAUSE (BUTTON_PLAY|BUTTON_REL) | ||
270 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
271 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
272 | #define MPEG_RW BUTTON_DOWN | ||
273 | #define MPEG_FF BUTTON_UP | ||
274 | |||
275 | #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD | ||
276 | #define MPEG_MENU BUTTON_MENU | ||
277 | #define MPEG_STOP BUTTON_POWER | ||
278 | #define MPEG_PAUSE BUTTON_SELECT | ||
279 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
280 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
281 | #define MPEG_RW BUTTON_LEFT | ||
282 | #define MPEG_FF BUTTON_RIGHT | ||
283 | |||
284 | #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD | ||
285 | #define MPEG_MENU BUTTON_MENU | ||
286 | #define MPEG_STOP BUTTON_POWER | ||
287 | #define MPEG_PAUSE BUTTON_PLAY | ||
288 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
289 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
290 | #define MPEG_RW BUTTON_PREV | ||
291 | #define MPEG_FF BUTTON_NEXT | ||
292 | |||
293 | #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD | ||
294 | #define MPEG_MENU BUTTON_MENU | ||
295 | #define MPEG_STOP BUTTON_POWER | ||
296 | #define MPEG_PAUSE BUTTON_PLAY | ||
297 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
298 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
299 | #define MPEG_RW BUTTON_UP | ||
300 | #define MPEG_FF BUTTON_DOWN | ||
301 | |||
302 | #elif CONFIG_KEYPAD == ONDAVX747_PAD | ||
303 | #define MPEG_MENU (BUTTON_MENU|BUTTON_REL) | ||
304 | //#define MPEG_STOP BUTTON_POWER | ||
305 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
306 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
307 | |||
308 | #elif CONFIG_KEYPAD == ONDAVX777_PAD | ||
309 | #define MPEG_MENU BUTTON_POWER | ||
310 | |||
311 | #elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) || \ | ||
312 | (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD) | ||
313 | #define MPEG_MENU BUTTON_REW | ||
314 | #define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT) | ||
315 | #define MPEG_PAUSE (BUTTON_PLAY | BUTTON_REL) | ||
316 | #define MPEG_VOLDOWN BUTTON_DOWN | ||
317 | #define MPEG_VOLUP BUTTON_UP | ||
318 | #define MPEG_RW BUTTON_LEFT | ||
319 | #define MPEG_FF BUTTON_RIGHT | ||
320 | #define MPEG_SHOW_OSD BUTTON_FFWD | ||
321 | |||
322 | #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD | ||
323 | #define MPEG_MENU BUTTON_MENU | ||
324 | #define MPEG_STOP BUTTON_REC | ||
325 | #define MPEG_PAUSE BUTTON_PLAY | ||
326 | #define MPEG_VOLDOWN BUTTON_DOWN | ||
327 | #define MPEG_VOLUP BUTTON_UP | ||
328 | #define MPEG_RW BUTTON_PREV | ||
329 | #define MPEG_FF BUTTON_NEXT | ||
330 | |||
331 | #elif CONFIG_KEYPAD == MPIO_HD200_PAD | ||
332 | #define MPEG_MENU BUTTON_FUNC | ||
333 | #define MPEG_PAUSE (BUTTON_PLAY | BUTTON_REL) | ||
334 | #define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT) | ||
335 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
336 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
337 | #define MPEG_RW BUTTON_REW | ||
338 | #define MPEG_FF BUTTON_FF | ||
339 | |||
340 | #elif CONFIG_KEYPAD == MPIO_HD300_PAD | ||
341 | #define MPEG_MENU BUTTON_MENU | ||
342 | #define MPEG_PAUSE (BUTTON_PLAY | BUTTON_REL) | ||
343 | #define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT) | ||
344 | #define MPEG_VOLDOWN BUTTON_DOWN | ||
345 | #define MPEG_VOLUP BUTTON_UP | ||
346 | #define MPEG_RW BUTTON_REW | ||
347 | #define MPEG_FF BUTTON_FF | ||
348 | |||
349 | #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD | ||
350 | #define MPEG_MENU BUTTON_POWER | ||
351 | #define MPEG_PAUSE (BUTTON_PLAYPAUSE | BUTTON_REL) | ||
352 | #define MPEG_STOP (BUTTON_PLAYPAUSE | BUTTON_REPEAT) | ||
353 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
354 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
355 | #define MPEG_RW BUTTON_LEFT | ||
356 | #define MPEG_FF BUTTON_RIGHT | ||
357 | |||
358 | #elif CONFIG_KEYPAD == SANSA_CONNECT_PAD | ||
359 | #define MPEG_MENU BUTTON_POWER | ||
360 | #define MPEG_PAUSE (BUTTON_SELECT | BUTTON_REL) | ||
361 | #define MPEG_STOP (BUTTON_SELECT | BUTTON_REPEAT) | ||
362 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
363 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
364 | #define MPEG_RW BUTTON_LEFT | ||
365 | #define MPEG_FF BUTTON_RIGHT | ||
366 | |||
367 | #elif CONFIG_KEYPAD == SAMSUNG_YPR0_PAD | ||
368 | #define MPEG_MENU BUTTON_MENU | ||
369 | #define MPEG_PAUSE BUTTON_SELECT | ||
370 | #define MPEG_STOP BUTTON_POWER | ||
371 | #define MPEG_VOLDOWN BUTTON_DOWN | ||
372 | #define MPEG_VOLUP BUTTON_UP | ||
373 | #define MPEG_RW BUTTON_LEFT | ||
374 | #define MPEG_FF BUTTON_RIGHT | ||
375 | |||
376 | #elif CONFIG_KEYPAD == HM60X_PAD | ||
377 | #define MPEG_MENU BUTTON_POWER | ||
378 | #define MPEG_PAUSE BUTTON_SELECT | ||
379 | #define MPEG_STOP (BUTTON_SELECT | BUTTON_POWER) | ||
380 | #define MPEG_VOLDOWN (BUTTON_POWER | BUTTON_DOWN) | ||
381 | #define MPEG_VOLUP (BUTTON_POWER | BUTTON_UP) | ||
382 | #define MPEG_RW BUTTON_LEFT | ||
383 | #define MPEG_FF BUTTON_RIGHT | ||
384 | |||
385 | #elif CONFIG_KEYPAD == HM801_PAD | ||
386 | #define MPEG_MENU BUTTON_POWER | ||
387 | #define MPEG_PAUSE BUTTON_PLAY | ||
388 | #define MPEG_STOP (BUTTON_POWER | BUTTON_PLAY) | ||
389 | #define MPEG_VOLDOWN (BUTTON_POWER | BUTTON_DOWN) | ||
390 | #define MPEG_VOLUP (BUTTON_POWER | BUTTON_UP) | ||
391 | #define MPEG_RW BUTTON_PREV | ||
392 | #define MPEG_FF BUTTON_NEXT | ||
393 | |||
394 | #elif CONFIG_KEYPAD == SONY_NWZ_PAD | ||
395 | #define MPEG_MENU BUTTON_BACK | ||
396 | #define MPEG_PAUSE BUTTON_PLAY | ||
397 | #define MPEG_STOP BUTTON_POWER | ||
398 | #define MPEG_VOLDOWN BUTTON_UP | ||
399 | #define MPEG_VOLUP BUTTON_DOWN | ||
400 | #define MPEG_RW BUTTON_LEFT | ||
401 | #define MPEG_FF BUTTON_RIGHT | ||
402 | |||
403 | #elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD | ||
404 | #define MPEG_MENU BUTTON_MENU | ||
405 | #define MPEG_PAUSE BUTTON_PLAYPAUSE | ||
406 | #define MPEG_STOP BUTTON_BACK | ||
407 | #define MPEG_VOLDOWN BUTTON_DOWN | ||
408 | #define MPEG_VOLUP BUTTON_UP | ||
409 | #define MPEG_RW BUTTON_LEFT | ||
410 | #define MPEG_FF BUTTON_RIGHT | ||
411 | |||
412 | #elif CONFIG_KEYPAD == DX50_PAD | ||
413 | #define MPEG_MENU BUTTON_POWER | ||
414 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
415 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
416 | #define MPEG_RW BUTTON_LEFT | ||
417 | #define MPEG_FF BUTTON_RIGHT | ||
418 | #define MPEG_PAUSE BUTTON_PLAY | ||
419 | #define MPEG_STOP (BUTTON_PLAY|BUTTON_REPEAT) | ||
420 | |||
421 | #elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD | ||
422 | #define MPEG_MENU BUTTON_POWER | ||
423 | #define MPEG_PAUSE BUTTON_MENU | ||
424 | #define MPEG_STOP (BUTTON_MENU|BUTTON_REPEAT) | ||
425 | |||
426 | #elif CONFIG_KEYPAD == AGPTEK_ROCKER_PAD | ||
427 | #define MPEG_MENU BUTTON_POWER | ||
428 | #define MPEG_PAUSE BUTTON_SELECT | ||
429 | #define MPEG_STOP BUTTON_DOWN | ||
430 | #define MPEG_VOLDOWN BUTTON_VOLDOWN | ||
431 | #define MPEG_VOLUP BUTTON_VOLUP | ||
432 | #define MPEG_RW BUTTON_LEFT | ||
433 | #define MPEG_FF BUTTON_RIGHT | ||
434 | |||
435 | #elif CONFIG_KEYPAD == XDUOO_X3_PAD | ||
436 | #define MPEG_MENU BUTTON_PLAY | ||
437 | #define MPEG_STOP BUTTON_POWER | ||
438 | #define MPEG_PAUSE BUTTON_HOME | ||
439 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
440 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
441 | #define MPEG_RW BUTTON_PREV | ||
442 | #define MPEG_FF BUTTON_NEXT | ||
443 | |||
444 | #elif CONFIG_KEYPAD == XDUOO_X3II_PAD || CONFIG_KEYPAD == XDUOO_X20_PAD | ||
445 | #define MPEG_MENU BUTTON_PLAY | ||
446 | #define MPEG_STOP BUTTON_POWER | ||
447 | #define MPEG_PAUSE BUTTON_HOME | ||
448 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
449 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
450 | #define MPEG_RW BUTTON_PREV | ||
451 | #define MPEG_FF BUTTON_NEXT | ||
452 | |||
453 | #elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD | ||
454 | #define MPEG_MENU BUTTON_PLAY | ||
455 | #define MPEG_STOP BUTTON_POWER | ||
456 | #define MPEG_PAUSE BUTTON_HOME | ||
457 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
458 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
459 | #define MPEG_RW BUTTON_PREV | ||
460 | #define MPEG_FF BUTTON_NEXT | ||
461 | |||
462 | #elif CONFIG_KEYPAD == IHIFI_770_PAD || CONFIG_KEYPAD == IHIFI_800_PAD | ||
463 | #define MPEG_MENU BUTTON_PLAY | ||
464 | #define MPEG_STOP BUTTON_POWER | ||
465 | #define MPEG_PAUSE BUTTON_HOME | ||
466 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
467 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
468 | #define MPEG_RW BUTTON_PREV | ||
469 | #define MPEG_FF BUTTON_NEXT | ||
470 | |||
471 | #elif CONFIG_KEYPAD == EROSQ_PAD | ||
472 | #define MPEG_MENU BUTTON_MENU | ||
473 | #define MPEG_STOP BUTTON_POWER | ||
474 | #define MPEG_PAUSE BUTTON_PLAY | ||
475 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
476 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
477 | #define MPEG_RW BUTTON_PREV | ||
478 | #define MPEG_FF BUTTON_NEXT | ||
479 | |||
480 | #elif CONFIG_KEYPAD == FIIO_M3K_PAD | ||
481 | #define MPEG_MENU BUTTON_MENU | ||
482 | #define MPEG_STOP BUTTON_POWER | ||
483 | #define MPEG_PAUSE BUTTON_PLAY | ||
484 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | ||
485 | #define MPEG_VOLUP BUTTON_VOL_UP | ||
486 | #define MPEG_RW BUTTON_LEFT | ||
487 | #define MPEG_FF BUTTON_RIGHT | ||
488 | |||
489 | #elif CONFIG_KEYPAD == SHANLING_Q1_PAD | ||
490 | /* use touchscreen */ | ||
491 | |||
492 | #else | ||
493 | #error No keymap defined! | ||
494 | #endif | ||
495 | |||
496 | #ifdef HAVE_TOUCHSCREEN | ||
497 | #ifndef MPEG_MENU | ||
498 | #define MPEG_MENU (BUTTON_TOPRIGHT|BUTTON_REL) | ||
499 | #endif | ||
500 | #ifndef MPEG_STOP | ||
501 | #define MPEG_STOP BUTTON_TOPLEFT | ||
502 | #endif | ||
503 | #ifndef MPEG_PAUSE | ||
504 | #define MPEG_PAUSE BUTTON_CENTER | ||
505 | #endif | ||
506 | #ifndef MPEG_VOLDOWN | ||
507 | #define MPEG_VOLDOWN BUTTON_BOTTOMMIDDLE | ||
508 | #endif | ||
509 | #ifndef MPEG_VOLUP | ||
510 | #define MPEG_VOLUP BUTTON_TOPMIDDLE | ||
511 | #endif | ||
512 | #ifndef MPEG_RW | ||
513 | #define MPEG_RW BUTTON_MIDLEFT | ||
514 | #endif | ||
515 | #ifndef MPEG_FF | ||
516 | #define MPEG_FF BUTTON_MIDRIGHT | ||
517 | #endif | ||
518 | #endif | ||
519 | |||
520 | /* One thing we can do here for targets with remotes is having a display | ||
521 | * always on the remote instead of always forcing a popup on the main display */ | ||
522 | |||
523 | #define FF_REWIND_MAX_PERCENT 3 /* cap ff/rewind step size at max % of file */ | ||
524 | /* 3% of 30min file == 54s step size */ | ||
525 | #define MIN_FF_REWIND_STEP (TS_SECOND/2) | ||
526 | #define OSD_MIN_UPDATE_INTERVAL (HZ/2) | ||
527 | #define FPS_UPDATE_INTERVAL (HZ) /* Get new FPS reading each second */ | ||
528 | |||
529 | enum video_action | ||
530 | { | ||
531 | VIDEO_STOP = 0, | ||
532 | VIDEO_PREV, | ||
533 | VIDEO_NEXT, | ||
534 | VIDEO_ACTION_MANUAL = 0x8000, /* Flag that says user did it */ | ||
535 | }; | ||
536 | |||
537 | /* OSD status - same order as icon array */ | ||
538 | enum osd_status_enum | ||
539 | { | ||
540 | OSD_STATUS_STOPPED = 0, | ||
541 | OSD_STATUS_PAUSED, | ||
542 | OSD_STATUS_PLAYING, | ||
543 | OSD_STATUS_FF, | ||
544 | OSD_STATUS_RW, | ||
545 | OSD_STATUS_COUNT, | ||
546 | OSD_STATUS_MASK = 0x7 | ||
547 | }; | ||
548 | |||
549 | enum osd_bits | ||
550 | { | ||
551 | OSD_REFRESH_DEFAULT = 0x0000, /* Only refresh elements when due */ | ||
552 | /* Refresh the... */ | ||
553 | OSD_REFRESH_VOLUME = 0x0001, /* ...volume display */ | ||
554 | OSD_REFRESH_TIME = 0x0002, /* ...time display+progress */ | ||
555 | OSD_REFRESH_STATUS = 0x0004, /* ...playback status icon */ | ||
556 | OSD_REFRESH_BACKGROUND = 0x0008, /* ...background (implies ALL) */ | ||
557 | OSD_REFRESH_VIDEO = 0x0010, /* ...video image upon timeout */ | ||
558 | OSD_REFRESH_RESUME = 0x0020, /* Resume playback upon timeout */ | ||
559 | OSD_NODRAW = 0x8000, /* OR bitflag - don't draw anything */ | ||
560 | OSD_SHOW = 0x4000, /* OR bitflag - show the OSD */ | ||
561 | #ifdef HAVE_HEADPHONE_DETECTION | ||
562 | OSD_HP_PAUSE = 0x2000, /* OR bitflag - headphones caused pause */ | ||
563 | #endif | ||
564 | OSD_HIDE = 0x0000, /* hide the OSD (aid readability) */ | ||
565 | OSD_REFRESH_ALL = 0x000f, /* Only immediate graphical elements */ | ||
566 | }; | ||
567 | |||
568 | /* Status icons selected according to font height */ | ||
569 | extern const unsigned char mpegplayer_status_icons_8x8x1[]; | ||
570 | extern const unsigned char mpegplayer_status_icons_12x12x1[]; | ||
571 | extern const unsigned char mpegplayer_status_icons_16x16x1[]; | ||
572 | |||
573 | /* Main border areas that contain OSD elements */ | ||
574 | #define OSD_BDR_L 2 | ||
575 | #define OSD_BDR_T 2 | ||
576 | #define OSD_BDR_R 2 | ||
577 | #define OSD_BDR_B 2 | ||
578 | |||
579 | struct osd | ||
580 | { | ||
581 | long hide_tick; | ||
582 | long show_for; | ||
583 | long print_tick; | ||
584 | long print_delay; | ||
585 | long resume_tick; | ||
586 | long resume_delay; | ||
587 | long next_auto_refresh; | ||
588 | int x; | ||
589 | int y; | ||
590 | int width; | ||
591 | int height; | ||
592 | unsigned fgcolor; | ||
593 | unsigned bgcolor; | ||
594 | unsigned prog_fillcolor; | ||
595 | struct vo_rect update_rect; | ||
596 | struct vo_rect prog_rect; | ||
597 | struct vo_rect time_rect; | ||
598 | struct vo_rect dur_rect; | ||
599 | struct vo_rect vol_rect; | ||
600 | const unsigned char *icons; | ||
601 | struct vo_rect stat_rect; | ||
602 | int status; | ||
603 | uint32_t curr_time; | ||
604 | unsigned auto_refresh; | ||
605 | unsigned flags; | ||
606 | int font; | ||
607 | }; | ||
608 | |||
609 | struct fps | ||
610 | { | ||
611 | /* FPS Display */ | ||
612 | struct vo_rect rect; /* OSD coordinates */ | ||
613 | int pf_x; /* Screen coordinates */ | ||
614 | int pf_y; | ||
615 | int pf_width; | ||
616 | int pf_height; | ||
617 | long update_tick; /* When to next update FPS reading */ | ||
618 | #define FPS_FORMAT "%d.%02d" | ||
619 | #define FPS_DIMSTR "999.99" /* For establishing rect size */ | ||
620 | #define FPS_BUFSIZE sizeof("999.99") | ||
621 | }; | ||
622 | |||
623 | static struct osd osd; | ||
624 | static struct fps fps NOCACHEBSS_ATTR; /* Accessed on other processor */ | ||
625 | |||
626 | #ifdef LCD_PORTRAIT | ||
627 | static fb_data* get_framebuffer(void) | ||
628 | { | ||
629 | struct viewport *vp_main = *(rb->screens[SCREEN_MAIN]->current_viewport); | ||
630 | return vp_main->buffer->fb_ptr; | ||
631 | } | ||
632 | #endif | ||
633 | |||
634 | static void osd_show(unsigned show); | ||
635 | |||
636 | #ifdef LCD_LANDSCAPE | ||
637 | #define __X (x + osd.x) | ||
638 | #define __Y (y + osd.y) | ||
639 | #define __W width | ||
640 | #define __H height | ||
641 | #else | ||
642 | #define __X (LCD_WIDTH - (y + osd.y) - height) | ||
643 | #define __Y (x + osd.x) | ||
644 | #define __W height | ||
645 | #define __H width | ||
646 | #endif | ||
647 | |||
648 | #ifdef HAVE_LCD_COLOR | ||
649 | /* Blend two colors in 0-100% (0-255) mix of c2 into c1 */ | ||
650 | static unsigned draw_blendcolor(unsigned c1, unsigned c2, unsigned char amount) | ||
651 | { | ||
652 | int r1 = RGB_UNPACK_RED(c1); | ||
653 | int g1 = RGB_UNPACK_GREEN(c1); | ||
654 | int b1 = RGB_UNPACK_BLUE(c1); | ||
655 | |||
656 | int r2 = RGB_UNPACK_RED(c2); | ||
657 | int g2 = RGB_UNPACK_GREEN(c2); | ||
658 | int b2 = RGB_UNPACK_BLUE(c2); | ||
659 | |||
660 | return LCD_RGBPACK(amount*(r2 - r1) / 255 + r1, | ||
661 | amount*(g2 - g1) / 255 + g1, | ||
662 | amount*(b2 - b1) / 255 + b1); | ||
663 | } | ||
664 | #endif | ||
665 | |||
666 | #ifdef PLUGIN_USE_IRAM | ||
667 | /* IRAM preserving mechanism to enable talking menus */ | ||
668 | static char *iram_saved_copy; | ||
669 | extern char iramstart[], iramend[]; | ||
670 | |||
671 | static void iram_saving_init(void) | ||
672 | { | ||
673 | #ifndef SIMULATOR | ||
674 | size_t size; | ||
675 | iram_saved_copy = (char *)rb->plugin_get_buffer(&size); | ||
676 | |||
677 | if (size >= (size_t)(iramend-iramstart)) | ||
678 | iram_saved_copy += size - (size_t)(iramend - iramstart); | ||
679 | else | ||
680 | #endif | ||
681 | iram_saved_copy = NULL; | ||
682 | |||
683 | return; | ||
684 | } | ||
685 | |||
686 | void mpegplayer_iram_preserve(void) | ||
687 | { | ||
688 | if (iram_saved_copy) | ||
689 | { | ||
690 | rb->memcpy(iram_saved_copy, iramstart, iramend-iramstart); | ||
691 | #ifdef HAVE_CPUCACHE_INVALIDATE | ||
692 | /* make the icache (if it exists) up to date with the new code */ | ||
693 | rb->cpucache_invalidate(); | ||
694 | #endif /* HAVE_CPUCACHE_INVALIDATE */ | ||
695 | } | ||
696 | return; | ||
697 | } | ||
698 | |||
699 | void mpegplayer_iram_restore(void) | ||
700 | { | ||
701 | if (iram_saved_copy) | ||
702 | { | ||
703 | rb->audio_hard_stop(); | ||
704 | rb->memcpy(iramstart, iram_saved_copy, iramend-iramstart); | ||
705 | #ifdef HAVE_CPUCACHE_INVALIDATE | ||
706 | /* make the icache (if it exists) up to date with the new code */ | ||
707 | rb->cpucache_invalidate(); | ||
708 | #endif /* HAVE_CPUCACHE_INVALIDATE */ | ||
709 | } | ||
710 | return; | ||
711 | } | ||
712 | #endif | ||
713 | |||
714 | /* Drawing functions that operate rotated on LCD_PORTRAIT displays - | ||
715 | * most are just wrappers of lcd_* functions with transforms applied. | ||
716 | * The origin is the upper-left corner of the OSD area */ | ||
717 | static void draw_update_rect(int x, int y, int width, int height) | ||
718 | { | ||
719 | mylcd_update_rect(__X, __Y, __W, __H); | ||
720 | } | ||
721 | |||
722 | static void draw_clear_area(int x, int y, int width, int height) | ||
723 | { | ||
724 | #ifdef HAVE_LCD_COLOR | ||
725 | rb->screen_clear_area(rb->screens[SCREEN_MAIN], __X, __Y, __W, __H); | ||
726 | #else | ||
727 | int oldmode = grey_get_drawmode(); | ||
728 | grey_set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID); | ||
729 | grey_fillrect(__X, __Y, __W, __H); | ||
730 | grey_set_drawmode(oldmode); | ||
731 | #endif | ||
732 | } | ||
733 | |||
734 | static void draw_clear_area_rect(const struct vo_rect *rc) | ||
735 | { | ||
736 | draw_clear_area(rc->l, rc->t, rc->r - rc->l, rc->b - rc->t); | ||
737 | } | ||
738 | |||
739 | static void draw_fillrect(int x, int y, int width, int height) | ||
740 | { | ||
741 | mylcd_fillrect(__X, __Y, __W, __H); | ||
742 | } | ||
743 | |||
744 | static void draw_hline(int x1, int x2, int y) | ||
745 | { | ||
746 | #ifdef LCD_LANDSCAPE | ||
747 | mylcd_hline(x1 + osd.x, x2 + osd.x, y + osd.y); | ||
748 | #else | ||
749 | y = LCD_WIDTH - (y + osd.y) - 1; | ||
750 | mylcd_vline(y, x1 + osd.x, x2 + osd.x); | ||
751 | #endif | ||
752 | } | ||
753 | |||
754 | static void draw_vline(int x, int y1, int y2) | ||
755 | { | ||
756 | #ifdef LCD_LANDSCAPE | ||
757 | mylcd_vline(x + osd.x, y1 + osd.y, y2 + osd.y); | ||
758 | #else | ||
759 | y1 = LCD_WIDTH - (y1 + osd.y) - 1; | ||
760 | y2 = LCD_WIDTH - (y2 + osd.y) - 1; | ||
761 | mylcd_hline(y1, y2, x + osd.x); | ||
762 | #endif | ||
763 | } | ||
764 | |||
765 | static void draw_scrollbar_draw(int x, int y, int width, int height, | ||
766 | uint32_t min, uint32_t max, uint32_t val) | ||
767 | { | ||
768 | unsigned oldfg = mylcd_get_foreground(); | ||
769 | |||
770 | draw_hline(x + 1, x + width - 2, y); | ||
771 | draw_hline(x + 1, x + width - 2, y + height - 1); | ||
772 | draw_vline(x, y + 1, y + height - 2); | ||
773 | draw_vline(x + width - 1, y + 1, y + height - 2); | ||
774 | |||
775 | val = muldiv_uint32(width - 2, val, max - min); | ||
776 | val = MIN(val, (uint32_t)(width - 2)); | ||
777 | |||
778 | draw_fillrect(x + 1, y + 1, val, height - 2); | ||
779 | |||
780 | mylcd_set_foreground(osd.prog_fillcolor); | ||
781 | |||
782 | draw_fillrect(x + 1 + val, y + 1, width - 2 - val, height - 2); | ||
783 | |||
784 | mylcd_set_foreground(oldfg); | ||
785 | } | ||
786 | |||
787 | static void draw_scrollbar_draw_rect(const struct vo_rect *rc, int min, | ||
788 | int max, int val) | ||
789 | { | ||
790 | draw_scrollbar_draw(rc->l, rc->t, rc->r - rc->l, rc->b - rc->t, | ||
791 | min, max, val); | ||
792 | } | ||
793 | |||
794 | static void draw_setfont(int font) | ||
795 | { | ||
796 | osd.font = font; | ||
797 | mylcd_setfont(font); | ||
798 | } | ||
799 | |||
800 | #ifdef LCD_PORTRAIT | ||
801 | /* Portrait displays need rotated text rendering */ | ||
802 | |||
803 | /* Limited function that only renders in DRMODE_FG and uses absolute screen | ||
804 | * coordinates */ | ||
805 | static void draw_oriented_mono_bitmap_part(const unsigned char *src, | ||
806 | int src_x, int src_y, | ||
807 | int stride, int x, int y, | ||
808 | int width, int height) | ||
809 | { | ||
810 | const unsigned char *src_end; | ||
811 | fb_data *dst, *dst_end; | ||
812 | unsigned fg_pattern; | ||
813 | |||
814 | if (x + width > SCREEN_WIDTH) | ||
815 | width = SCREEN_WIDTH - x; /* Clip right */ | ||
816 | if (x < 0) | ||
817 | width += x, x = 0; /* Clip left */ | ||
818 | if (width <= 0) | ||
819 | return; /* nothing left to do */ | ||
820 | |||
821 | if (y + height > SCREEN_HEIGHT) | ||
822 | height = SCREEN_HEIGHT - y; /* Clip bottom */ | ||
823 | if (y < 0) | ||
824 | height += y, y = 0; /* Clip top */ | ||
825 | if (height <= 0) | ||
826 | return; /* nothing left to do */ | ||
827 | |||
828 | fg_pattern = rb->lcd_get_foreground(); | ||
829 | /*bg_pattern =*/ rb->lcd_get_background(); | ||
830 | |||
831 | src += stride * (src_y >> 3) + src_x; /* move starting point */ | ||
832 | src_y &= 7; | ||
833 | src_end = src + width; | ||
834 | |||
835 | dst = get_framebuffer() + (LCD_WIDTH - y) + x*LCD_WIDTH; | ||
836 | do | ||
837 | { | ||
838 | const unsigned char *src_col = src++; | ||
839 | unsigned data = *src_col >> src_y; | ||
840 | int numbits = 8 - src_y; | ||
841 | |||
842 | fb_data *dst_col = dst; | ||
843 | dst_end = dst_col - height; | ||
844 | dst += LCD_WIDTH; | ||
845 | |||
846 | do | ||
847 | { | ||
848 | dst_col--; | ||
849 | |||
850 | if (data & 1) | ||
851 | *dst_col = FB_SCALARPACK(fg_pattern); | ||
852 | #if 0 | ||
853 | else | ||
854 | *dst_col = bg_pattern; | ||
855 | #endif | ||
856 | data >>= 1; | ||
857 | if (--numbits == 0) { | ||
858 | src_col += stride; | ||
859 | data = *src_col; | ||
860 | numbits = 8; | ||
861 | } | ||
862 | } | ||
863 | while (dst_col > dst_end); | ||
864 | } | ||
865 | while (src < src_end); | ||
866 | } | ||
867 | |||
868 | |||
869 | #define ALPHA_COLOR_FONT_DEPTH 2 | ||
870 | #define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH) | ||
871 | #define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1) | ||
872 | #define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH) | ||
873 | #define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH) | ||
874 | #ifdef CPU_ARM | ||
875 | #define BLEND_INIT do {} while (0) | ||
876 | #define BLEND_FINISH do {} while(0) | ||
877 | #define BLEND_START(acc, color, alpha) \ | ||
878 | asm volatile("mul %0, %1, %2" : "=&r" (acc) : "r" (color), "r" (alpha)) | ||
879 | #define BLEND_CONT(acc, color, alpha) \ | ||
880 | asm volatile("mla %0, %1, %2, %0" : "+&r" (acc) : "r" (color), "r" (alpha)) | ||
881 | #define BLEND_OUT(acc) do {} while (0) | ||
882 | #elif defined(CPU_COLDFIRE) | ||
883 | #define ALPHA_BITMAP_READ_WORDS | ||
884 | #define BLEND_INIT \ | ||
885 | unsigned long _macsr = coldfire_get_macsr(); \ | ||
886 | coldfire_set_macsr(EMAC_UNSIGNED) | ||
887 | #define BLEND_FINISH \ | ||
888 | coldfire_set_macsr(_macsr) | ||
889 | #define BLEND_START(acc, color, alpha) \ | ||
890 | asm volatile("mac.l %0, %1, %%acc0" :: "%d" (color), "d" (alpha)) | ||
891 | #define BLEND_CONT BLEND_START | ||
892 | #define BLEND_OUT(acc) asm volatile("movclr.l %%acc0, %0" : "=d" (acc)) | ||
893 | #else | ||
894 | #define BLEND_INIT do {} while (0) | ||
895 | #define BLEND_FINISH do {} while(0) | ||
896 | #define BLEND_START(acc, color, alpha) ((acc) = (color) * (alpha)) | ||
897 | #define BLEND_CONT(acc, color, alpha) ((acc) += (color) * (alpha)) | ||
898 | #define BLEND_OUT(acc) do {} while (0) | ||
899 | #endif | ||
900 | |||
901 | /* Blend the given two colors */ | ||
902 | static inline unsigned blend_two_colors(unsigned c1, unsigned c2, unsigned a) | ||
903 | { | ||
904 | #if LCD_DEPTH == 16 | ||
905 | a += a >> (ALPHA_COLOR_LOOKUP_SHIFT - 1); | ||
906 | #if (LCD_PIXELFORMAT == RGB565SWAPPED) | ||
907 | c1 = swap16(c1); | ||
908 | c2 = swap16(c2); | ||
909 | #endif | ||
910 | unsigned c1l = (c1 | (c1 << 16)) & 0x07e0f81f; | ||
911 | unsigned c2l = (c2 | (c2 << 16)) & 0x07e0f81f; | ||
912 | unsigned p; | ||
913 | BLEND_START(p, c1l, a); | ||
914 | BLEND_CONT(p, c2l, ALPHA_COLOR_LOOKUP_SIZE + 1 - a); | ||
915 | BLEND_OUT(p); | ||
916 | p = (p >> ALPHA_COLOR_LOOKUP_SHIFT) & 0x07e0f81f; | ||
917 | p |= (p >> 16); | ||
918 | #if (LCD_PIXELFORMAT == RGB565SWAPPED) | ||
919 | return swap16(p); | ||
920 | #else | ||
921 | return p; | ||
922 | #endif | ||
923 | |||
924 | #else /* LCD_DEPTH == 24 */ | ||
925 | unsigned s = c1; | ||
926 | unsigned d = c2; | ||
927 | unsigned s1 = s & 0xff00ff; | ||
928 | unsigned d1 = d & 0xff00ff; | ||
929 | a += a >> (ALPHA_COLOR_LOOKUP_SHIFT - 1); | ||
930 | d1 = (d1 + ((s1 - d1) * a >> ALPHA_COLOR_LOOKUP_SHIFT)) & 0xff00ff; | ||
931 | s &= 0xff00; | ||
932 | d &= 0xff00; | ||
933 | d = (d + ((s - d) * a >> ALPHA_COLOR_LOOKUP_SHIFT)) & 0xff00; | ||
934 | |||
935 | return d1 | d; | ||
936 | #endif | ||
937 | } | ||
938 | |||
939 | static void draw_oriented_alpha_bitmap_part(const unsigned char *src, | ||
940 | int src_x, int src_y, | ||
941 | int stride, int x, int y, | ||
942 | int width, int height) | ||
943 | { | ||
944 | fb_data *dst, *dst_start; | ||
945 | unsigned fg_pattern; | ||
946 | |||
947 | if (x + width > SCREEN_WIDTH) | ||
948 | width = SCREEN_WIDTH - x; /* Clip right */ | ||
949 | if (x < 0) | ||
950 | width += x, x = 0; /* Clip left */ | ||
951 | if (width <= 0) | ||
952 | return; /* nothing left to do */ | ||
953 | |||
954 | if (y + height > SCREEN_HEIGHT) | ||
955 | height = SCREEN_HEIGHT - y; /* Clip bottom */ | ||
956 | if (y < 0) | ||
957 | height += y, y = 0; /* Clip top */ | ||
958 | if (height <= 0) | ||
959 | return; /* nothing left to do */ | ||
960 | |||
961 | /* initialize blending */ | ||
962 | BLEND_INIT; | ||
963 | |||
964 | fg_pattern = rb->lcd_get_foreground(); | ||
965 | /*bg_pattern=*/ rb->lcd_get_background(); | ||
966 | |||
967 | dst_start = get_framebuffer() + (LCD_WIDTH - y - 1) + x*LCD_WIDTH; | ||
968 | int col, row = height; | ||
969 | unsigned data, pixels; | ||
970 | unsigned skip_end = (stride - width); | ||
971 | unsigned skip_start = src_y * stride + src_x; | ||
972 | |||
973 | #ifdef ALPHA_BITMAP_READ_WORDS | ||
974 | uint32_t *src_w = (uint32_t *)((uintptr_t)src & ~3); | ||
975 | skip_start += ALPHA_COLOR_PIXEL_PER_BYTE * ((uintptr_t)src & 3); | ||
976 | src_w += skip_start / ALPHA_COLOR_PIXEL_PER_WORD; | ||
977 | data = letoh32(*src_w++); | ||
978 | #else | ||
979 | src += skip_start / ALPHA_COLOR_PIXEL_PER_BYTE; | ||
980 | data = *src; | ||
981 | #endif | ||
982 | pixels = skip_start % ALPHA_COLOR_PIXEL_PER_WORD; | ||
983 | data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; | ||
984 | #ifdef ALPHA_BITMAP_READ_WORDS | ||
985 | pixels = 8 - pixels; | ||
986 | #endif | ||
987 | |||
988 | do | ||
989 | { | ||
990 | col = width; | ||
991 | dst = dst_start--; | ||
992 | #ifdef ALPHA_BITMAP_READ_WORDS | ||
993 | #define UPDATE_SRC_ALPHA do { \ | ||
994 | if (--pixels) \ | ||
995 | data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ | ||
996 | else \ | ||
997 | { \ | ||
998 | data = letoh32(*src_w++); \ | ||
999 | pixels = ALPHA_COLOR_PIXEL_PER_WORD; \ | ||
1000 | } \ | ||
1001 | } while (0) | ||
1002 | #elif ALPHA_COLOR_PIXEL_PER_BYTE == 2 | ||
1003 | #define UPDATE_SRC_ALPHA do { \ | ||
1004 | if (pixels ^= 1) \ | ||
1005 | data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ | ||
1006 | else \ | ||
1007 | data = *(++src); \ | ||
1008 | } while (0) | ||
1009 | #else | ||
1010 | #define UPDATE_SRC_ALPHA do { \ | ||
1011 | if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \ | ||
1012 | data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ | ||
1013 | else \ | ||
1014 | data = *(++src); \ | ||
1015 | } while (0) | ||
1016 | #endif | ||
1017 | do | ||
1018 | { | ||
1019 | unsigned color = blend_two_colors(FB_UNPACK_SCALAR_LCD(*dst), fg_pattern, | ||
1020 | data & ALPHA_COLOR_LOOKUP_SIZE ); | ||
1021 | *dst= FB_SCALARPACK(color); | ||
1022 | dst += LCD_WIDTH; | ||
1023 | UPDATE_SRC_ALPHA; | ||
1024 | } | ||
1025 | while (--col); | ||
1026 | #ifdef ALPHA_BITMAP_READ_WORDS | ||
1027 | if (skip_end < pixels) | ||
1028 | { | ||
1029 | pixels -= skip_end; | ||
1030 | data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT; | ||
1031 | } else { | ||
1032 | pixels = skip_end - pixels; | ||
1033 | src_w += pixels / ALPHA_COLOR_PIXEL_PER_WORD; | ||
1034 | pixels %= ALPHA_COLOR_PIXEL_PER_WORD; | ||
1035 | data = letoh32(*src_w++); | ||
1036 | data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; | ||
1037 | pixels = 8 - pixels; | ||
1038 | } | ||
1039 | #else | ||
1040 | if (skip_end) | ||
1041 | { | ||
1042 | pixels += skip_end; | ||
1043 | if (pixels >= ALPHA_COLOR_PIXEL_PER_BYTE) | ||
1044 | { | ||
1045 | src += pixels / ALPHA_COLOR_PIXEL_PER_BYTE; | ||
1046 | pixels %= ALPHA_COLOR_PIXEL_PER_BYTE; | ||
1047 | data = *src; | ||
1048 | data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; | ||
1049 | } else | ||
1050 | data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT; | ||
1051 | } | ||
1052 | #endif | ||
1053 | } while (--row); | ||
1054 | } | ||
1055 | |||
1056 | static void draw_putsxy_oriented(int x, int y, const char *str) | ||
1057 | { | ||
1058 | unsigned short ch; | ||
1059 | unsigned short *ucs; | ||
1060 | int ofs = MIN(x, 0); | ||
1061 | struct font* pf = rb->font_get(osd.font); | ||
1062 | |||
1063 | ucs = rb->bidi_l2v(str, 1); | ||
1064 | |||
1065 | x += osd.x; | ||
1066 | y += osd.y; | ||
1067 | |||
1068 | while ((ch = *ucs++) != 0 && x < SCREEN_WIDTH) | ||
1069 | { | ||
1070 | int width; | ||
1071 | const unsigned char *bits; | ||
1072 | |||
1073 | /* get proportional width and glyph bits */ | ||
1074 | width = rb->font_get_width(pf, ch); | ||
1075 | |||
1076 | if (ofs > width) { | ||
1077 | ofs -= width; | ||
1078 | continue; | ||
1079 | } | ||
1080 | |||
1081 | bits = rb->font_get_bits(pf, ch); | ||
1082 | |||
1083 | if (pf->depth) | ||
1084 | draw_oriented_alpha_bitmap_part(bits, ofs, 0, width, x, y, | ||
1085 | width - ofs, pf->height); | ||
1086 | else | ||
1087 | draw_oriented_mono_bitmap_part(bits, ofs, 0, width, x, y, | ||
1088 | width - ofs, pf->height); | ||
1089 | |||
1090 | x += width - ofs; | ||
1091 | ofs = 0; | ||
1092 | } | ||
1093 | } | ||
1094 | #else | ||
1095 | static void draw_oriented_mono_bitmap_part(const unsigned char *src, | ||
1096 | int src_x, int src_y, | ||
1097 | int stride, int x, int y, | ||
1098 | int width, int height) | ||
1099 | { | ||
1100 | int mode = mylcd_get_drawmode(); | ||
1101 | mylcd_set_drawmode(DRMODE_FG); | ||
1102 | mylcd_mono_bitmap_part(src, src_x, src_y, stride, x, y, width, height); | ||
1103 | mylcd_set_drawmode(mode); | ||
1104 | } | ||
1105 | |||
1106 | static void draw_putsxy_oriented(int x, int y, const char *str) | ||
1107 | { | ||
1108 | int mode = mylcd_get_drawmode(); | ||
1109 | mylcd_set_drawmode(DRMODE_FG); | ||
1110 | mylcd_putsxy(x + osd.x, y + osd.y, str); | ||
1111 | mylcd_set_drawmode(mode); | ||
1112 | } | ||
1113 | #endif /* LCD_PORTRAIT */ | ||
1114 | |||
1115 | /** FPS Display **/ | ||
1116 | |||
1117 | /* Post-frame callback (on video thread) - update the FPS rectangle from the | ||
1118 | * framebuffer */ | ||
1119 | static void fps_post_frame_callback(void) | ||
1120 | { | ||
1121 | vo_lock(); | ||
1122 | mylcd_update_rect(fps.pf_x, fps.pf_y, | ||
1123 | fps.pf_width, fps.pf_height); | ||
1124 | vo_unlock(); | ||
1125 | } | ||
1126 | |||
1127 | /* Set up to have the callback only update the intersection of the video | ||
1128 | * rectangle and the FPS text rectangle - if they don't intersect, then | ||
1129 | * the callback is set to NULL */ | ||
1130 | static void fps_update_post_frame_callback(void) | ||
1131 | { | ||
1132 | void (*cb)(void) = NULL; | ||
1133 | |||
1134 | if (settings.showfps) { | ||
1135 | struct vo_rect cliprect; | ||
1136 | |||
1137 | if (stream_vo_get_clip(&cliprect)) { | ||
1138 | /* Oriented screen coordinates -> OSD coordinates */ | ||
1139 | vo_rect_offset(&cliprect, -osd.x, -osd.y); | ||
1140 | |||
1141 | if (vo_rect_intersect(&cliprect, &cliprect, &fps.rect)) { | ||
1142 | int x = cliprect.l; | ||
1143 | int y = cliprect.t; | ||
1144 | int width = cliprect.r - cliprect.l; | ||
1145 | int height = cliprect.b - cliprect.t; | ||
1146 | |||
1147 | /* OSD coordinates -> framebuffer coordinates */ | ||
1148 | fps.pf_x = __X; | ||
1149 | fps.pf_y = __Y; | ||
1150 | fps.pf_width = __W; | ||
1151 | fps.pf_height = __H; | ||
1152 | |||
1153 | cb = fps_post_frame_callback; | ||
1154 | } | ||
1155 | } | ||
1156 | } | ||
1157 | |||
1158 | stream_set_callback(VIDEO_SET_POST_FRAME_CALLBACK, cb); | ||
1159 | } | ||
1160 | |||
1161 | /* Refresh the FPS display */ | ||
1162 | static void fps_refresh(void) | ||
1163 | { | ||
1164 | char str[FPS_BUFSIZE]; | ||
1165 | struct video_output_stats stats; | ||
1166 | int w, h, sw; | ||
1167 | long tick; | ||
1168 | |||
1169 | tick = *rb->current_tick; | ||
1170 | |||
1171 | if (TIME_BEFORE(tick, fps.update_tick)) | ||
1172 | return; | ||
1173 | |||
1174 | fps.update_tick = tick + FPS_UPDATE_INTERVAL; | ||
1175 | |||
1176 | stream_video_stats(&stats); | ||
1177 | |||
1178 | rb->snprintf(str, FPS_BUFSIZE, FPS_FORMAT, | ||
1179 | stats.fps / 100, stats.fps % 100); | ||
1180 | |||
1181 | w = fps.rect.r - fps.rect.l; | ||
1182 | h = fps.rect.b - fps.rect.t; | ||
1183 | |||
1184 | draw_clear_area(fps.rect.l, fps.rect.t, w, h); | ||
1185 | mylcd_getstringsize(str, &sw, NULL); | ||
1186 | draw_putsxy_oriented(fps.rect.r - sw, fps.rect.t, str); | ||
1187 | |||
1188 | vo_lock(); | ||
1189 | draw_update_rect(fps.rect.l, fps.rect.t, w, h); | ||
1190 | vo_unlock(); | ||
1191 | } | ||
1192 | |||
1193 | /* Initialize the FPS display */ | ||
1194 | static void fps_init(void) | ||
1195 | { | ||
1196 | fps.update_tick = *rb->current_tick; | ||
1197 | fps.rect.l = fps.rect.t = 0; | ||
1198 | mylcd_getstringsize(FPS_DIMSTR, &fps.rect.r, &fps.rect.b); | ||
1199 | vo_rect_offset(&fps.rect, -osd.x, -osd.y); | ||
1200 | fps_update_post_frame_callback(); | ||
1201 | } | ||
1202 | |||
1203 | /** OSD **/ | ||
1204 | |||
1205 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | ||
1206 | /* So we can refresh the overlay */ | ||
1207 | static void osd_lcd_enable_hook(unsigned short id, void* param) | ||
1208 | { | ||
1209 | (void)id; | ||
1210 | (void)param; | ||
1211 | rb->queue_post(rb->button_queue, LCD_ENABLE_EVENT_1, 0); | ||
1212 | } | ||
1213 | #endif | ||
1214 | |||
1215 | static void osdbacklight_hw_on_video_mode(bool video_on) | ||
1216 | { | ||
1217 | if (video_on) { | ||
1218 | #ifdef HAVE_BACKLIGHT | ||
1219 | /* Turn off backlight timeout */ | ||
1220 | backlight_ignore_timeout(); | ||
1221 | #endif | ||
1222 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | ||
1223 | rb->remove_event(LCD_EVENT_ACTIVATION, osd_lcd_enable_hook); | ||
1224 | #endif | ||
1225 | } else { | ||
1226 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | ||
1227 | rb->add_event(LCD_EVENT_ACTIVATION, osd_lcd_enable_hook); | ||
1228 | #endif | ||
1229 | #ifdef HAVE_BACKLIGHT | ||
1230 | /* Revert to user's backlight settings */ | ||
1231 | backlight_use_settings(); | ||
1232 | #endif | ||
1233 | } | ||
1234 | } | ||
1235 | |||
1236 | #ifdef HAVE_BACKLIGHT_BRIGHTNESS | ||
1237 | static void osd_backlight_brightness_video_mode(bool video_on) | ||
1238 | { | ||
1239 | if (settings.backlight_brightness < 0) | ||
1240 | return; | ||
1241 | |||
1242 | mpeg_backlight_update_brightness( | ||
1243 | video_on ? settings.backlight_brightness : -1); | ||
1244 | } | ||
1245 | #else | ||
1246 | #define osd_backlight_brightness_video_mode(video_on) | ||
1247 | #endif /* HAVE_BACKLIGHT_BRIGHTNESS */ | ||
1248 | |||
1249 | static void osd_text_init(void) | ||
1250 | { | ||
1251 | struct hms hms; | ||
1252 | char buf[32]; | ||
1253 | int phys; | ||
1254 | int spc_width; | ||
1255 | |||
1256 | draw_setfont(FONT_UI); | ||
1257 | |||
1258 | osd.x = 0; | ||
1259 | osd.width = SCREEN_WIDTH; | ||
1260 | |||
1261 | vo_rect_clear(&osd.time_rect); | ||
1262 | vo_rect_clear(&osd.stat_rect); | ||
1263 | vo_rect_clear(&osd.prog_rect); | ||
1264 | vo_rect_clear(&osd.vol_rect); | ||
1265 | |||
1266 | ts_to_hms(stream_get_duration(), &hms); | ||
1267 | hms_format(buf, sizeof (buf), &hms); | ||
1268 | mylcd_getstringsize(buf, &osd.time_rect.r, &osd.time_rect.b); | ||
1269 | |||
1270 | /* Choose well-sized bitmap images relative to font height */ | ||
1271 | if (osd.time_rect.b < 12) { | ||
1272 | osd.icons = mpegplayer_status_icons_8x8x1; | ||
1273 | osd.stat_rect.r = osd.stat_rect.b = 8; | ||
1274 | } else if (osd.time_rect.b < 16) { | ||
1275 | osd.icons = mpegplayer_status_icons_12x12x1; | ||
1276 | osd.stat_rect.r = osd.stat_rect.b = 12; | ||
1277 | } else { | ||
1278 | osd.icons = mpegplayer_status_icons_16x16x1; | ||
1279 | osd.stat_rect.r = osd.stat_rect.b = 16; | ||
1280 | } | ||
1281 | |||
1282 | if (osd.stat_rect.b < osd.time_rect.b) { | ||
1283 | vo_rect_offset(&osd.stat_rect, 0, | ||
1284 | (osd.time_rect.b - osd.stat_rect.b) / 2 + OSD_BDR_T); | ||
1285 | vo_rect_offset(&osd.time_rect, OSD_BDR_L, OSD_BDR_T); | ||
1286 | } else { | ||
1287 | vo_rect_offset(&osd.time_rect, OSD_BDR_L, | ||
1288 | osd.stat_rect.b - osd.time_rect.b + OSD_BDR_T); | ||
1289 | vo_rect_offset(&osd.stat_rect, 0, OSD_BDR_T); | ||
1290 | } | ||
1291 | |||
1292 | osd.dur_rect = osd.time_rect; | ||
1293 | |||
1294 | phys = rb->sound_val2phys(SOUND_VOLUME, rb->sound_min(SOUND_VOLUME)); | ||
1295 | rb->snprintf(buf, sizeof(buf), "%d%s", phys, | ||
1296 | rb->sound_unit(SOUND_VOLUME)); | ||
1297 | |||
1298 | mylcd_getstringsize(" ", &spc_width, NULL); | ||
1299 | mylcd_getstringsize(buf, &osd.vol_rect.r, &osd.vol_rect.b); | ||
1300 | |||
1301 | osd.prog_rect.r = SCREEN_WIDTH - OSD_BDR_L - spc_width - | ||
1302 | osd.vol_rect.r - OSD_BDR_R; | ||
1303 | osd.prog_rect.b = 3*osd.stat_rect.b / 4; | ||
1304 | vo_rect_offset(&osd.prog_rect, osd.time_rect.l, | ||
1305 | osd.time_rect.b); | ||
1306 | |||
1307 | vo_rect_offset(&osd.stat_rect, | ||
1308 | (osd.prog_rect.r + osd.prog_rect.l - osd.stat_rect.r) / 2, | ||
1309 | 0); | ||
1310 | |||
1311 | vo_rect_offset(&osd.dur_rect, | ||
1312 | osd.prog_rect.r - osd.dur_rect.r, 0); | ||
1313 | |||
1314 | vo_rect_offset(&osd.vol_rect, osd.prog_rect.r + spc_width, | ||
1315 | (osd.prog_rect.b + osd.prog_rect.t - osd.vol_rect.b) / 2); | ||
1316 | |||
1317 | osd.height = OSD_BDR_T + MAX(osd.prog_rect.b, osd.vol_rect.b) - | ||
1318 | MIN(osd.time_rect.t, osd.stat_rect.t) + OSD_BDR_B; | ||
1319 | |||
1320 | #ifdef HAVE_LCD_COLOR | ||
1321 | osd.height = ALIGN_UP(osd.height, 2); | ||
1322 | #endif | ||
1323 | osd.y = SCREEN_HEIGHT - osd.height; | ||
1324 | |||
1325 | draw_setfont(FONT_SYSFIXED); | ||
1326 | } | ||
1327 | |||
1328 | static void osd_init(void) | ||
1329 | { | ||
1330 | osd.flags = 0; | ||
1331 | osd.show_for = HZ*4; | ||
1332 | osd.print_delay = 75*HZ/100; | ||
1333 | osd.resume_delay = HZ/2; | ||
1334 | #ifdef HAVE_LCD_COLOR | ||
1335 | osd.bgcolor = LCD_RGBPACK(0x73, 0x75, 0xbd); | ||
1336 | osd.fgcolor = LCD_WHITE; | ||
1337 | osd.prog_fillcolor = LCD_BLACK; | ||
1338 | #else | ||
1339 | osd.bgcolor = GREY_LIGHTGRAY; | ||
1340 | osd.fgcolor = GREY_BLACK; | ||
1341 | osd.prog_fillcolor = GREY_WHITE; | ||
1342 | #endif | ||
1343 | osd.curr_time = 0; | ||
1344 | osd.status = OSD_STATUS_STOPPED; | ||
1345 | osd.auto_refresh = OSD_REFRESH_TIME; | ||
1346 | osd.next_auto_refresh = *rb->current_tick; | ||
1347 | osd_text_init(); | ||
1348 | fps_init(); | ||
1349 | } | ||
1350 | |||
1351 | #ifdef HAVE_HEADPHONE_DETECTION | ||
1352 | static void osd_set_hp_pause_flag(bool set) | ||
1353 | { | ||
1354 | if (set) | ||
1355 | osd.flags |= OSD_HP_PAUSE; | ||
1356 | else | ||
1357 | osd.flags &= ~OSD_HP_PAUSE; | ||
1358 | } | ||
1359 | #else | ||
1360 | #define osd_set_hp_pause_flag(set) | ||
1361 | #endif /* HAVE_HEADPHONE_DETECTION */ | ||
1362 | |||
1363 | static void osd_schedule_refresh(unsigned refresh) | ||
1364 | { | ||
1365 | long tick = *rb->current_tick; | ||
1366 | |||
1367 | if (refresh & OSD_REFRESH_VIDEO) | ||
1368 | osd.print_tick = tick + osd.print_delay; | ||
1369 | |||
1370 | if (refresh & OSD_REFRESH_RESUME) | ||
1371 | osd.resume_tick = tick + osd.resume_delay; | ||
1372 | |||
1373 | osd.auto_refresh |= refresh; | ||
1374 | } | ||
1375 | |||
1376 | static void osd_cancel_refresh(unsigned refresh) | ||
1377 | { | ||
1378 | osd.auto_refresh &= ~refresh; | ||
1379 | } | ||
1380 | |||
1381 | /* Refresh the background area */ | ||
1382 | static void osd_refresh_background(void) | ||
1383 | { | ||
1384 | char buf[32]; | ||
1385 | struct hms hms; | ||
1386 | |||
1387 | unsigned bg = mylcd_get_background(); | ||
1388 | mylcd_set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID); | ||
1389 | |||
1390 | #ifdef HAVE_LCD_COLOR | ||
1391 | /* Draw a "raised" area for our graphics */ | ||
1392 | mylcd_set_background(draw_blendcolor(bg, MYLCD_WHITE, 192)); | ||
1393 | draw_hline(0, osd.width, 0); | ||
1394 | |||
1395 | mylcd_set_background(draw_blendcolor(bg, MYLCD_WHITE, 80)); | ||
1396 | draw_hline(0, osd.width, 1); | ||
1397 | |||
1398 | mylcd_set_background(draw_blendcolor(bg, MYLCD_BLACK, 48)); | ||
1399 | draw_hline(0, osd.width, osd.height-2); | ||
1400 | |||
1401 | mylcd_set_background(draw_blendcolor(bg, MYLCD_BLACK, 128)); | ||
1402 | draw_hline(0, osd.width, osd.height-1); | ||
1403 | |||
1404 | mylcd_set_background(bg); | ||
1405 | draw_clear_area(0, 2, osd.width, osd.height - 4); | ||
1406 | #else | ||
1407 | /* Give contrast with the main background */ | ||
1408 | mylcd_set_background(MYLCD_WHITE); | ||
1409 | draw_hline(0, osd.width, 0); | ||
1410 | |||
1411 | mylcd_set_background(MYLCD_DARKGRAY); | ||
1412 | draw_hline(0, osd.width, osd.height-1); | ||
1413 | |||
1414 | mylcd_set_background(bg); | ||
1415 | draw_clear_area(0, 1, osd.width, osd.height - 2); | ||
1416 | #endif | ||
1417 | |||
1418 | vo_rect_set_ext(&osd.update_rect, 0, 0, osd.width, osd.height); | ||
1419 | mylcd_set_drawmode(DRMODE_SOLID); | ||
1420 | |||
1421 | if (stream_get_duration() != INVALID_TIMESTAMP) { | ||
1422 | /* Draw the movie duration */ | ||
1423 | ts_to_hms(stream_get_duration(), &hms); | ||
1424 | hms_format(buf, sizeof (buf), &hms); | ||
1425 | draw_putsxy_oriented(osd.dur_rect.l, osd.dur_rect.t, buf); | ||
1426 | } | ||
1427 | /* else don't know the duration */ | ||
1428 | } | ||
1429 | |||
1430 | /* Refresh the current time display + the progress bar */ | ||
1431 | static void osd_refresh_time(void) | ||
1432 | { | ||
1433 | char buf[32]; | ||
1434 | struct hms hms; | ||
1435 | |||
1436 | uint32_t duration = stream_get_duration(); | ||
1437 | |||
1438 | draw_scrollbar_draw_rect(&osd.prog_rect, 0, duration, | ||
1439 | osd.curr_time); | ||
1440 | |||
1441 | ts_to_hms(osd.curr_time, &hms); | ||
1442 | hms_format(buf, sizeof (buf), &hms); | ||
1443 | |||
1444 | draw_clear_area_rect(&osd.time_rect); | ||
1445 | draw_putsxy_oriented(osd.time_rect.l, osd.time_rect.t, buf); | ||
1446 | |||
1447 | vo_rect_union(&osd.update_rect, &osd.update_rect, | ||
1448 | &osd.prog_rect); | ||
1449 | vo_rect_union(&osd.update_rect, &osd.update_rect, | ||
1450 | &osd.time_rect); | ||
1451 | } | ||
1452 | |||
1453 | /* Refresh the volume display area */ | ||
1454 | static void osd_refresh_volume(void) | ||
1455 | { | ||
1456 | char buf[32]; | ||
1457 | int width; | ||
1458 | |||
1459 | int volume = rb->global_settings->volume; | ||
1460 | rb->snprintf(buf, sizeof (buf), "%d%s", | ||
1461 | rb->sound_val2phys(SOUND_VOLUME, volume), | ||
1462 | rb->sound_unit(SOUND_VOLUME)); | ||
1463 | mylcd_getstringsize(buf, &width, NULL); | ||
1464 | |||
1465 | /* Right-justified */ | ||
1466 | draw_clear_area_rect(&osd.vol_rect); | ||
1467 | draw_putsxy_oriented(osd.vol_rect.r - width, osd.vol_rect.t, buf); | ||
1468 | |||
1469 | vo_rect_union(&osd.update_rect, &osd.update_rect, &osd.vol_rect); | ||
1470 | } | ||
1471 | |||
1472 | /* Refresh the status icon */ | ||
1473 | static void osd_refresh_status(void) | ||
1474 | { | ||
1475 | int icon_size = osd.stat_rect.r - osd.stat_rect.l; | ||
1476 | |||
1477 | draw_clear_area_rect(&osd.stat_rect); | ||
1478 | |||
1479 | #ifdef HAVE_LCD_COLOR | ||
1480 | /* Draw status icon with a drop shadow */ | ||
1481 | unsigned oldfg = mylcd_get_foreground(); | ||
1482 | int i = 1; | ||
1483 | |||
1484 | mylcd_set_foreground(draw_blendcolor(mylcd_get_background(), | ||
1485 | MYLCD_BLACK, 96)); | ||
1486 | |||
1487 | while (1) | ||
1488 | { | ||
1489 | draw_oriented_mono_bitmap_part(osd.icons, | ||
1490 | icon_size*osd.status, | ||
1491 | 0, | ||
1492 | icon_size*OSD_STATUS_COUNT, | ||
1493 | osd.stat_rect.l + osd.x + i, | ||
1494 | osd.stat_rect.t + osd.y + i, | ||
1495 | icon_size, icon_size); | ||
1496 | |||
1497 | if (--i < 0) | ||
1498 | break; | ||
1499 | |||
1500 | mylcd_set_foreground(oldfg); | ||
1501 | } | ||
1502 | |||
1503 | vo_rect_union(&osd.update_rect, &osd.update_rect, &osd.stat_rect); | ||
1504 | #else | ||
1505 | draw_oriented_mono_bitmap_part(osd.icons, | ||
1506 | icon_size*osd.status, | ||
1507 | 0, | ||
1508 | icon_size*OSD_STATUS_COUNT, | ||
1509 | osd.stat_rect.l + osd.x, | ||
1510 | osd.stat_rect.t + osd.y, | ||
1511 | icon_size, icon_size); | ||
1512 | vo_rect_union(&osd.update_rect, &osd.update_rect, &osd.stat_rect); | ||
1513 | #endif | ||
1514 | } | ||
1515 | |||
1516 | /* Update the current status which determines which icon is displayed */ | ||
1517 | static bool osd_update_status(void) | ||
1518 | { | ||
1519 | int status; | ||
1520 | |||
1521 | switch (stream_status()) | ||
1522 | { | ||
1523 | default: | ||
1524 | status = OSD_STATUS_STOPPED; | ||
1525 | break; | ||
1526 | case STREAM_PAUSED: | ||
1527 | /* If paused with a pending resume, coerce it to OSD_STATUS_PLAYING */ | ||
1528 | status = (osd.auto_refresh & OSD_REFRESH_RESUME) ? | ||
1529 | OSD_STATUS_PLAYING : OSD_STATUS_PAUSED; | ||
1530 | break; | ||
1531 | case STREAM_PLAYING: | ||
1532 | status = OSD_STATUS_PLAYING; | ||
1533 | break; | ||
1534 | } | ||
1535 | |||
1536 | if (status != osd.status) { | ||
1537 | /* A refresh is needed */ | ||
1538 | osd.status = status; | ||
1539 | return true; | ||
1540 | } | ||
1541 | |||
1542 | return false; | ||
1543 | } | ||
1544 | |||
1545 | /* Update the current time that will be displayed */ | ||
1546 | static void osd_update_time(void) | ||
1547 | { | ||
1548 | uint32_t start; | ||
1549 | osd.curr_time = stream_get_seek_time(&start); | ||
1550 | osd.curr_time -= start; | ||
1551 | } | ||
1552 | |||
1553 | /* Refresh various parts of the OSD - showing it if it is hidden */ | ||
1554 | static void osd_refresh(int hint) | ||
1555 | { | ||
1556 | long tick; | ||
1557 | unsigned oldbg, oldfg; | ||
1558 | |||
1559 | tick = *rb->current_tick; | ||
1560 | |||
1561 | if (settings.showfps) | ||
1562 | fps_refresh(); | ||
1563 | |||
1564 | if (hint == OSD_REFRESH_DEFAULT) { | ||
1565 | /* The default which forces no updates */ | ||
1566 | |||
1567 | /* Make sure Rockbox doesn't turn off the player because of | ||
1568 | too little activity */ | ||
1569 | if (osd.status == OSD_STATUS_PLAYING) | ||
1570 | rb->reset_poweroff_timer(); | ||
1571 | |||
1572 | /* Redraw the current or possibly extract a new video frame */ | ||
1573 | if ((osd.auto_refresh & OSD_REFRESH_VIDEO) && | ||
1574 | TIME_AFTER(tick, osd.print_tick)) { | ||
1575 | osd.auto_refresh &= ~OSD_REFRESH_VIDEO; | ||
1576 | stream_draw_frame(false); | ||
1577 | } | ||
1578 | |||
1579 | /* Restart playback if the timout was reached */ | ||
1580 | if ((osd.auto_refresh & OSD_REFRESH_RESUME) && | ||
1581 | TIME_AFTER(tick, osd.resume_tick)) { | ||
1582 | osd.auto_refresh &= ~(OSD_REFRESH_RESUME | OSD_REFRESH_VIDEO); | ||
1583 | stream_resume(); | ||
1584 | } | ||
1585 | |||
1586 | /* If not visible, return */ | ||
1587 | if (!(osd.flags & OSD_SHOW)) | ||
1588 | return; | ||
1589 | |||
1590 | /* Hide if the visibility duration was reached */ | ||
1591 | if (TIME_AFTER(tick, osd.hide_tick)) { | ||
1592 | osd_show(OSD_HIDE); | ||
1593 | return; | ||
1594 | } | ||
1595 | } else { | ||
1596 | /* A forced update of some region */ | ||
1597 | |||
1598 | /* Show if currently invisible */ | ||
1599 | if (!(osd.flags & OSD_SHOW)) { | ||
1600 | /* Avoid call back into this function - it will be drawn */ | ||
1601 | osd_show(OSD_SHOW | OSD_NODRAW); | ||
1602 | hint = OSD_REFRESH_ALL; | ||
1603 | } | ||
1604 | |||
1605 | /* Move back timeouts for frame print and hide */ | ||
1606 | osd.print_tick = tick + osd.print_delay; | ||
1607 | osd.hide_tick = tick + osd.show_for; | ||
1608 | } | ||
1609 | |||
1610 | if (TIME_AFTER(tick, osd.next_auto_refresh)) { | ||
1611 | /* Refresh whatever graphical elements are due automatically */ | ||
1612 | osd.next_auto_refresh = tick + OSD_MIN_UPDATE_INTERVAL; | ||
1613 | |||
1614 | if (osd.auto_refresh & OSD_REFRESH_STATUS) { | ||
1615 | if (osd_update_status()) | ||
1616 | hint |= OSD_REFRESH_STATUS; | ||
1617 | } | ||
1618 | |||
1619 | if (osd.auto_refresh & OSD_REFRESH_TIME) { | ||
1620 | osd_update_time(); | ||
1621 | hint |= OSD_REFRESH_TIME; | ||
1622 | } | ||
1623 | } | ||
1624 | |||
1625 | if (hint == 0) | ||
1626 | return; /* No drawing needed */ | ||
1627 | |||
1628 | /* Set basic drawing params that are used. Elements that perform variations | ||
1629 | * will restore them. */ | ||
1630 | oldfg = mylcd_get_foreground(); | ||
1631 | oldbg = mylcd_get_background(); | ||
1632 | |||
1633 | draw_setfont(FONT_UI); | ||
1634 | mylcd_set_foreground(osd.fgcolor); | ||
1635 | mylcd_set_background(osd.bgcolor); | ||
1636 | |||
1637 | vo_rect_clear(&osd.update_rect); | ||
1638 | |||
1639 | if (hint & OSD_REFRESH_BACKGROUND) { | ||
1640 | osd_refresh_background(); | ||
1641 | hint |= OSD_REFRESH_ALL; /* Requires a redraw of everything */ | ||
1642 | } | ||
1643 | |||
1644 | if (hint & OSD_REFRESH_TIME) { | ||
1645 | osd_refresh_time(); | ||
1646 | } | ||
1647 | |||
1648 | if (hint & OSD_REFRESH_VOLUME) { | ||
1649 | osd_refresh_volume(); | ||
1650 | } | ||
1651 | |||
1652 | if (hint & OSD_REFRESH_STATUS) { | ||
1653 | osd_refresh_status(); | ||
1654 | } | ||
1655 | |||
1656 | /* Go back to defaults */ | ||
1657 | draw_setfont(FONT_SYSFIXED); | ||
1658 | mylcd_set_foreground(oldfg); | ||
1659 | mylcd_set_background(oldbg); | ||
1660 | |||
1661 | /* Update the dirty rectangle */ | ||
1662 | vo_lock(); | ||
1663 | |||
1664 | draw_update_rect(osd.update_rect.l, | ||
1665 | osd.update_rect.t, | ||
1666 | osd.update_rect.r - osd.update_rect.l, | ||
1667 | osd.update_rect.b - osd.update_rect.t); | ||
1668 | |||
1669 | vo_unlock(); | ||
1670 | } | ||
1671 | |||
1672 | /* Show/Hide the OSD */ | ||
1673 | static void osd_show(unsigned show) | ||
1674 | { | ||
1675 | if (((show ^ osd.flags) & OSD_SHOW) == 0) | ||
1676 | { | ||
1677 | if (show & OSD_SHOW) { | ||
1678 | osd.hide_tick = *rb->current_tick + osd.show_for; | ||
1679 | } | ||
1680 | return; | ||
1681 | } | ||
1682 | |||
1683 | if (show & OSD_SHOW) { | ||
1684 | /* Clip away the part of video that is covered */ | ||
1685 | struct vo_rect rc = { 0, 0, SCREEN_WIDTH, osd.y }; | ||
1686 | |||
1687 | osd.flags |= OSD_SHOW; | ||
1688 | |||
1689 | if (osd.status != OSD_STATUS_PLAYING) { | ||
1690 | /* Not playing - set brightness to mpegplayer setting */ | ||
1691 | osd_backlight_brightness_video_mode(true); | ||
1692 | } | ||
1693 | |||
1694 | stream_vo_set_clip(&rc); | ||
1695 | |||
1696 | if (!(show & OSD_NODRAW)) | ||
1697 | osd_refresh(OSD_REFRESH_ALL); | ||
1698 | } else { | ||
1699 | /* Uncover clipped video area and redraw it */ | ||
1700 | osd.flags &= ~OSD_SHOW; | ||
1701 | |||
1702 | draw_clear_area(0, 0, osd.width, osd.height); | ||
1703 | |||
1704 | if (!(show & OSD_NODRAW)) { | ||
1705 | vo_lock(); | ||
1706 | draw_update_rect(0, 0, osd.width, osd.height); | ||
1707 | vo_unlock(); | ||
1708 | |||
1709 | stream_vo_set_clip(NULL); | ||
1710 | stream_draw_frame(false); | ||
1711 | } else { | ||
1712 | stream_vo_set_clip(NULL); | ||
1713 | } | ||
1714 | |||
1715 | if (osd.status != OSD_STATUS_PLAYING) { | ||
1716 | /* Not playing - restore backlight brightness */ | ||
1717 | osd_backlight_brightness_video_mode(false); | ||
1718 | } | ||
1719 | } | ||
1720 | } | ||
1721 | |||
1722 | /* Set the current status - update screen if specified */ | ||
1723 | static void osd_set_status(int status) | ||
1724 | { | ||
1725 | bool draw = (status & OSD_NODRAW) == 0; | ||
1726 | |||
1727 | status &= OSD_STATUS_MASK; | ||
1728 | |||
1729 | if (osd.status != status) { | ||
1730 | |||
1731 | osd.status = status; | ||
1732 | |||
1733 | if (draw) | ||
1734 | osd_refresh(OSD_REFRESH_STATUS); | ||
1735 | } | ||
1736 | } | ||
1737 | |||
1738 | /* Get the current status value */ | ||
1739 | static int osd_get_status(void) | ||
1740 | { | ||
1741 | return osd.status & OSD_STATUS_MASK; | ||
1742 | } | ||
1743 | |||
1744 | /* Handle Fast-forward/Rewind keys using WPS settings (and some nicked code ;) | ||
1745 | * Returns last button code | ||
1746 | */ | ||
1747 | static int osd_ff_rw(int btn, unsigned refresh, uint32_t *new_time) | ||
1748 | { | ||
1749 | unsigned int step = TS_SECOND*rb->global_settings->ff_rewind_min_step; | ||
1750 | const long ff_rw_accel = (rb->global_settings->ff_rewind_accel + 3); | ||
1751 | uint32_t start; | ||
1752 | uint32_t time = stream_get_seek_time(&start); | ||
1753 | const uint32_t duration = stream_get_duration(); | ||
1754 | unsigned int max_step = 0; | ||
1755 | uint32_t ff_rw_count = 0; | ||
1756 | unsigned status = osd.status; | ||
1757 | int new_btn; | ||
1758 | |||
1759 | osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME | | ||
1760 | OSD_REFRESH_TIME); | ||
1761 | |||
1762 | time -= start; /* Absolute clock => stream-relative */ | ||
1763 | |||
1764 | switch (btn) | ||
1765 | { | ||
1766 | case MPEG_FF: | ||
1767 | #ifdef MPEG_FF2 | ||
1768 | case MPEG_FF2: | ||
1769 | #endif | ||
1770 | #ifdef MPEG_RC_FF | ||
1771 | case MPEG_RC_FF: | ||
1772 | #endif | ||
1773 | osd_set_status(OSD_STATUS_FF); | ||
1774 | new_btn = btn | BUTTON_REPEAT; /* simplify code below */ | ||
1775 | break; | ||
1776 | case MPEG_RW: | ||
1777 | #ifdef MPEG_RW2 | ||
1778 | case MPEG_RW2: | ||
1779 | #endif | ||
1780 | #ifdef MPEG_RC_RW | ||
1781 | case MPEG_RC_RW: | ||
1782 | #endif | ||
1783 | osd_set_status(OSD_STATUS_RW); | ||
1784 | new_btn = btn | BUTTON_REPEAT; /* simplify code below */ | ||
1785 | break; | ||
1786 | default: | ||
1787 | new_btn = BUTTON_NONE; /* Fail tests below but still do proper exit */ | ||
1788 | } | ||
1789 | |||
1790 | while (1) | ||
1791 | { | ||
1792 | stream_keep_disk_active(); | ||
1793 | |||
1794 | if (new_btn == (btn | BUTTON_REPEAT)) { | ||
1795 | if (osd.status == OSD_STATUS_FF) { | ||
1796 | /* fast forwarding, calc max step relative to end */ | ||
1797 | max_step = muldiv_uint32(duration - (time + ff_rw_count), | ||
1798 | FF_REWIND_MAX_PERCENT, 100); | ||
1799 | } else { | ||
1800 | /* rewinding, calc max step relative to start */ | ||
1801 | max_step = muldiv_uint32(time - ff_rw_count, | ||
1802 | FF_REWIND_MAX_PERCENT, 100); | ||
1803 | } | ||
1804 | |||
1805 | max_step = MAX(max_step, MIN_FF_REWIND_STEP); | ||
1806 | |||
1807 | if (step > max_step) | ||
1808 | step = max_step; | ||
1809 | |||
1810 | ff_rw_count += step; | ||
1811 | |||
1812 | /* smooth seeking by multiplying step by: 1 + (2 ^ -accel) */ | ||
1813 | step += step >> ff_rw_accel; | ||
1814 | |||
1815 | if (osd.status == OSD_STATUS_FF) { | ||
1816 | if (duration - time <= ff_rw_count) | ||
1817 | ff_rw_count = duration - time; | ||
1818 | |||
1819 | osd.curr_time = time + ff_rw_count; | ||
1820 | } else { | ||
1821 | if (time <= ff_rw_count) | ||
1822 | ff_rw_count = time; | ||
1823 | |||
1824 | osd.curr_time = time - ff_rw_count; | ||
1825 | } | ||
1826 | |||
1827 | osd_refresh(OSD_REFRESH_TIME); | ||
1828 | |||
1829 | new_btn = mpeg_button_get(TIMEOUT_BLOCK); | ||
1830 | } | ||
1831 | else { | ||
1832 | if (new_btn == (btn | BUTTON_REL)) { | ||
1833 | if (osd.status == OSD_STATUS_FF) | ||
1834 | time += ff_rw_count; | ||
1835 | else if (osd.status == OSD_STATUS_RW) | ||
1836 | time -= ff_rw_count; | ||
1837 | } | ||
1838 | |||
1839 | *new_time = time; | ||
1840 | |||
1841 | osd_schedule_refresh(refresh); | ||
1842 | osd_set_status(status); | ||
1843 | osd_schedule_refresh(OSD_REFRESH_TIME); | ||
1844 | |||
1845 | return new_btn; | ||
1846 | } | ||
1847 | } | ||
1848 | } | ||
1849 | |||
1850 | /* Return adjusted STREAM_* status */ | ||
1851 | static int osd_stream_status(void) | ||
1852 | { | ||
1853 | int status = stream_status(); | ||
1854 | |||
1855 | /* Coerce to STREAM_PLAYING if paused with a pending resume */ | ||
1856 | if (status == STREAM_PAUSED) { | ||
1857 | if (osd.auto_refresh & OSD_REFRESH_RESUME) | ||
1858 | status = STREAM_PLAYING; | ||
1859 | } | ||
1860 | |||
1861 | return status; | ||
1862 | } | ||
1863 | |||
1864 | /* Change the current audio volume by a specified amount */ | ||
1865 | static void osd_set_volume(int delta) | ||
1866 | { | ||
1867 | int vol = rb->global_settings->volume; | ||
1868 | int limit; | ||
1869 | |||
1870 | vol += delta; | ||
1871 | |||
1872 | if (delta < 0) { | ||
1873 | /* Volume down - clip to lower limit */ | ||
1874 | limit = rb->sound_min(SOUND_VOLUME); | ||
1875 | if (vol < limit) | ||
1876 | vol = limit; | ||
1877 | } else { | ||
1878 | /* Volume up - clip to upper limit */ | ||
1879 | limit = rb->sound_max(SOUND_VOLUME); | ||
1880 | if (vol > limit) | ||
1881 | vol = limit; | ||
1882 | } | ||
1883 | |||
1884 | /* Sync the global settings */ | ||
1885 | if (vol != rb->global_settings->volume) { | ||
1886 | rb->sound_set(SOUND_VOLUME, vol); | ||
1887 | rb->global_settings->volume = vol; | ||
1888 | } | ||
1889 | |||
1890 | /* Update the volume display */ | ||
1891 | osd_refresh(OSD_REFRESH_VOLUME); | ||
1892 | } | ||
1893 | |||
1894 | /* Begin playback at the specified time */ | ||
1895 | static int osd_play(uint32_t time) | ||
1896 | { | ||
1897 | int retval; | ||
1898 | |||
1899 | osd_set_hp_pause_flag(false); | ||
1900 | osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); | ||
1901 | |||
1902 | retval = stream_seek(time, SEEK_SET); | ||
1903 | |||
1904 | if (retval >= STREAM_OK) { | ||
1905 | osdbacklight_hw_on_video_mode(true); | ||
1906 | osd_backlight_brightness_video_mode(true); | ||
1907 | stream_show_vo(true); | ||
1908 | |||
1909 | retval = stream_play(); | ||
1910 | |||
1911 | if (retval >= STREAM_OK) | ||
1912 | osd_set_status(OSD_STATUS_PLAYING | OSD_NODRAW); | ||
1913 | } | ||
1914 | |||
1915 | return retval; | ||
1916 | } | ||
1917 | |||
1918 | /* Halt playback - pause engine and return logical state */ | ||
1919 | static int osd_halt(void) | ||
1920 | { | ||
1921 | int status = stream_pause(); | ||
1922 | |||
1923 | /* Coerce to STREAM_PLAYING if paused with a pending resume */ | ||
1924 | if (status == STREAM_PAUSED) { | ||
1925 | if (osd_get_status() == OSD_STATUS_PLAYING) | ||
1926 | status = STREAM_PLAYING; | ||
1927 | } | ||
1928 | |||
1929 | /* Cancel some auto refreshes - caller will restart them if desired */ | ||
1930 | osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); | ||
1931 | |||
1932 | /* No backlight fiddling here - callers does the right thing */ | ||
1933 | |||
1934 | return status; | ||
1935 | } | ||
1936 | |||
1937 | /* Pause playback if playing */ | ||
1938 | static int osd_pause(void) | ||
1939 | { | ||
1940 | unsigned refresh = osd.auto_refresh; | ||
1941 | int status = osd_halt(); | ||
1942 | |||
1943 | osd_set_hp_pause_flag(false); | ||
1944 | |||
1945 | if (status == STREAM_PLAYING && (refresh & OSD_REFRESH_RESUME)) { | ||
1946 | /* Resume pending - change to a still video frame update */ | ||
1947 | osd_schedule_refresh(OSD_REFRESH_VIDEO); | ||
1948 | } | ||
1949 | |||
1950 | osd_set_status(OSD_STATUS_PAUSED); | ||
1951 | |||
1952 | osdbacklight_hw_on_video_mode(false); | ||
1953 | /* Leave brightness alone and restore it when OSD is hidden */ | ||
1954 | |||
1955 | if (stream_can_seek() && rb->global_settings->pause_rewind) { | ||
1956 | stream_seek(-rb->global_settings->pause_rewind*TS_SECOND, | ||
1957 | SEEK_CUR); | ||
1958 | osd_schedule_refresh(OSD_REFRESH_VIDEO); | ||
1959 | /* Update time display now */ | ||
1960 | osd_update_time(); | ||
1961 | osd_refresh(OSD_REFRESH_TIME); | ||
1962 | } | ||
1963 | |||
1964 | return status; | ||
1965 | } | ||
1966 | |||
1967 | /* Resume playback if halted or paused */ | ||
1968 | static void osd_resume(void) | ||
1969 | { | ||
1970 | /* Cancel video and resume auto refresh - the resyc when starting | ||
1971 | * playback will perform those tasks */ | ||
1972 | osd_set_hp_pause_flag(false); | ||
1973 | osdbacklight_hw_on_video_mode(true); | ||
1974 | osd_backlight_brightness_video_mode(true); | ||
1975 | osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); | ||
1976 | osd_set_status(OSD_STATUS_PLAYING); | ||
1977 | stream_resume(); | ||
1978 | } | ||
1979 | |||
1980 | /* Stop playback - remember the resume point if not closed */ | ||
1981 | static void osd_stop(void) | ||
1982 | { | ||
1983 | uint32_t resume_time; | ||
1984 | |||
1985 | osd_set_hp_pause_flag(false); | ||
1986 | osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); | ||
1987 | osd_set_status(OSD_STATUS_STOPPED | OSD_NODRAW); | ||
1988 | osd_show(OSD_HIDE); | ||
1989 | |||
1990 | stream_stop(); | ||
1991 | |||
1992 | resume_time = stream_get_resume_time(); | ||
1993 | |||
1994 | if (resume_time != INVALID_TIMESTAMP) | ||
1995 | settings.resume_time = resume_time; | ||
1996 | |||
1997 | osdbacklight_hw_on_video_mode(false); | ||
1998 | osd_backlight_brightness_video_mode(false); | ||
1999 | } | ||
2000 | |||
2001 | /* Perform a seek by button if seeking is possible for this stream. | ||
2002 | * | ||
2003 | * A delay will be inserted before restarting in case the user decides to | ||
2004 | * seek again soon after. | ||
2005 | * | ||
2006 | * Returns last button code | ||
2007 | */ | ||
2008 | static int osd_seek_btn(int btn) | ||
2009 | { | ||
2010 | int status; | ||
2011 | unsigned refresh = 0; | ||
2012 | uint32_t time; | ||
2013 | |||
2014 | if (!stream_can_seek()) | ||
2015 | return true; | ||
2016 | |||
2017 | /* Halt playback - not strictly necessary but nice when doing | ||
2018 | * buttons */ | ||
2019 | status = osd_halt(); | ||
2020 | |||
2021 | if (status == STREAM_STOPPED) | ||
2022 | return true; | ||
2023 | |||
2024 | osd_show(OSD_SHOW); | ||
2025 | |||
2026 | /* Obtain a new playback point according to the buttons */ | ||
2027 | if (status == STREAM_PLAYING) | ||
2028 | refresh = OSD_REFRESH_RESUME; /* delay resume if playing */ | ||
2029 | else | ||
2030 | refresh = OSD_REFRESH_VIDEO; /* refresh if paused */ | ||
2031 | |||
2032 | btn = osd_ff_rw(btn, refresh, &time); | ||
2033 | |||
2034 | /* Tell engine to resume at that time */ | ||
2035 | stream_seek(time, SEEK_SET); | ||
2036 | |||
2037 | return btn; | ||
2038 | } | ||
2039 | |||
2040 | /* Perform a seek by time if seeking is possible for this stream | ||
2041 | * | ||
2042 | * If playing, the seeking is immediate, otherise a delay is added to showing | ||
2043 | * a still if paused in case the user does another seek soon after. | ||
2044 | * | ||
2045 | * If seeking isn't possible, a time of zero performs a skip to the | ||
2046 | * beginning. | ||
2047 | */ | ||
2048 | static void osd_seek_time(uint32_t time) | ||
2049 | { | ||
2050 | int status; | ||
2051 | unsigned refresh = 0; | ||
2052 | |||
2053 | if (!stream_can_seek() && time != 0) | ||
2054 | return; | ||
2055 | |||
2056 | stream_wait_status(); | ||
2057 | status = osd_stream_status(); | ||
2058 | |||
2059 | if (status == STREAM_STOPPED) | ||
2060 | return; | ||
2061 | |||
2062 | if (status == STREAM_PLAYING) /* merely preserve resume */ | ||
2063 | refresh = osd.auto_refresh & OSD_REFRESH_RESUME; | ||
2064 | else | ||
2065 | refresh = OSD_REFRESH_VIDEO; /* refresh if paused */ | ||
2066 | |||
2067 | /* Cancel print or resume if pending */ | ||
2068 | osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); | ||
2069 | |||
2070 | /* Tell engine to seek to the given time - no state change */ | ||
2071 | stream_seek(time, SEEK_SET); | ||
2072 | |||
2073 | osd_update_time(); | ||
2074 | osd_refresh(OSD_REFRESH_TIME); | ||
2075 | osd_schedule_refresh(refresh); | ||
2076 | } | ||
2077 | |||
2078 | /* Has this file one of the supported extensions? */ | ||
2079 | static bool is_videofile(const char* file) | ||
2080 | { | ||
2081 | static const char * const extensions[] = | ||
2082 | { | ||
2083 | /* Should match apps/plugins/viewers.config */ | ||
2084 | "mpg", "mpeg", "mpv", "m2v" | ||
2085 | }; | ||
2086 | |||
2087 | const char* ext = rb->strrchr(file, '.'); | ||
2088 | int i; | ||
2089 | |||
2090 | if (!ext) | ||
2091 | return false; | ||
2092 | |||
2093 | for (i = ARRAYLEN(extensions) - 1; i >= 0; i--) | ||
2094 | { | ||
2095 | if (!rb->strcasecmp(ext + 1, extensions[i])) | ||
2096 | break; | ||
2097 | } | ||
2098 | |||
2099 | return i >= 0; | ||
2100 | } | ||
2101 | |||
2102 | /* deliver the next/previous video file in the current directory. | ||
2103 | returns false if there is none. */ | ||
2104 | static bool get_videofile(int direction, char* videofile, size_t bufsize) | ||
2105 | { | ||
2106 | struct tree_context *tree = rb->tree_get_context(); | ||
2107 | struct entry *dircache = rb->tree_get_entries(tree); | ||
2108 | int i, step, end, found = 0; | ||
2109 | char *videoname = rb->strrchr(videofile, '/') + 1; | ||
2110 | size_t rest = bufsize - (videoname - videofile) - 1; | ||
2111 | |||
2112 | if (direction == VIDEO_NEXT) { | ||
2113 | i = 0; | ||
2114 | step = 1; | ||
2115 | end = tree->filesindir; | ||
2116 | } else { | ||
2117 | i = tree->filesindir-1; | ||
2118 | step = -1; | ||
2119 | end = -1; | ||
2120 | } | ||
2121 | for (; i != end; i += step) | ||
2122 | { | ||
2123 | const char* name = dircache[i].name; | ||
2124 | if (!rb->strcmp(name, videoname)) { | ||
2125 | found = 1; | ||
2126 | continue; | ||
2127 | } | ||
2128 | if (found && rb->strlen(name) <= rest && | ||
2129 | !(dircache[i].attr & ATTR_DIRECTORY) && is_videofile(name)) | ||
2130 | { | ||
2131 | rb->strcpy(videoname, name); | ||
2132 | return true; | ||
2133 | } | ||
2134 | } | ||
2135 | |||
2136 | return false; | ||
2137 | } | ||
2138 | |||
2139 | #ifdef HAVE_HEADPHONE_DETECTION | ||
2140 | /* Handle SYS_PHONE_PLUGGED/UNPLUGGED */ | ||
2141 | static void osd_handle_phone_plug(bool inserted) | ||
2142 | { | ||
2143 | if (rb->global_settings->unplug_mode == 0) | ||
2144 | return; | ||
2145 | |||
2146 | /* Wait for any incomplete state transition to complete first */ | ||
2147 | stream_wait_status(); | ||
2148 | |||
2149 | int status = osd_stream_status(); | ||
2150 | |||
2151 | if (inserted) { | ||
2152 | if (rb->global_settings->unplug_mode > 1) { | ||
2153 | if (status == STREAM_PAUSED && | ||
2154 | (osd.flags & OSD_HP_PAUSE)) { | ||
2155 | osd_resume(); | ||
2156 | } | ||
2157 | } | ||
2158 | } else { | ||
2159 | if (status == STREAM_PLAYING) { | ||
2160 | osd_pause(); | ||
2161 | |||
2162 | osd_set_hp_pause_flag(true); | ||
2163 | } | ||
2164 | } | ||
2165 | } | ||
2166 | #endif | ||
2167 | |||
2168 | static int button_loop(void) | ||
2169 | { | ||
2170 | int next_action = (settings.play_mode == 0) ? VIDEO_STOP : VIDEO_NEXT; | ||
2171 | |||
2172 | rb->lcd_setfont(FONT_SYSFIXED); | ||
2173 | #ifdef HAVE_LCD_COLOR | ||
2174 | rb->lcd_set_foreground(LCD_WHITE); | ||
2175 | rb->lcd_set_background(LCD_BLACK); | ||
2176 | #endif | ||
2177 | rb->lcd_clear_display(); | ||
2178 | rb->lcd_update(); | ||
2179 | |||
2180 | #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV) | ||
2181 | rb->lcd_set_mode(LCD_MODE_YUV); | ||
2182 | #endif | ||
2183 | |||
2184 | osd_init(); | ||
2185 | |||
2186 | /* Start playback at the specified starting time */ | ||
2187 | if (osd_play(settings.resume_time) < STREAM_OK) { | ||
2188 | rb->splash(HZ*2, "Playback failed"); | ||
2189 | return VIDEO_STOP; | ||
2190 | } | ||
2191 | |||
2192 | /* Gently poll the video player for EOS and handle UI */ | ||
2193 | while (stream_status() != STREAM_STOPPED) | ||
2194 | { | ||
2195 | int button = mpeg_button_get(OSD_MIN_UPDATE_INTERVAL/2); | ||
2196 | |||
2197 | switch (button) | ||
2198 | { | ||
2199 | case BUTTON_NONE: | ||
2200 | { | ||
2201 | osd_refresh(OSD_REFRESH_DEFAULT); | ||
2202 | continue; | ||
2203 | } /* BUTTON_NONE: */ | ||
2204 | |||
2205 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | ||
2206 | case LCD_ENABLE_EVENT_1: | ||
2207 | { | ||
2208 | /* Draw the current frame if prepared already */ | ||
2209 | stream_draw_frame(true); | ||
2210 | break; | ||
2211 | } /* LCD_ENABLE_EVENT_1: */ | ||
2212 | #endif | ||
2213 | |||
2214 | case MPEG_VOLUP: | ||
2215 | case MPEG_VOLUP|BUTTON_REPEAT: | ||
2216 | #ifdef MPEG_VOLUP2 | ||
2217 | case MPEG_VOLUP2: | ||
2218 | case MPEG_VOLUP2|BUTTON_REPEAT: | ||
2219 | #endif | ||
2220 | #ifdef MPEG_RC_VOLUP | ||
2221 | case MPEG_RC_VOLUP: | ||
2222 | case MPEG_RC_VOLUP|BUTTON_REPEAT: | ||
2223 | #endif | ||
2224 | { | ||
2225 | osd_set_volume(+1); | ||
2226 | break; | ||
2227 | } /* MPEG_VOLUP*: */ | ||
2228 | |||
2229 | case MPEG_VOLDOWN: | ||
2230 | case MPEG_VOLDOWN|BUTTON_REPEAT: | ||
2231 | #ifdef MPEG_VOLDOWN2 | ||
2232 | case MPEG_VOLDOWN2: | ||
2233 | case MPEG_VOLDOWN2|BUTTON_REPEAT: | ||
2234 | #endif | ||
2235 | #ifdef MPEG_RC_VOLDOWN | ||
2236 | case MPEG_RC_VOLDOWN: | ||
2237 | case MPEG_RC_VOLDOWN|BUTTON_REPEAT: | ||
2238 | #endif | ||
2239 | { | ||
2240 | osd_set_volume(-1); | ||
2241 | break; | ||
2242 | } /* MPEG_VOLDOWN*: */ | ||
2243 | |||
2244 | case MPEG_MENU: | ||
2245 | #ifdef MPEG_RC_MENU | ||
2246 | case MPEG_RC_MENU: | ||
2247 | #endif | ||
2248 | { | ||
2249 | int state = osd_halt(); /* save previous state */ | ||
2250 | int result; | ||
2251 | |||
2252 | /* Hide video output */ | ||
2253 | osd_show(OSD_HIDE | OSD_NODRAW); | ||
2254 | stream_show_vo(false); | ||
2255 | osd_backlight_brightness_video_mode(false); | ||
2256 | |||
2257 | #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV) | ||
2258 | rb->lcd_set_mode(LCD_MODE_RGB565); | ||
2259 | #endif | ||
2260 | |||
2261 | result = mpeg_menu(); | ||
2262 | |||
2263 | next_action = (settings.play_mode == 0) ? VIDEO_STOP : VIDEO_NEXT; | ||
2264 | |||
2265 | fps_update_post_frame_callback(); | ||
2266 | |||
2267 | /* The menu can change the font, so restore */ | ||
2268 | rb->lcd_setfont(FONT_SYSFIXED); | ||
2269 | #ifdef HAVE_LCD_COLOR | ||
2270 | rb->lcd_set_foreground(LCD_WHITE); | ||
2271 | rb->lcd_set_background(LCD_BLACK); | ||
2272 | #endif | ||
2273 | rb->lcd_clear_display(); | ||
2274 | rb->lcd_update(); | ||
2275 | |||
2276 | switch (result) | ||
2277 | { | ||
2278 | case MPEG_MENU_QUIT: | ||
2279 | next_action = VIDEO_STOP; | ||
2280 | osd_stop(); | ||
2281 | break; | ||
2282 | |||
2283 | default: | ||
2284 | #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV) | ||
2285 | rb->lcd_set_mode(LCD_MODE_YUV); | ||
2286 | #endif | ||
2287 | /* If not stopped, show video again */ | ||
2288 | if (state != STREAM_STOPPED) { | ||
2289 | osd_show(OSD_SHOW); | ||
2290 | stream_show_vo(true); | ||
2291 | } | ||
2292 | |||
2293 | /* If stream was playing, restart it */ | ||
2294 | if (state == STREAM_PLAYING) { | ||
2295 | osd_resume(); | ||
2296 | } | ||
2297 | break; | ||
2298 | } | ||
2299 | break; | ||
2300 | } /* MPEG_MENU: */ | ||
2301 | |||
2302 | #ifdef MPEG_SHOW_OSD | ||
2303 | case MPEG_SHOW_OSD: | ||
2304 | case MPEG_SHOW_OSD | BUTTON_REPEAT: | ||
2305 | /* Show if not visible */ | ||
2306 | osd_show(OSD_SHOW); | ||
2307 | /* Make sure it refreshes */ | ||
2308 | osd_refresh(OSD_REFRESH_DEFAULT); | ||
2309 | break; | ||
2310 | #endif | ||
2311 | |||
2312 | case MPEG_STOP: | ||
2313 | #ifdef MPEG_RC_STOP | ||
2314 | case MPEG_RC_STOP: | ||
2315 | #endif | ||
2316 | case ACTION_STD_CANCEL: | ||
2317 | { | ||
2318 | cancel_playback: | ||
2319 | next_action = VIDEO_STOP; | ||
2320 | osd_stop(); | ||
2321 | break; | ||
2322 | } /* MPEG_STOP: */ | ||
2323 | |||
2324 | case MPEG_PAUSE: | ||
2325 | #ifdef MPEG_PAUSE2 | ||
2326 | case MPEG_PAUSE2: | ||
2327 | #endif | ||
2328 | #ifdef MPEG_RC_PAUSE | ||
2329 | case MPEG_RC_PAUSE: | ||
2330 | #endif | ||
2331 | { | ||
2332 | int status = osd_stream_status(); | ||
2333 | |||
2334 | if (status == STREAM_PLAYING) { | ||
2335 | /* Playing => Paused */ | ||
2336 | osd_pause(); | ||
2337 | } | ||
2338 | else if (status == STREAM_PAUSED) { | ||
2339 | /* Paused => Playing */ | ||
2340 | osd_resume(); | ||
2341 | } | ||
2342 | |||
2343 | break; | ||
2344 | } /* MPEG_PAUSE*: */ | ||
2345 | |||
2346 | case MPEG_RW: | ||
2347 | #ifdef MPEG_RW2 | ||
2348 | case MPEG_RW2: | ||
2349 | #endif | ||
2350 | #ifdef MPEG_RC_RW | ||
2351 | case MPEG_RC_RW: | ||
2352 | #endif | ||
2353 | { | ||
2354 | int old_button = button; | ||
2355 | |||
2356 | /* If button has been released: skip to next/previous file */ | ||
2357 | button = mpeg_button_get(OSD_MIN_UPDATE_INTERVAL); | ||
2358 | |||
2359 | if ((old_button | BUTTON_REL) == button) { | ||
2360 | /* Check current playback position */ | ||
2361 | osd_update_time(); | ||
2362 | |||
2363 | if (settings.play_mode == 0 || osd.curr_time >= 3*TS_SECOND) { | ||
2364 | /* Start the current video from the beginning */ | ||
2365 | osd_seek_time(0*TS_SECOND); | ||
2366 | } | ||
2367 | else { | ||
2368 | /* Release within 3 seconds of start: skip to previous | ||
2369 | * file */ | ||
2370 | osd_stop(); | ||
2371 | next_action = VIDEO_PREV | VIDEO_ACTION_MANUAL; | ||
2372 | } | ||
2373 | } | ||
2374 | else if ((button & ~BUTTON_REPEAT) == old_button) { | ||
2375 | button = osd_seek_btn(old_button); | ||
2376 | } | ||
2377 | |||
2378 | if (button == ACTION_STD_CANCEL) | ||
2379 | goto cancel_playback; /* jump to stop handling above */ | ||
2380 | |||
2381 | rb->default_event_handler(button); | ||
2382 | break; | ||
2383 | } /* MPEG_RW: */ | ||
2384 | |||
2385 | case MPEG_FF: | ||
2386 | #ifdef MPEG_FF2 | ||
2387 | case MPEG_FF2: | ||
2388 | #endif | ||
2389 | #ifdef MPEG_RC_FF | ||
2390 | case MPEG_RC_FF: | ||
2391 | #endif | ||
2392 | { | ||
2393 | int old_button = button; | ||
2394 | |||
2395 | if (settings.play_mode != 0) | ||
2396 | button = mpeg_button_get(OSD_MIN_UPDATE_INTERVAL); | ||
2397 | |||
2398 | if ((old_button | BUTTON_REL) == button) { | ||
2399 | /* If button has been released: skip to next file */ | ||
2400 | osd_stop(); | ||
2401 | next_action = VIDEO_NEXT | VIDEO_ACTION_MANUAL; | ||
2402 | } | ||
2403 | else if ((button & ~BUTTON_REPEAT) == old_button) { | ||
2404 | button = osd_seek_btn(old_button); | ||
2405 | } | ||
2406 | |||
2407 | if (button == ACTION_STD_CANCEL) | ||
2408 | goto cancel_playback; /* jump to stop handling above */ | ||
2409 | |||
2410 | rb->default_event_handler(button); | ||
2411 | break; | ||
2412 | } /* MPEG_FF: */ | ||
2413 | |||
2414 | #ifdef HAVE_HEADPHONE_DETECTION | ||
2415 | case SYS_PHONE_PLUGGED: | ||
2416 | case SYS_PHONE_UNPLUGGED: | ||
2417 | { | ||
2418 | osd_handle_phone_plug(button == SYS_PHONE_PLUGGED); | ||
2419 | break; | ||
2420 | } /* SYS_PHONE_*: */ | ||
2421 | #endif | ||
2422 | |||
2423 | default: | ||
2424 | { | ||
2425 | osd_refresh(OSD_REFRESH_DEFAULT); | ||
2426 | rb->default_event_handler(button); | ||
2427 | break; | ||
2428 | } /* default: */ | ||
2429 | } | ||
2430 | |||
2431 | rb->yield(); | ||
2432 | } /* end while */ | ||
2433 | |||
2434 | osd_stop(); | ||
2435 | |||
2436 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | ||
2437 | /* Be sure hook is removed before exiting since the stop will put it | ||
2438 | * back because of the backlight restore. */ | ||
2439 | rb->remove_event(LCD_EVENT_ACTIVATION, osd_lcd_enable_hook); | ||
2440 | #endif | ||
2441 | |||
2442 | rb->lcd_setfont(FONT_UI); | ||
2443 | |||
2444 | return next_action; | ||
2445 | } | ||
2446 | |||
2447 | enum plugin_status plugin_start(const void* parameter) | ||
2448 | { | ||
2449 | static char videofile[MAX_PATH]; | ||
2450 | int status = PLUGIN_OK; /* assume success */ | ||
2451 | bool quit = false; | ||
2452 | |||
2453 | #if defined(PLUGIN_USE_IRAM) && !defined(SIMULATOR) | ||
2454 | bool preserved_talk_state; | ||
2455 | #endif | ||
2456 | |||
2457 | if (parameter == NULL) { | ||
2458 | /* No file = GTFO */ | ||
2459 | rb->splash(HZ*2, "No File"); | ||
2460 | return PLUGIN_ERROR; | ||
2461 | } | ||
2462 | |||
2463 | /* Disable all talking before initializing IRAM */ | ||
2464 | rb->talk_disable(true); | ||
2465 | |||
2466 | #ifdef PLUGIN_USE_IRAM | ||
2467 | iram_saving_init(); | ||
2468 | |||
2469 | #ifndef SIMULATOR | ||
2470 | preserved_talk_state = rb->global_settings->talk_menu; | ||
2471 | if (!iram_saved_copy) | ||
2472 | rb->global_settings->talk_menu = false; | ||
2473 | #endif | ||
2474 | #endif | ||
2475 | |||
2476 | #ifdef HAVE_LCD_COLOR | ||
2477 | rb->lcd_set_backdrop(NULL); | ||
2478 | rb->lcd_set_foreground(LCD_WHITE); | ||
2479 | rb->lcd_set_background(LCD_BLACK); | ||
2480 | #endif | ||
2481 | |||
2482 | rb->lcd_clear_display(); | ||
2483 | rb->lcd_update(); | ||
2484 | |||
2485 | rb->strcpy(videofile, (const char*) parameter); | ||
2486 | |||
2487 | if (stream_init() < STREAM_OK) { | ||
2488 | /* Fatal because this should not fail */ | ||
2489 | DEBUGF("Could not initialize streams\n"); | ||
2490 | status = PLUGIN_ERROR; | ||
2491 | } else { | ||
2492 | int next_action = VIDEO_STOP; | ||
2493 | bool get_videofile_says = true; | ||
2494 | |||
2495 | while (!quit) | ||
2496 | { | ||
2497 | init_settings(videofile); | ||
2498 | |||
2499 | int result = stream_open(videofile); | ||
2500 | bool manual_skip = false; | ||
2501 | |||
2502 | if (result >= STREAM_OK) { | ||
2503 | /* start menu */ | ||
2504 | rb->lcd_clear_display(); | ||
2505 | rb->lcd_update(); | ||
2506 | result = mpeg_start_menu(stream_get_duration()); | ||
2507 | |||
2508 | next_action = VIDEO_STOP; | ||
2509 | if (result != MPEG_START_QUIT) { | ||
2510 | /* Enter button loop and process UI */ | ||
2511 | next_action = button_loop(); | ||
2512 | manual_skip = next_action & VIDEO_ACTION_MANUAL; | ||
2513 | next_action &= ~VIDEO_ACTION_MANUAL; | ||
2514 | } | ||
2515 | |||
2516 | stream_close(); | ||
2517 | |||
2518 | rb->lcd_clear_display(); | ||
2519 | rb->lcd_update(); | ||
2520 | |||
2521 | save_settings(); | ||
2522 | } else { | ||
2523 | /* Problem with file; display message about it - not | ||
2524 | * considered a plugin error */ | ||
2525 | long tick; | ||
2526 | const char *errstring; | ||
2527 | |||
2528 | DEBUGF("Could not open %s\n", videofile); | ||
2529 | switch (result) | ||
2530 | { | ||
2531 | case STREAM_UNSUPPORTED: | ||
2532 | errstring = "Unsupported format"; | ||
2533 | break; | ||
2534 | default: | ||
2535 | errstring = "Error opening file: %d"; | ||
2536 | } | ||
2537 | |||
2538 | tick = *rb->current_tick + HZ*2; | ||
2539 | |||
2540 | rb->splashf(0, errstring, result); | ||
2541 | |||
2542 | /* Be sure it doesn't get stuck in an unbreakable loop of bad | ||
2543 | * files, just in case! Otherwise, keep searching in the | ||
2544 | * chosen direction until a good one is found. */ | ||
2545 | while (!quit && TIME_BEFORE(*rb->current_tick, tick)) | ||
2546 | { | ||
2547 | int button = mpeg_button_get(HZ*2); | ||
2548 | |||
2549 | switch (button) | ||
2550 | { | ||
2551 | case MPEG_STOP: | ||
2552 | case ACTION_STD_CANCEL: | ||
2553 | /* Abort the search and exit */ | ||
2554 | next_action = VIDEO_STOP; | ||
2555 | quit = true; | ||
2556 | break; | ||
2557 | |||
2558 | case BUTTON_NONE: | ||
2559 | if (settings.play_mode != 0) { | ||
2560 | if (next_action == VIDEO_STOP) { | ||
2561 | /* Default to next file */ | ||
2562 | next_action = VIDEO_NEXT; | ||
2563 | } | ||
2564 | else if (next_action == VIDEO_PREV && | ||
2565 | !get_videofile_says) { | ||
2566 | /* Was first file already; avoid endlessly | ||
2567 | * retrying it */ | ||
2568 | next_action = VIDEO_STOP; | ||
2569 | } | ||
2570 | } | ||
2571 | break; | ||
2572 | |||
2573 | default: | ||
2574 | rb->default_event_handler(button); | ||
2575 | } /* switch */ | ||
2576 | } /* while */ | ||
2577 | } | ||
2578 | |||
2579 | /* return value of button_loop says, what's next */ | ||
2580 | switch (next_action) | ||
2581 | { | ||
2582 | case VIDEO_NEXT: | ||
2583 | { | ||
2584 | get_videofile_says = get_videofile(VIDEO_NEXT, videofile, | ||
2585 | sizeof(videofile)); | ||
2586 | /* quit after finished the last videofile */ | ||
2587 | quit = !get_videofile_says; | ||
2588 | |||
2589 | if (manual_skip) | ||
2590 | { | ||
2591 | rb->system_sound_play(get_videofile_says ? | ||
2592 | SOUND_TRACK_SKIP : SOUND_TRACK_NO_MORE); | ||
2593 | } | ||
2594 | |||
2595 | break; | ||
2596 | } | ||
2597 | case VIDEO_PREV: | ||
2598 | { | ||
2599 | get_videofile_says = get_videofile(VIDEO_PREV, videofile, | ||
2600 | sizeof(videofile)); | ||
2601 | /* if there is no previous file, play the same videofile */ | ||
2602 | |||
2603 | if (manual_skip) | ||
2604 | { | ||
2605 | rb->system_sound_play(get_videofile_says ? | ||
2606 | SOUND_TRACK_SKIP : SOUND_TRACK_NO_MORE); | ||
2607 | } | ||
2608 | |||
2609 | break; | ||
2610 | } | ||
2611 | case VIDEO_STOP: | ||
2612 | { | ||
2613 | quit = true; | ||
2614 | break; | ||
2615 | } | ||
2616 | } | ||
2617 | } /* while */ | ||
2618 | } | ||
2619 | |||
2620 | #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV) | ||
2621 | rb->lcd_set_mode(LCD_MODE_RGB565); | ||
2622 | #endif | ||
2623 | |||
2624 | stream_exit(); | ||
2625 | |||
2626 | #if defined(PLUGIN_USE_IRAM) && !defined(SIMULATOR) | ||
2627 | if (!iram_saved_copy) | ||
2628 | rb->global_settings->talk_menu = preserved_talk_state; | ||
2629 | #endif | ||
2630 | |||
2631 | rb->talk_disable(false); | ||
2632 | |||
2633 | /* Actually handle delayed processing of system events of interest | ||
2634 | * that were captured in other button loops */ | ||
2635 | mpeg_sysevent_handle(); | ||
2636 | |||
2637 | return status; | ||
2638 | } | ||
diff --git a/apps/plugins/mpegplayer/mpegplayer.h b/apps/plugins/mpegplayer/mpegplayer.h deleted file mode 100644 index 51fb9a8f8a..0000000000 --- a/apps/plugins/mpegplayer/mpegplayer.h +++ /dev/null | |||
@@ -1,95 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Main mpegplayer config header. | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #ifndef MPEGPLAYER_H | ||
24 | #define MPEGPLAYER_H | ||
25 | |||
26 | #ifdef HAVE_SCHEDULER_BOOSTCTRL | ||
27 | #define trigger_cpu_boost rb->trigger_cpu_boost | ||
28 | #define cancel_cpu_boost rb->cancel_cpu_boost | ||
29 | #endif | ||
30 | /* #else function-like empty macros are defined in the headers */ | ||
31 | |||
32 | /* Should be enough for now */ | ||
33 | #define MPEGPLAYER_MAX_STREAMS 4 | ||
34 | |||
35 | /* Memory allotments for various subsystems */ | ||
36 | #define MIN_MEMMARGIN (4*1024) | ||
37 | |||
38 | /** Video thread **/ | ||
39 | #define LIBMPEG2_ALLOC_SIZE (2*1024*1024) | ||
40 | |||
41 | /** MPEG audio buffer **/ | ||
42 | #define AUDIOBUF_GUARD_SIZE (MPA_MAX_FRAME_SIZE + 2*MAD_BUFFER_GUARD) | ||
43 | #define AUDIOBUF_SIZE (64*1024) | ||
44 | #define AUDIOBUF_ALLOC_SIZE (AUDIOBUF_SIZE+AUDIOBUF_GUARD_SIZE) | ||
45 | |||
46 | /** PCM buffer **/ | ||
47 | #define CLOCK_RATE 44100 /* Our clock rate in ticks/second (samplerate) */ | ||
48 | |||
49 | /* Define this as "1" to have a test tone instead of silence clip */ | ||
50 | #define SILENCE_TEST_TONE 0 | ||
51 | |||
52 | /* NOTE: Sizes make no frame header allowance when considering duration */ | ||
53 | #define PCMOUT_BUFSIZE (CLOCK_RATE/2*4) /* 1/2s */ | ||
54 | #define PCMOUT_GUARD_SIZE (PCMOUT_BUFSIZE) /* guarantee contiguous sizes */ | ||
55 | #define PCMOUT_ALLOC_SIZE (PCMOUT_BUFSIZE + PCMOUT_GUARD_SIZE) | ||
56 | /* Start pcm playback @ 25% full */ | ||
57 | #define PCMOUT_PLAY_WM (PCMOUT_BUFSIZE/4) | ||
58 | #define PCMOUT_LOW_WM (0) | ||
59 | |||
60 | /** disk buffer **/ | ||
61 | #define DISK_BUF_LOW_WATERMARK (1024*1024) | ||
62 | /* 65535+6 is required since each PES has a 6 byte header with a 16 bit | ||
63 | * packet length field */ | ||
64 | #define DISK_GUARDBUF_SIZE ALIGN_UP(65535+6, 4) | ||
65 | |||
66 | #ifdef HAVE_LCD_COLOR | ||
67 | #define mylcd_splash rb->splash | ||
68 | #else | ||
69 | #include "lib/grey.h" | ||
70 | #define mylcd_splash grey_splash | ||
71 | #endif | ||
72 | |||
73 | #include "lib/mylcd.h" | ||
74 | |||
75 | #include "libmpeg2/mpeg2.h" | ||
76 | #include "video_out.h" | ||
77 | #include "mpeg_stream.h" | ||
78 | #include "mpeg_misc.h" | ||
79 | #include "mpeg_alloc.h" | ||
80 | #include "stream_thread.h" | ||
81 | #include "parser.h" | ||
82 | #include "pcm_output.h" | ||
83 | #include "disk_buf.h" | ||
84 | #include "stream_mgr.h" | ||
85 | |||
86 | #define LCD_ENABLE_EVENT_0 MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0) | ||
87 | #define LCD_ENABLE_EVENT_1 MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 1) | ||
88 | |||
89 | #ifdef PLUGIN_USE_IRAM | ||
90 | /* IRAM preserving mechanism to enable talking menus */ | ||
91 | extern void mpegplayer_iram_preserve(void); | ||
92 | extern void mpegplayer_iram_restore(void); | ||
93 | #endif | ||
94 | |||
95 | #endif /* MPEGPLAYER_H */ | ||
diff --git a/apps/plugins/mpegplayer/mpegplayer.make b/apps/plugins/mpegplayer/mpegplayer.make deleted file mode 100644 index af2156787e..0000000000 --- a/apps/plugins/mpegplayer/mpegplayer.make +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | # __________ __ ___. | ||
2 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
3 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
4 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
5 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
6 | # \/ \/ \/ \/ \/ | ||
7 | # $Id$ | ||
8 | # | ||
9 | |||
10 | MPEGSRCDIR := $(APPSDIR)/plugins/mpegplayer | ||
11 | MPEGBUILDDIR := $(BUILDDIR)/apps/plugins/mpegplayer | ||
12 | |||
13 | ROCKS += $(MPEGBUILDDIR)/mpegplayer.rock | ||
14 | |||
15 | MPEG_SRC := $(call preprocess, $(MPEGSRCDIR)/SOURCES) | ||
16 | MPEG_OBJ := $(call c2obj, $(MPEG_SRC)) | ||
17 | |||
18 | # add source files to OTHER_SRC to get automatic dependencies | ||
19 | OTHER_SRC += $(MPEG_SRC) | ||
20 | |||
21 | # Set '-fgnu89-inline' if supported (GCCVER >= 4.1.3, GCCNUM > 401) | ||
22 | ifeq ($(shell expr $(GCCNUM) \> 401),1) | ||
23 | MPEGCFLAGS = $(PLUGINFLAGS) -fgnu89-inline | ||
24 | else | ||
25 | MPEGCFLAGS = $(PLUGINFLAGS) | ||
26 | endif | ||
27 | |||
28 | $(MPEGBUILDDIR)/mpegplayer.rock: $(MPEG_OBJ) $(CODECDIR)/libmad-mpeg.a | ||
29 | |||
30 | $(MPEGBUILDDIR)/%.o: $(MPEGSRCDIR)/%.c $(MPEGSRCDIR)/mpegplayer.make | ||
31 | $(SILENT)mkdir -p $(dir $@) | ||
32 | $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(MPEGCFLAGS) -c $< -o $@ | ||
diff --git a/apps/plugins/mpegplayer/parser.h b/apps/plugins/mpegplayer/parser.h deleted file mode 100644 index ba2181e98b..0000000000 --- a/apps/plugins/mpegplayer/parser.h +++ /dev/null | |||
@@ -1,103 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * AV parser inteface declarations | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #ifndef PARSER_H | ||
24 | #define PARSER_H | ||
25 | |||
26 | enum stream_formats | ||
27 | { | ||
28 | STREAM_FMT_UNKNOWN = -1, | ||
29 | STREAM_FMT_MPEG_TS, /* MPEG transport stream */ | ||
30 | STREAM_FMT_MPEG_PS, /* MPEG program stream */ | ||
31 | STREAM_FMT_MPV, /* MPEG Video only (1 or 2) */ | ||
32 | STREAM_FMT_MPA, /* MPEG Audio only */ | ||
33 | }; | ||
34 | |||
35 | /* Structure used by a thread that handles a single demuxed data stream and | ||
36 | * receives commands from the stream manager */ | ||
37 | enum stream_parse_states | ||
38 | { | ||
39 | /* Stream is... */ | ||
40 | SSTATE_SYNC, /* synchronizing by trying to find a start code */ | ||
41 | SSTATE_PARSE, /* parsing the stream looking for packets */ | ||
42 | SSTATE_END, /* at the end of data */ | ||
43 | }; | ||
44 | |||
45 | enum stream_parse_mode | ||
46 | { | ||
47 | STREAM_PM_STREAMING = 0, /* Next packet when streaming */ | ||
48 | STREAM_PM_RANDOM_ACCESS, /* Random-access parsing */ | ||
49 | }; | ||
50 | |||
51 | enum stream_parser_flags | ||
52 | { | ||
53 | STREAMF_CAN_SEEK = 0x1, /* Seeking possible for this stream */ | ||
54 | }; | ||
55 | |||
56 | struct stream_parser | ||
57 | { | ||
58 | /* Common generic parser data */ | ||
59 | enum stream_formats format; /* Stream format */ | ||
60 | uint32_t start_pts; /* The movie start time as represented by | ||
61 | the first audio PTS tag in the | ||
62 | stream converted to half minutes */ | ||
63 | uint32_t end_pts; /* The movie end time as represented by | ||
64 | the maximum audio PTS tag in the | ||
65 | stream converted to half minutes */ | ||
66 | uint32_t duration; /* Duration in PTS units */ | ||
67 | unsigned flags; /* Various attributes set at init */ | ||
68 | struct vo_ext dims; /* Movie dimensions in pixels */ | ||
69 | uint32_t last_seek_time; | ||
70 | int (*next_data)(struct stream *str, enum stream_parse_mode type); | ||
71 | union /* A place for reusable no-cache parameters */ | ||
72 | { | ||
73 | struct str_sync_data sd; | ||
74 | } parms; | ||
75 | }; | ||
76 | |||
77 | extern struct stream_parser str_parser; | ||
78 | |||
79 | /* MPEG parsing */ | ||
80 | uint8_t * mpeg_parser_scan_start_code(struct stream_scan *sk, uint32_t code); | ||
81 | unsigned mpeg_parser_scan_pes(struct stream_scan *sk); | ||
82 | uint32_t mpeg_parser_scan_scr(struct stream_scan *sk); | ||
83 | uint32_t mpeg_parser_scan_pts(struct stream_scan *sk, unsigned id); | ||
84 | off_t mpeg_stream_stream_seek_PTS(uint32_t time, int id); | ||
85 | |||
86 | /* General parsing */ | ||
87 | bool parser_init(void); | ||
88 | void str_initialize(struct stream *str, off_t pos); | ||
89 | bool parser_prepare_image(uint32_t time); | ||
90 | bool parser_get_video_size(struct vo_ext *sz); | ||
91 | int parser_init_stream(void); | ||
92 | void parser_close_stream(void); | ||
93 | static inline bool parser_can_seek(void) | ||
94 | { return str_parser.flags & STREAMF_CAN_SEEK; } | ||
95 | uint32_t parser_seek_time(uint32_t time); | ||
96 | void parser_prepare_streaming(void); | ||
97 | void str_end_of_stream(struct stream *str); | ||
98 | |||
99 | static inline int parser_get_next_data(struct stream *str, | ||
100 | enum stream_parse_mode type) | ||
101 | { return str_parser.next_data(str, type); } | ||
102 | |||
103 | #endif /* PARSER_H */ | ||
diff --git a/apps/plugins/mpegplayer/pcm_output.c b/apps/plugins/mpegplayer/pcm_output.c deleted file mode 100644 index 5e95d16316..0000000000 --- a/apps/plugins/mpegplayer/pcm_output.c +++ /dev/null | |||
@@ -1,396 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * PCM output buffer definitions | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #include "plugin.h" | ||
24 | #include "mpegplayer.h" | ||
25 | |||
26 | /* PCM channel we're using */ | ||
27 | #define MPEG_PCM_CHANNEL PCM_MIXER_CHAN_PLAYBACK | ||
28 | |||
29 | /* Pointers */ | ||
30 | |||
31 | /* Start of buffer */ | ||
32 | static struct pcm_frame_header * ALIGNED_ATTR(4) pcm_buffer; | ||
33 | /* End of buffer (not guard) */ | ||
34 | static struct pcm_frame_header * ALIGNED_ATTR(4) pcmbuf_end; | ||
35 | /* Read pointer */ | ||
36 | static struct pcm_frame_header * ALIGNED_ATTR(4) pcmbuf_head IBSS_ATTR; | ||
37 | /* Write pointer */ | ||
38 | static struct pcm_frame_header * ALIGNED_ATTR(4) pcmbuf_tail IBSS_ATTR; | ||
39 | |||
40 | /* Bytes */ | ||
41 | static ssize_t pcmbuf_curr_size IBSS_ATTR; /* Size of currently playing frame */ | ||
42 | static ssize_t pcmbuf_read IBSS_ATTR; /* Number of bytes read by DMA */ | ||
43 | static ssize_t pcmbuf_written IBSS_ATTR; /* Number of bytes written by source */ | ||
44 | static ssize_t pcmbuf_threshold IBSS_ATTR; /* Non-silence threshold */ | ||
45 | |||
46 | /* Clock */ | ||
47 | static uint32_t clock_start IBSS_ATTR; /* Clock at playback start */ | ||
48 | static uint32_t volatile clock_tick IBSS_ATTR; /* Our base clock */ | ||
49 | static uint32_t volatile clock_time IBSS_ATTR; /* Timestamp adjusted */ | ||
50 | |||
51 | static int pcm_skipped = 0; | ||
52 | static int pcm_underruns = 0; | ||
53 | |||
54 | static unsigned int old_sampr = 0; | ||
55 | |||
56 | /* Small silence clip. ~5.80ms @ 44.1kHz */ | ||
57 | static int16_t silence[256*2] ALIGNED_ATTR(4) = { 0 }; | ||
58 | |||
59 | /* Delete all buffer contents */ | ||
60 | static void pcm_reset_buffer(void) | ||
61 | { | ||
62 | pcmbuf_threshold = PCMOUT_PLAY_WM; | ||
63 | pcmbuf_curr_size = pcmbuf_read = pcmbuf_written = 0; | ||
64 | pcmbuf_head = pcmbuf_tail = pcm_buffer; | ||
65 | pcm_skipped = pcm_underruns = 0; | ||
66 | } | ||
67 | |||
68 | /* Advance a PCM buffer pointer by size bytes circularly */ | ||
69 | static inline void pcm_advance_buffer(struct pcm_frame_header **p, | ||
70 | size_t size) | ||
71 | { | ||
72 | *p = SKIPBYTES(*p, size); | ||
73 | if (*p >= pcmbuf_end) | ||
74 | *p = SKIPBYTES(*p, -PCMOUT_BUFSIZE); | ||
75 | } | ||
76 | |||
77 | /* Return physical space used */ | ||
78 | static inline ssize_t pcm_output_bytes_used(void) | ||
79 | { | ||
80 | return pcmbuf_written - pcmbuf_read; /* wrap-safe */ | ||
81 | } | ||
82 | |||
83 | /* Return physical space free */ | ||
84 | static inline ssize_t pcm_output_bytes_free(void) | ||
85 | { | ||
86 | return PCMOUT_BUFSIZE - pcm_output_bytes_used(); | ||
87 | } | ||
88 | |||
89 | /* Audio DMA handler */ | ||
90 | static void get_more(const void **start, size_t *size) | ||
91 | { | ||
92 | ssize_t sz; | ||
93 | |||
94 | /* Free-up the last frame played frame if any */ | ||
95 | pcmbuf_read += pcmbuf_curr_size; | ||
96 | pcmbuf_curr_size = 0; | ||
97 | |||
98 | sz = pcm_output_bytes_used(); | ||
99 | |||
100 | if (sz > pcmbuf_threshold) | ||
101 | { | ||
102 | pcmbuf_threshold = PCMOUT_LOW_WM; | ||
103 | |||
104 | while (1) | ||
105 | { | ||
106 | uint32_t time = pcmbuf_head->time; | ||
107 | int32_t offset = time - clock_time; | ||
108 | |||
109 | sz = pcmbuf_head->size; | ||
110 | |||
111 | if (sz < (ssize_t)(PCM_HDR_SIZE + 4) || | ||
112 | (sz & 3) != 0) | ||
113 | { | ||
114 | /* Just show a warning about this - will never happen | ||
115 | * without a corrupted buffer */ | ||
116 | DEBUGF("get_more: invalid size (%ld)\n", (long)sz); | ||
117 | } | ||
118 | |||
119 | if (offset < -100*CLOCK_RATE/1000) | ||
120 | { | ||
121 | /* Frame more than 100ms late - drop it */ | ||
122 | pcm_advance_buffer(&pcmbuf_head, sz); | ||
123 | pcmbuf_read += sz; | ||
124 | pcm_skipped++; | ||
125 | if (pcm_output_bytes_used() > 0) | ||
126 | continue; | ||
127 | |||
128 | /* Ran out so revert to default watermark */ | ||
129 | pcmbuf_threshold = PCMOUT_PLAY_WM; | ||
130 | pcm_underruns++; | ||
131 | } | ||
132 | else if (offset < 100*CLOCK_RATE/1000) | ||
133 | { | ||
134 | /* Frame less than 100ms early - play it */ | ||
135 | struct pcm_frame_header *head = pcmbuf_head; | ||
136 | |||
137 | pcm_advance_buffer(&pcmbuf_head, sz); | ||
138 | pcmbuf_curr_size = sz; | ||
139 | |||
140 | sz -= PCM_HDR_SIZE; | ||
141 | |||
142 | /* Audio is time master - keep clock synchronized */ | ||
143 | clock_time = time + (sz >> 2); | ||
144 | |||
145 | /* Update base clock */ | ||
146 | clock_tick += sz >> 2; | ||
147 | |||
148 | *start = head->data; | ||
149 | *size = sz; | ||
150 | return; | ||
151 | } | ||
152 | /* Frame will be dropped - play silence clip */ | ||
153 | break; | ||
154 | } | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | /* Ran out so revert to default watermark */ | ||
159 | if (pcmbuf_threshold == PCMOUT_LOW_WM) | ||
160 | pcm_underruns++; | ||
161 | |||
162 | pcmbuf_threshold = PCMOUT_PLAY_WM; | ||
163 | } | ||
164 | |||
165 | /* Keep clock going at all times */ | ||
166 | clock_time += sizeof (silence) / 4; | ||
167 | clock_tick += sizeof (silence) / 4; | ||
168 | |||
169 | *start = silence; | ||
170 | *size = sizeof (silence); | ||
171 | |||
172 | if (sz < 0) | ||
173 | pcmbuf_read = pcmbuf_written; | ||
174 | } | ||
175 | |||
176 | /** Public interface **/ | ||
177 | |||
178 | /* Return a buffer pointer if at least size bytes are available and if so, | ||
179 | * give the actual free space */ | ||
180 | void * pcm_output_get_buffer(ssize_t *size) | ||
181 | { | ||
182 | ssize_t sz = *size; | ||
183 | ssize_t free = pcm_output_bytes_free() - PCM_HDR_SIZE; | ||
184 | |||
185 | if (sz >= 0 && free >= sz) | ||
186 | { | ||
187 | *size = free; /* return actual free space (- header) */ | ||
188 | return pcmbuf_tail->data; | ||
189 | } | ||
190 | |||
191 | /* Leave *size alone so caller doesn't have to reinit */ | ||
192 | return NULL; | ||
193 | } | ||
194 | |||
195 | /* Commit the buffer returned by pcm_ouput_get_buffer; timestamp is PCM | ||
196 | * clock time units, not video format time units */ | ||
197 | bool pcm_output_commit_data(ssize_t size, uint32_t timestamp) | ||
198 | { | ||
199 | if (size <= 0 || (size & 3)) | ||
200 | return false; /* invalid */ | ||
201 | |||
202 | size += PCM_HDR_SIZE; | ||
203 | |||
204 | if (size > pcm_output_bytes_free()) | ||
205 | return false; /* too big */ | ||
206 | |||
207 | pcmbuf_tail->size = size; | ||
208 | pcmbuf_tail->time = timestamp; | ||
209 | |||
210 | pcm_advance_buffer(&pcmbuf_tail, size); | ||
211 | pcmbuf_written += size; | ||
212 | |||
213 | return true; | ||
214 | } | ||
215 | |||
216 | /* Returns 'true' if the buffer is completely empty */ | ||
217 | bool pcm_output_empty(void) | ||
218 | { | ||
219 | return pcm_output_bytes_used() <= 0; | ||
220 | } | ||
221 | |||
222 | /* Flushes the buffer - clock keeps counting */ | ||
223 | void pcm_output_flush(void) | ||
224 | { | ||
225 | rb->pcm_play_lock(); | ||
226 | |||
227 | enum channel_status status = rb->mixer_channel_status(MPEG_PCM_CHANNEL); | ||
228 | |||
229 | /* Stop PCM to clear current buffer */ | ||
230 | if (status != CHANNEL_STOPPED) | ||
231 | rb->mixer_channel_stop(MPEG_PCM_CHANNEL); | ||
232 | |||
233 | rb->pcm_play_unlock(); | ||
234 | |||
235 | pcm_reset_buffer(); | ||
236 | |||
237 | /* Restart if playing state was current */ | ||
238 | if (status == CHANNEL_PLAYING) | ||
239 | rb->mixer_channel_play_data(MPEG_PCM_CHANNEL, | ||
240 | get_more, NULL, 0); | ||
241 | } | ||
242 | |||
243 | /* Seek the reference clock to the specified time - next audio data ready to | ||
244 | go to DMA should be on the buffer with the same time index or else the PCM | ||
245 | buffer should be empty */ | ||
246 | void pcm_output_set_clock(uint32_t time) | ||
247 | { | ||
248 | rb->pcm_play_lock(); | ||
249 | |||
250 | clock_start = time; | ||
251 | clock_tick = time; | ||
252 | clock_time = time; | ||
253 | |||
254 | rb->pcm_play_unlock(); | ||
255 | } | ||
256 | |||
257 | /* Return the clock as synchronized by audio frame timestamps */ | ||
258 | uint32_t pcm_output_get_clock(void) | ||
259 | { | ||
260 | uint32_t time, rem; | ||
261 | |||
262 | /* Reread if data race detected - rem will be 0 if driver hasn't yet | ||
263 | * updated to the new buffer size. Also be sure pcm state doesn't | ||
264 | * cause indefinite loop. | ||
265 | * | ||
266 | * FYI: NOT scrutinized for rd/wr reordering on different cores. */ | ||
267 | do | ||
268 | { | ||
269 | time = clock_time; | ||
270 | rem = rb->mixer_channel_get_bytes_waiting(MPEG_PCM_CHANNEL) >> 2; | ||
271 | } | ||
272 | while (UNLIKELY(time != clock_time || | ||
273 | (rem == 0 && | ||
274 | rb->mixer_channel_status(MPEG_PCM_CHANNEL) == CHANNEL_PLAYING)) | ||
275 | ); | ||
276 | |||
277 | return time - rem; | ||
278 | |||
279 | } | ||
280 | |||
281 | /* Return the raw clock as counted from the last pcm_output_set_clock | ||
282 | * call */ | ||
283 | uint32_t pcm_output_get_ticks(uint32_t *start) | ||
284 | { | ||
285 | uint32_t tick, rem; | ||
286 | |||
287 | /* Same procedure as pcm_output_get_clock */ | ||
288 | do | ||
289 | { | ||
290 | tick = clock_tick; | ||
291 | rem = rb->mixer_channel_get_bytes_waiting(MPEG_PCM_CHANNEL) >> 2; | ||
292 | } | ||
293 | while (UNLIKELY(tick != clock_tick || | ||
294 | (rem == 0 && | ||
295 | rb->mixer_channel_status(MPEG_PCM_CHANNEL) == CHANNEL_PLAYING)) | ||
296 | ); | ||
297 | |||
298 | if (start) | ||
299 | *start = clock_start; | ||
300 | |||
301 | return tick - rem; | ||
302 | } | ||
303 | |||
304 | /* Pauses/Starts pcm playback - and the clock */ | ||
305 | void pcm_output_play_pause(bool play) | ||
306 | { | ||
307 | rb->pcm_play_lock(); | ||
308 | |||
309 | if (rb->mixer_channel_status(MPEG_PCM_CHANNEL) != CHANNEL_STOPPED) | ||
310 | { | ||
311 | rb->mixer_channel_play_pause(MPEG_PCM_CHANNEL, play); | ||
312 | rb->pcm_play_unlock(); | ||
313 | } | ||
314 | else | ||
315 | { | ||
316 | rb->pcm_play_unlock(); | ||
317 | |||
318 | if (play) | ||
319 | { | ||
320 | rb->mixer_channel_set_amplitude(MPEG_PCM_CHANNEL, MIX_AMP_UNITY); | ||
321 | rb->mixer_channel_play_data(MPEG_PCM_CHANNEL, | ||
322 | get_more, NULL, 0); | ||
323 | } | ||
324 | } | ||
325 | } | ||
326 | |||
327 | /* Stops all playback and resets the clock */ | ||
328 | void pcm_output_stop(void) | ||
329 | { | ||
330 | rb->pcm_play_lock(); | ||
331 | |||
332 | if (rb->mixer_channel_status(MPEG_PCM_CHANNEL) != CHANNEL_STOPPED) | ||
333 | rb->mixer_channel_stop(MPEG_PCM_CHANNEL); | ||
334 | |||
335 | rb->pcm_play_unlock(); | ||
336 | |||
337 | pcm_output_flush(); | ||
338 | pcm_output_set_clock(0); | ||
339 | } | ||
340 | |||
341 | /* Drains any data if the start threshold hasn't been reached */ | ||
342 | void pcm_output_drain(void) | ||
343 | { | ||
344 | rb->pcm_play_lock(); | ||
345 | pcmbuf_threshold = PCMOUT_LOW_WM; | ||
346 | rb->pcm_play_unlock(); | ||
347 | } | ||
348 | |||
349 | bool pcm_output_init(void) | ||
350 | { | ||
351 | pcm_buffer = mpeg_malloc(PCMOUT_ALLOC_SIZE, MPEG_ALLOC_PCMOUT); | ||
352 | if (pcm_buffer == NULL) | ||
353 | return false; | ||
354 | |||
355 | pcmbuf_end = SKIPBYTES(pcm_buffer, PCMOUT_BUFSIZE); | ||
356 | |||
357 | pcm_reset_buffer(); | ||
358 | |||
359 | #if INPUT_SRC_CAPS != 0 | ||
360 | /* Select playback */ | ||
361 | rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); | ||
362 | rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); | ||
363 | #endif | ||
364 | |||
365 | #if SILENCE_TEST_TONE | ||
366 | /* Make the silence clip a square wave */ | ||
367 | const int16_t silence_amp = INT16_MAX / 16; | ||
368 | unsigned i; | ||
369 | |||
370 | for (i = 0; i < ARRAYLEN(silence); i += 2) | ||
371 | { | ||
372 | if (i < ARRAYLEN(silence)/2) | ||
373 | { | ||
374 | silence[i] = silence_amp; | ||
375 | silence[i+1] = silence_amp; | ||
376 | } | ||
377 | else | ||
378 | { | ||
379 | silence[i] = -silence_amp; | ||
380 | silence[i+1] = -silence_amp; | ||
381 | } | ||
382 | } | ||
383 | #endif | ||
384 | |||
385 | old_sampr = rb->mixer_get_frequency(); | ||
386 | rb->mixer_set_frequency(CLOCK_RATE); | ||
387 | rb->pcmbuf_fade(false, true); | ||
388 | return true; | ||
389 | } | ||
390 | |||
391 | void pcm_output_exit(void) | ||
392 | { | ||
393 | rb->pcmbuf_fade(false, false); | ||
394 | if (old_sampr != 0) | ||
395 | rb->mixer_set_frequency(old_sampr); | ||
396 | } | ||
diff --git a/apps/plugins/mpegplayer/pcm_output.h b/apps/plugins/mpegplayer/pcm_output.h deleted file mode 100644 index bae00cd045..0000000000 --- a/apps/plugins/mpegplayer/pcm_output.h +++ /dev/null | |||
@@ -1,48 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * PCM output buffer declarations | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #ifndef PCM_OUTPUT_H | ||
24 | #define PCM_OUTPUT_H | ||
25 | |||
26 | #define PCM_HDR_SIZE (sizeof (struct pcm_frame_header)) | ||
27 | struct pcm_frame_header /* Header added to pcm data every time a decoded | ||
28 | audio frame is sent out */ | ||
29 | { | ||
30 | uint32_t size; /* size of this frame - including header */ | ||
31 | uint32_t time; /* timestamp for this frame in audio ticks */ | ||
32 | unsigned char data[]; /* open array of audio data */ | ||
33 | } ALIGNED_ATTR(4); | ||
34 | |||
35 | bool pcm_output_init(void); | ||
36 | void pcm_output_exit(void); | ||
37 | void pcm_output_flush(void); | ||
38 | void pcm_output_set_clock(uint32_t time); | ||
39 | uint32_t pcm_output_get_clock(void); | ||
40 | uint32_t pcm_output_get_ticks(uint32_t *start); | ||
41 | void pcm_output_play_pause(bool play); | ||
42 | void pcm_output_stop(void); | ||
43 | void pcm_output_drain(void); | ||
44 | void * pcm_output_get_buffer(ssize_t *size); | ||
45 | bool pcm_output_commit_data(ssize_t size, uint32_t timestamp); | ||
46 | bool pcm_output_empty(void); | ||
47 | |||
48 | #endif /* PCM_OUTPUT_H */ | ||
diff --git a/apps/plugins/mpegplayer/stream_mgr.c b/apps/plugins/mpegplayer/stream_mgr.c deleted file mode 100644 index 3cac8c0f57..0000000000 --- a/apps/plugins/mpegplayer/stream_mgr.c +++ /dev/null | |||
@@ -1,1163 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * AV stream manager implementation | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #include "plugin.h" | ||
24 | #include "mpegplayer.h" | ||
25 | #include "lib/grey.h" | ||
26 | #include "mpeg_settings.h" | ||
27 | |||
28 | #ifndef HAVE_LCD_COLOR | ||
29 | GREY_INFO_STRUCT_IRAM | ||
30 | #endif | ||
31 | |||
32 | static struct event_queue stream_mgr_queue SHAREDBSS_ATTR; | ||
33 | static struct queue_sender_list stream_mgr_queue_send SHAREDBSS_ATTR; | ||
34 | static uint32_t stream_mgr_thread_stack[DEFAULT_STACK_SIZE*2/sizeof(uint32_t)]; | ||
35 | |||
36 | struct stream_mgr stream_mgr SHAREDBSS_ATTR; | ||
37 | |||
38 | /* Forward decs */ | ||
39 | static int stream_on_close(void); | ||
40 | |||
41 | struct str_broadcast_data | ||
42 | { | ||
43 | long cmd; /* Command to send to stream */ | ||
44 | intptr_t data; /* Data to send with command */ | ||
45 | }; | ||
46 | |||
47 | static inline void stream_mgr_lock(void) | ||
48 | { | ||
49 | rb->mutex_lock(&stream_mgr.str_mtx); | ||
50 | } | ||
51 | |||
52 | static inline void stream_mgr_unlock(void) | ||
53 | { | ||
54 | rb->mutex_unlock(&stream_mgr.str_mtx); | ||
55 | } | ||
56 | |||
57 | static inline void actl_lock(void) | ||
58 | { | ||
59 | rb->mutex_lock(&stream_mgr.actl_mtx); | ||
60 | } | ||
61 | |||
62 | static inline void actl_unlock(void) | ||
63 | { | ||
64 | rb->mutex_unlock(&stream_mgr.actl_mtx); | ||
65 | } | ||
66 | |||
67 | static inline void stream_mgr_post_msg(long id, intptr_t data) | ||
68 | { | ||
69 | rb->queue_post(stream_mgr.q, id, data); | ||
70 | } | ||
71 | |||
72 | static inline intptr_t stream_mgr_send_msg(long id, intptr_t data) | ||
73 | { | ||
74 | return rb->queue_send(stream_mgr.q, id, data); | ||
75 | } | ||
76 | |||
77 | static inline void stream_mgr_reply_msg(intptr_t retval) | ||
78 | { | ||
79 | rb->queue_reply(stream_mgr.q, retval); | ||
80 | } | ||
81 | |||
82 | int str_next_data_not_ready(struct stream *str) | ||
83 | { | ||
84 | /* Save the current window since it actually might be ready by the time | ||
85 | * the registration is received by buffering. */ | ||
86 | off_t win_right = str->hdr.win_right; | ||
87 | |||
88 | if (str->hdr.win_right < disk_buf.filesize - MIN_BUFAHEAD && | ||
89 | disk_buf.filesize > MIN_BUFAHEAD) | ||
90 | { | ||
91 | /* Set right edge to where probing left off + the minimum margin */ | ||
92 | str->hdr.win_right += MIN_BUFAHEAD; | ||
93 | } | ||
94 | else | ||
95 | { | ||
96 | /* Request would be passed the end of the file */ | ||
97 | str->hdr.win_right = disk_buf.filesize; | ||
98 | } | ||
99 | |||
100 | switch (disk_buf_send_msg(DISK_BUF_DATA_NOTIFY, (intptr_t)str)) | ||
101 | { | ||
102 | case DISK_BUF_NOTIFY_OK: | ||
103 | /* Was ready - restore window and process */ | ||
104 | str->hdr.win_right = win_right; | ||
105 | return STREAM_OK; | ||
106 | |||
107 | case DISK_BUF_NOTIFY_ERROR: | ||
108 | /* Error - quit parsing */ | ||
109 | str_end_of_stream(str); | ||
110 | return STREAM_DATA_END; | ||
111 | |||
112 | default: | ||
113 | /* Not ready - go wait for notification from buffering. */ | ||
114 | str->pkt_flags = 0; | ||
115 | return STREAM_DATA_NOT_READY; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | void str_data_notify_received(struct stream *str) | ||
120 | { | ||
121 | /* Normalize win_right back to the packet length */ | ||
122 | if (str->state == SSTATE_END) | ||
123 | return; | ||
124 | |||
125 | if (str->curr_packet == NULL) | ||
126 | { | ||
127 | /* Nothing was yet parsed since init */ | ||
128 | str->hdr.win_right = str->hdr.win_left; | ||
129 | } | ||
130 | else | ||
131 | { | ||
132 | /* Restore window based upon current packet */ | ||
133 | str->hdr.win_right = str->hdr.win_left + | ||
134 | (str->curr_packet_end - str->curr_packet); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /* Set stream manager to a "no-file" state */ | ||
139 | static void stream_mgr_init_state(void) | ||
140 | { | ||
141 | stream_mgr.filename = NULL; | ||
142 | stream_mgr.resume_time = INVALID_TIMESTAMP; | ||
143 | stream_mgr.seeked = false; | ||
144 | } | ||
145 | |||
146 | /* Add a stream to the playback pool */ | ||
147 | void stream_add_stream(struct stream *str) | ||
148 | { | ||
149 | actl_lock(); | ||
150 | |||
151 | list_remove_item(stream_mgr.strl, str); | ||
152 | list_add_item(stream_mgr.strl, str); | ||
153 | |||
154 | actl_unlock(); | ||
155 | } | ||
156 | |||
157 | /* Callback for various list-moving operations */ | ||
158 | static bool strl_enum_callback(struct stream *str, void *data) | ||
159 | { | ||
160 | actl_lock(); | ||
161 | |||
162 | list_remove_item(stream_mgr.strl, str); | ||
163 | |||
164 | if (*(int*)data == 1) | ||
165 | list_add_item(stream_mgr.actl, str); | ||
166 | |||
167 | actl_unlock(); | ||
168 | |||
169 | return true; | ||
170 | } | ||
171 | |||
172 | /* Clear all streams from active and playback pools */ | ||
173 | void stream_remove_streams(void) | ||
174 | { | ||
175 | int add_item = 0; | ||
176 | list_enum_items(stream_mgr.strl, | ||
177 | (list_enum_callback_t)strl_enum_callback, (void *)&add_item); | ||
178 | } | ||
179 | |||
180 | /* Move the playback pool to the active list */ | ||
181 | void move_strl_to_actl(void) | ||
182 | { | ||
183 | int add_item = 1; | ||
184 | list_enum_items(stream_mgr.strl, | ||
185 | (list_enum_callback_t)strl_enum_callback, (void *)&add_item); | ||
186 | } | ||
187 | |||
188 | /* Remove a stream from the active list and return it to the pool */ | ||
189 | static bool actl_stream_remove(struct stream *str) | ||
190 | { | ||
191 | bool retval; | ||
192 | |||
193 | actl_lock(); | ||
194 | |||
195 | retval = list_remove_item(stream_mgr.actl, str); | ||
196 | |||
197 | if (retval) | ||
198 | list_add_item(stream_mgr.strl, str); | ||
199 | |||
200 | actl_unlock(); | ||
201 | |||
202 | return retval; | ||
203 | } | ||
204 | |||
205 | /* Broadcast a message to all active streams */ | ||
206 | static bool actl_stream_broadcast_callback(struct stream *str, | ||
207 | struct str_broadcast_data *sbd) | ||
208 | { | ||
209 | switch (sbd->cmd) | ||
210 | { | ||
211 | case STREAM_PLAY: | ||
212 | case STREAM_PAUSE: | ||
213 | break; | ||
214 | |||
215 | case STREAM_STOP: | ||
216 | if (sbd->data != 0) | ||
217 | { | ||
218 | actl_lock(); | ||
219 | |||
220 | list_remove_item(stream_mgr.actl, str); | ||
221 | list_add_item(stream_mgr.strl, str); | ||
222 | |||
223 | actl_unlock(); | ||
224 | sbd->data = 0; | ||
225 | } | ||
226 | break; | ||
227 | |||
228 | default: | ||
229 | return false; | ||
230 | } | ||
231 | |||
232 | str_send_msg(str, sbd->cmd, sbd->data); | ||
233 | return true; | ||
234 | } | ||
235 | |||
236 | static void actl_stream_broadcast(int cmd, intptr_t data) | ||
237 | { | ||
238 | struct str_broadcast_data sbd; | ||
239 | sbd.cmd = cmd; | ||
240 | sbd.data = data; | ||
241 | list_enum_items(stream_mgr.actl, | ||
242 | (list_enum_callback_t)actl_stream_broadcast_callback, | ||
243 | (void*)&sbd); | ||
244 | } | ||
245 | |||
246 | /* Set the current base clock */ | ||
247 | static void set_stream_clock(uint32_t time) | ||
248 | { | ||
249 | /* Fudge: Start clock 100ms early to allow for some filling time */ | ||
250 | if (time > 100*TS_SECOND/1000) | ||
251 | time -= 100*TS_SECOND/1000; | ||
252 | else | ||
253 | time = 0; | ||
254 | |||
255 | pcm_output_set_clock(TS_TO_TICKS(time)); | ||
256 | } | ||
257 | |||
258 | static void stream_start_playback(uint32_t time, bool fill_buffer) | ||
259 | { | ||
260 | if (stream_mgr.seeked) | ||
261 | { | ||
262 | /* Clear any seeked status */ | ||
263 | stream_mgr.seeked = false; | ||
264 | |||
265 | /* Flush old PCM data */ | ||
266 | pcm_output_flush(); | ||
267 | |||
268 | /* Set the master clock */ | ||
269 | set_stream_clock(time); | ||
270 | |||
271 | /* Make sure streams are back in active pool */ | ||
272 | move_strl_to_actl(); | ||
273 | |||
274 | /* Prepare the parser and associated streams */ | ||
275 | parser_prepare_streaming(); | ||
276 | } | ||
277 | |||
278 | /* Start buffer which optional force fill */ | ||
279 | disk_buf_send_msg(STREAM_PLAY, fill_buffer); | ||
280 | |||
281 | /* Tell each stream to start - may generate end of stream signals | ||
282 | * now - we'll handle this when finished */ | ||
283 | actl_stream_broadcast(STREAM_PLAY, 0); | ||
284 | |||
285 | /* Actually start the clock */ | ||
286 | pcm_output_play_pause(true); | ||
287 | } | ||
288 | |||
289 | /* Return the play time relative to the specified play time */ | ||
290 | static uint32_t time_from_whence(uint32_t time, int whence) | ||
291 | { | ||
292 | int64_t currtime; | ||
293 | uint32_t start; | ||
294 | |||
295 | switch (whence) | ||
296 | { | ||
297 | case SEEK_SET: | ||
298 | /* Set the current time (time = unsigned offset from 0) */ | ||
299 | if (time > str_parser.duration) | ||
300 | time = str_parser.duration; | ||
301 | break; | ||
302 | case SEEK_CUR: | ||
303 | /* Seek forward or backward from the current time | ||
304 | * (time = signed offset from current) */ | ||
305 | currtime = stream_get_seek_time(&start); | ||
306 | currtime -= start; | ||
307 | currtime += (int32_t)time; | ||
308 | |||
309 | if (currtime < 0) | ||
310 | currtime = 0; | ||
311 | else if ((uint64_t)currtime > str_parser.duration) | ||
312 | currtime = str_parser.duration; | ||
313 | |||
314 | time = (uint32_t)currtime; | ||
315 | break; | ||
316 | case SEEK_END: | ||
317 | /* Seek from the end (time = unsigned offset from end) */ | ||
318 | if (time > str_parser.duration) | ||
319 | time = str_parser.duration; | ||
320 | time = str_parser.duration - time; | ||
321 | break; | ||
322 | } | ||
323 | |||
324 | return time; | ||
325 | } | ||
326 | |||
327 | /* Handle seeking details if playing or paused */ | ||
328 | static uint32_t stream_seek_intl(uint32_t time, int whence, | ||
329 | int status, bool *was_buffering) | ||
330 | { | ||
331 | if (status != STREAM_STOPPED) | ||
332 | { | ||
333 | bool wb; | ||
334 | |||
335 | /* Place streams in a non-running state - keep them on actl if | ||
336 | * still there */ | ||
337 | actl_stream_broadcast(STREAM_PAUSE, 0); | ||
338 | |||
339 | /* Stop all buffering or else risk clobbering random-access data */ | ||
340 | wb = disk_buf_send_msg(STREAM_STOP, 0); | ||
341 | |||
342 | if (was_buffering != NULL) | ||
343 | *was_buffering = wb; | ||
344 | } | ||
345 | |||
346 | time = time_from_whence(time, whence); | ||
347 | |||
348 | stream_mgr.seeked = true; | ||
349 | |||
350 | return parser_seek_time(time); | ||
351 | } | ||
352 | |||
353 | /* Store the resume time at the last seek/current clock point */ | ||
354 | static void stream_remember_resume_time(void) | ||
355 | { | ||
356 | /* Assume invalidity */ | ||
357 | stream_mgr.resume_time = 0; | ||
358 | |||
359 | if (stream_can_seek()) | ||
360 | { | ||
361 | /* Read the current stream time or the last seeked position */ | ||
362 | uint32_t start; | ||
363 | uint32_t time = stream_get_seek_time(&start); | ||
364 | |||
365 | if (time >= str_parser.start_pts && time <= str_parser.end_pts) | ||
366 | { | ||
367 | /* Save the current stream time */ | ||
368 | stream_mgr.resume_time = time - start; | ||
369 | } | ||
370 | } | ||
371 | } | ||
372 | |||
373 | /* Handle STREAM_OPEN */ | ||
374 | void stream_on_open(const char *filename) | ||
375 | { | ||
376 | int err = STREAM_ERROR; | ||
377 | |||
378 | stream_mgr_lock(); | ||
379 | |||
380 | trigger_cpu_boost(); | ||
381 | |||
382 | /* Open the video file */ | ||
383 | if (disk_buf_open(filename) >= 0) | ||
384 | { | ||
385 | /* Initialize the parser */ | ||
386 | err = parser_init_stream(); | ||
387 | |||
388 | if (err >= STREAM_OK) | ||
389 | { | ||
390 | /* File ok - save the opened filename */ | ||
391 | stream_mgr.filename = filename; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | /* If error - cleanup */ | ||
396 | if (err < STREAM_OK) | ||
397 | stream_on_close(); | ||
398 | |||
399 | cancel_cpu_boost(); | ||
400 | |||
401 | stream_mgr_unlock(); | ||
402 | |||
403 | stream_mgr_reply_msg(err); | ||
404 | } | ||
405 | |||
406 | /* Handler STREAM_PLAY */ | ||
407 | static void stream_on_play(void) | ||
408 | { | ||
409 | int status = stream_mgr.status; | ||
410 | |||
411 | stream_mgr_lock(); | ||
412 | |||
413 | if (status == STREAM_STOPPED) | ||
414 | { | ||
415 | uint32_t start; | ||
416 | |||
417 | /* We just say we're playing now */ | ||
418 | stream_mgr.status = STREAM_PLAYING; | ||
419 | |||
420 | /* Reply with previous state */ | ||
421 | stream_mgr_reply_msg(status); | ||
422 | |||
423 | trigger_cpu_boost(); | ||
424 | |||
425 | /* Seek to initial position and set clock to that time */ | ||
426 | |||
427 | /* Save the resume time */ | ||
428 | stream_remember_resume_time(); | ||
429 | |||
430 | /* Prepare seek to start point */ | ||
431 | start = stream_seek_intl(stream_mgr.resume_time, SEEK_SET, | ||
432 | STREAM_STOPPED, NULL); | ||
433 | |||
434 | /* Sync and start - force buffer fill */ | ||
435 | stream_start_playback(start, true); | ||
436 | } | ||
437 | else | ||
438 | { | ||
439 | /* Reply with previous state */ | ||
440 | stream_mgr_reply_msg(status); | ||
441 | } | ||
442 | |||
443 | stream_mgr_unlock(); | ||
444 | } | ||
445 | |||
446 | /* Handle STREAM_PAUSE */ | ||
447 | static void stream_on_pause(void) | ||
448 | { | ||
449 | int status = stream_mgr.status; | ||
450 | |||
451 | stream_mgr_lock(); | ||
452 | |||
453 | /* Reply with previous state */ | ||
454 | stream_mgr_reply_msg(status); | ||
455 | |||
456 | if (status == STREAM_PLAYING) | ||
457 | { | ||
458 | /* Pause the clock */ | ||
459 | pcm_output_play_pause(false); | ||
460 | |||
461 | /* Pause each active stream */ | ||
462 | actl_stream_broadcast(STREAM_PAUSE, 0); | ||
463 | |||
464 | /* Pause the disk buffer - buffer may continue filling */ | ||
465 | disk_buf_send_msg(STREAM_PAUSE, false); | ||
466 | |||
467 | /* Unboost the CPU */ | ||
468 | cancel_cpu_boost(); | ||
469 | |||
470 | /* Offically paused */ | ||
471 | stream_mgr.status = STREAM_PAUSED; | ||
472 | } | ||
473 | |||
474 | stream_mgr_unlock(); | ||
475 | } | ||
476 | |||
477 | /* Handle STREAM_RESUME */ | ||
478 | static void stream_on_resume(void) | ||
479 | { | ||
480 | int status = stream_mgr.status; | ||
481 | |||
482 | stream_mgr_lock(); | ||
483 | |||
484 | /* Reply with previous state */ | ||
485 | stream_mgr_reply_msg(status); | ||
486 | |||
487 | if (status == STREAM_PAUSED) | ||
488 | { | ||
489 | /* Boost the CPU */ | ||
490 | trigger_cpu_boost(); | ||
491 | |||
492 | /* Sync and start - no force buffering */ | ||
493 | stream_start_playback(str_parser.last_seek_time, false); | ||
494 | |||
495 | /* Officially playing */ | ||
496 | stream_mgr.status = STREAM_PLAYING; | ||
497 | } | ||
498 | |||
499 | stream_mgr_unlock(); | ||
500 | } | ||
501 | |||
502 | /* Handle STREAM_STOP */ | ||
503 | static void stream_on_stop(bool reply) | ||
504 | { | ||
505 | int status = stream_mgr.status; | ||
506 | |||
507 | stream_mgr_lock(); | ||
508 | |||
509 | if (reply) | ||
510 | stream_mgr_reply_msg(status); | ||
511 | |||
512 | if (status != STREAM_STOPPED) | ||
513 | { | ||
514 | /* Pause the clock */ | ||
515 | pcm_output_play_pause(false); | ||
516 | |||
517 | /* Update the resume time info */ | ||
518 | stream_remember_resume_time(); | ||
519 | |||
520 | /* Not stopped = paused or playing */ | ||
521 | stream_mgr.seeked = false; | ||
522 | |||
523 | /* Stop buffering */ | ||
524 | disk_buf_send_msg(STREAM_STOP, 0); | ||
525 | |||
526 | /* Clear any still-active streams and remove from actl */ | ||
527 | actl_stream_broadcast(STREAM_STOP, 1); | ||
528 | |||
529 | /* Stop PCM output (and clock) */ | ||
530 | pcm_output_stop(); | ||
531 | |||
532 | /* Cancel our processor boost */ | ||
533 | cancel_cpu_boost(); | ||
534 | |||
535 | stream_mgr.status = STREAM_STOPPED; | ||
536 | } | ||
537 | |||
538 | stream_mgr_unlock(); | ||
539 | } | ||
540 | |||
541 | /* Handle STREAM_SEEK */ | ||
542 | static void stream_on_seek(struct stream_seek_data *skd) | ||
543 | { | ||
544 | uint32_t time = skd->time; | ||
545 | int whence = skd->whence; | ||
546 | |||
547 | switch (whence) | ||
548 | { | ||
549 | case SEEK_SET: | ||
550 | case SEEK_CUR: | ||
551 | case SEEK_END: | ||
552 | if (stream_mgr.filename == NULL) | ||
553 | break; | ||
554 | |||
555 | /* Keep things spinning if already doing so */ | ||
556 | stream_keep_disk_active(); | ||
557 | |||
558 | /* Have data - reply in order to acquire lock */ | ||
559 | stream_mgr_reply_msg(STREAM_OK); | ||
560 | |||
561 | stream_mgr_lock(); | ||
562 | |||
563 | /* Either seeking must be possible or a full rewind must be done */ | ||
564 | if (stream_can_seek() || time_from_whence(time, whence) == 0) | ||
565 | { | ||
566 | bool buffer = false; | ||
567 | |||
568 | if (stream_mgr.status == STREAM_PLAYING) | ||
569 | { | ||
570 | /* Keep clock from advancing while seeking */ | ||
571 | pcm_output_play_pause(false); | ||
572 | } | ||
573 | |||
574 | time = stream_seek_intl(time, whence, stream_mgr.status, &buffer); | ||
575 | stream_remember_resume_time(); | ||
576 | |||
577 | if (stream_mgr.status == STREAM_PLAYING) | ||
578 | { | ||
579 | /* Sync and restart - no force buffering */ | ||
580 | stream_start_playback(time, buffer); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | stream_mgr_unlock(); | ||
585 | return; | ||
586 | } | ||
587 | |||
588 | /* Invalid parameter or no file */ | ||
589 | stream_mgr_reply_msg(STREAM_ERROR); | ||
590 | } | ||
591 | |||
592 | /* Handle STREAM_CLOSE */ | ||
593 | static int stream_on_close(void) | ||
594 | { | ||
595 | int status = STREAM_STOPPED; | ||
596 | |||
597 | stream_mgr_lock(); | ||
598 | |||
599 | /* Any open file that was accepted for playback? */ | ||
600 | if (stream_mgr.filename != NULL) | ||
601 | { | ||
602 | /* Yes - hide video */ | ||
603 | stream_show_vo(false); | ||
604 | /* Stop any playback */ | ||
605 | status = stream_mgr.status; | ||
606 | stream_on_stop(false); | ||
607 | /* Tell parser file is finished */ | ||
608 | parser_close_stream(); | ||
609 | /* Reinitialize manager */ | ||
610 | stream_mgr_init_state(); | ||
611 | } | ||
612 | |||
613 | /* Let disk buffer reset itself - file might be open even if no good */ | ||
614 | disk_buf_close(); | ||
615 | |||
616 | stream_mgr_unlock(); | ||
617 | |||
618 | return status; | ||
619 | } | ||
620 | |||
621 | /* Handle STREAM_EV_COMPLETE */ | ||
622 | static void stream_on_ev_complete(struct stream *str) | ||
623 | { | ||
624 | stream_mgr_lock(); | ||
625 | |||
626 | /* Stream is active? */ | ||
627 | if (actl_stream_remove(str)) | ||
628 | { | ||
629 | /* No - remove this stream from the active list */ | ||
630 | DEBUGF(" finished: 0x%02x\n", str->id); | ||
631 | if (list_is_empty(stream_mgr.actl)) | ||
632 | { | ||
633 | /* All streams have acked - stop playback */ | ||
634 | stream_on_stop(false); | ||
635 | stream_mgr.resume_time = 0; /* Played to end - no resume */ | ||
636 | } | ||
637 | else | ||
638 | { | ||
639 | /* Stream is done - stop it and place back in pool */ | ||
640 | str_send_msg(str, STREAM_STOP, 1); | ||
641 | } | ||
642 | } | ||
643 | |||
644 | stream_mgr_unlock(); | ||
645 | } | ||
646 | |||
647 | /* Callback for stream to notify about events internal to them */ | ||
648 | void stream_generate_event(struct stream *str, long id, intptr_t data) | ||
649 | { | ||
650 | if (str == NULL) | ||
651 | return; | ||
652 | |||
653 | switch (id) | ||
654 | { | ||
655 | case STREAM_EV_COMPLETE: | ||
656 | /* The last stream has ended */ | ||
657 | stream_mgr_post_msg(STREAM_EV_COMPLETE, (intptr_t)str); | ||
658 | break; | ||
659 | } | ||
660 | |||
661 | (void)data; | ||
662 | } | ||
663 | |||
664 | /* Clear any particular notification for which a stream registered */ | ||
665 | void stream_clear_notify(struct stream *str, int for_msg) | ||
666 | { | ||
667 | switch (for_msg) | ||
668 | { | ||
669 | case DISK_BUF_DATA_NOTIFY: | ||
670 | disk_buf_send_msg(DISK_BUF_CLEAR_DATA_NOTIFY, (intptr_t)str); | ||
671 | break; | ||
672 | } | ||
673 | } | ||
674 | |||
675 | /* Special handling for certain messages since they involve multiple | ||
676 | * operations behind the scenes */ | ||
677 | static intptr_t send_video_msg(long id, intptr_t data) | ||
678 | { | ||
679 | intptr_t retval = 0; | ||
680 | |||
681 | if (video_str.thread != 0 && disk_buf.in_file >= 0) | ||
682 | { | ||
683 | |||
684 | switch (id) | ||
685 | { | ||
686 | case VIDEO_DISPLAY_SHOW: | ||
687 | if (data != 0 && disk_buf_status() == STREAM_STOPPED) | ||
688 | { /* Only prepare image if showing and not playing */ | ||
689 | parser_prepare_image(str_parser.last_seek_time); | ||
690 | } | ||
691 | break; | ||
692 | |||
693 | case VIDEO_PRINT_FRAME: | ||
694 | if (data) | ||
695 | break; | ||
696 | case VIDEO_PRINT_THUMBNAIL: | ||
697 | if (disk_buf_status() != STREAM_STOPPED) | ||
698 | break; /* Prepare image if not playing */ | ||
699 | |||
700 | /* Ignore return and try video thread anyway */ | ||
701 | parser_prepare_image(str_parser.last_seek_time); | ||
702 | |||
703 | /* Image ready - pass message to video thread */ | ||
704 | break; | ||
705 | } | ||
706 | |||
707 | retval = str_send_msg(&video_str, id, data); | ||
708 | } | ||
709 | |||
710 | return retval; | ||
711 | } | ||
712 | |||
713 | /* Show/hide the video output */ | ||
714 | bool stream_show_vo(bool show) | ||
715 | { | ||
716 | bool vis; | ||
717 | stream_mgr_lock(); | ||
718 | |||
719 | vis = send_video_msg(VIDEO_DISPLAY_SHOW, show); | ||
720 | #ifndef HAVE_LCD_COLOR | ||
721 | grey_show(show); | ||
722 | #endif | ||
723 | stream_mgr_unlock(); | ||
724 | |||
725 | return vis; | ||
726 | } | ||
727 | |||
728 | /* Query the visibility of video output */ | ||
729 | bool stream_vo_is_visible(void) | ||
730 | { | ||
731 | bool vis; | ||
732 | stream_mgr_lock(); | ||
733 | vis = send_video_msg(VIDEO_DISPLAY_IS_VISIBLE, 0); | ||
734 | stream_mgr_unlock(); | ||
735 | return vis; | ||
736 | } | ||
737 | |||
738 | /* Return the video dimensions */ | ||
739 | bool stream_vo_get_size(struct vo_ext *sz) | ||
740 | { | ||
741 | bool retval = false; | ||
742 | |||
743 | stream_mgr_lock(); | ||
744 | |||
745 | if (str_parser.dims.w > 0 && str_parser.dims.h > 0) | ||
746 | { | ||
747 | *sz = str_parser.dims; | ||
748 | retval = true; | ||
749 | } | ||
750 | |||
751 | stream_mgr_unlock(); | ||
752 | |||
753 | return retval; | ||
754 | } | ||
755 | |||
756 | void stream_vo_set_clip(const struct vo_rect *rc) | ||
757 | { | ||
758 | stream_mgr_lock(); | ||
759 | |||
760 | if (rc) | ||
761 | { | ||
762 | stream_mgr.parms.rc = *rc; | ||
763 | rc = &stream_mgr.parms.rc; | ||
764 | } | ||
765 | |||
766 | send_video_msg(VIDEO_SET_CLIP_RECT, (intptr_t)rc); | ||
767 | |||
768 | stream_mgr_unlock(); | ||
769 | } | ||
770 | |||
771 | bool stream_vo_get_clip(struct vo_rect *rc) | ||
772 | { | ||
773 | bool retval; | ||
774 | |||
775 | if (!rc) | ||
776 | return false; | ||
777 | |||
778 | stream_mgr_lock(); | ||
779 | |||
780 | retval = send_video_msg(VIDEO_GET_CLIP_RECT, | ||
781 | (intptr_t)&stream_mgr.parms.rc); | ||
782 | |||
783 | *rc = stream_mgr.parms.rc; | ||
784 | |||
785 | stream_mgr_unlock(); | ||
786 | |||
787 | return retval; | ||
788 | } | ||
789 | |||
790 | #ifndef HAVE_LCD_COLOR | ||
791 | /* Show/hide the gray video overlay (independently of vo visibility). */ | ||
792 | void stream_gray_show(bool show) | ||
793 | { | ||
794 | stream_mgr_lock(); | ||
795 | |||
796 | grey_show(show); | ||
797 | |||
798 | stream_mgr_unlock(); | ||
799 | } | ||
800 | |||
801 | #endif /* !HAVE_LCD_COLOR */ | ||
802 | |||
803 | /* Display a thumbnail at the last seek point */ | ||
804 | bool stream_display_thumb(const struct vo_rect *rc) | ||
805 | { | ||
806 | bool retval; | ||
807 | |||
808 | if (rc == NULL) | ||
809 | return false; | ||
810 | |||
811 | stream_mgr_lock(); | ||
812 | |||
813 | stream_mgr.parms.rc = *rc; | ||
814 | retval = send_video_msg(VIDEO_PRINT_THUMBNAIL, | ||
815 | (intptr_t)&stream_mgr.parms.rc); | ||
816 | |||
817 | stream_mgr_unlock(); | ||
818 | |||
819 | return retval; | ||
820 | } | ||
821 | |||
822 | bool stream_draw_frame(bool no_prepare) | ||
823 | { | ||
824 | bool retval; | ||
825 | stream_mgr_lock(); | ||
826 | |||
827 | retval = send_video_msg(VIDEO_PRINT_FRAME, no_prepare); | ||
828 | |||
829 | stream_mgr_unlock(); | ||
830 | |||
831 | return retval; | ||
832 | } | ||
833 | |||
834 | bool stream_set_callback(long id, void *fn) | ||
835 | { | ||
836 | bool retval = false; | ||
837 | |||
838 | stream_mgr_lock(); | ||
839 | |||
840 | switch (id) | ||
841 | { | ||
842 | case VIDEO_SET_POST_FRAME_CALLBACK: | ||
843 | retval = send_video_msg(id, (intptr_t)fn); | ||
844 | } | ||
845 | |||
846 | stream_mgr_unlock(); | ||
847 | |||
848 | return retval; | ||
849 | } | ||
850 | |||
851 | /* Return the time playback should resume if interrupted */ | ||
852 | uint32_t stream_get_resume_time(void) | ||
853 | { | ||
854 | uint32_t resume_time; | ||
855 | |||
856 | /* A stop request is async and replies before setting this - must lock */ | ||
857 | stream_mgr_lock(); | ||
858 | |||
859 | resume_time = stream_mgr.resume_time; | ||
860 | |||
861 | stream_mgr_unlock(); | ||
862 | |||
863 | return resume_time; | ||
864 | } | ||
865 | |||
866 | uint32_t stream_get_seek_time(uint32_t *start) | ||
867 | { | ||
868 | uint32_t time; | ||
869 | |||
870 | stream_mgr_lock(); | ||
871 | |||
872 | if (stream_mgr.seeked) | ||
873 | { | ||
874 | time = str_parser.last_seek_time; | ||
875 | } | ||
876 | else | ||
877 | { | ||
878 | time = TICKS_TO_TS(pcm_output_get_clock()); | ||
879 | |||
880 | /* Clock can be start early so keep in range */ | ||
881 | if (time < str_parser.start_pts) | ||
882 | time = str_parser.start_pts; | ||
883 | } | ||
884 | |||
885 | if (start != NULL) | ||
886 | *start = str_parser.start_pts; | ||
887 | |||
888 | stream_mgr_unlock(); | ||
889 | |||
890 | return time; | ||
891 | } | ||
892 | |||
893 | /* Wait for a state transistion to complete */ | ||
894 | void stream_wait_status(void) | ||
895 | { | ||
896 | stream_mgr_lock(); | ||
897 | stream_mgr_unlock(); | ||
898 | } | ||
899 | |||
900 | /* Returns the smallest file window that includes all active streams' | ||
901 | * windows */ | ||
902 | static bool stream_get_window_callback(struct stream *str, | ||
903 | struct stream_window *sw) | ||
904 | { | ||
905 | off_t swl = str->hdr.win_left; | ||
906 | off_t swr = str->hdr.win_right; | ||
907 | |||
908 | if (swl < sw->left) | ||
909 | sw->left = swl; | ||
910 | |||
911 | if (swr > sw->right) | ||
912 | sw->right = swr; | ||
913 | |||
914 | return true; | ||
915 | } | ||
916 | |||
917 | bool stream_get_window(struct stream_window *sw) | ||
918 | { | ||
919 | if (sw == NULL) | ||
920 | return false; | ||
921 | |||
922 | sw->left = LONG_MAX; | ||
923 | sw->right = LONG_MIN; | ||
924 | |||
925 | actl_lock(); | ||
926 | list_enum_items(stream_mgr.actl, | ||
927 | (list_enum_callback_t)stream_get_window_callback, | ||
928 | (void*)sw); | ||
929 | actl_unlock(); | ||
930 | |||
931 | return sw->left <= sw->right; | ||
932 | } | ||
933 | |||
934 | /* Playback control thread */ | ||
935 | static void stream_mgr_thread(void) | ||
936 | { | ||
937 | struct queue_event ev; | ||
938 | |||
939 | while (1) | ||
940 | { | ||
941 | rb->queue_wait(stream_mgr.q, &ev); | ||
942 | |||
943 | switch (ev.id) | ||
944 | { | ||
945 | case STREAM_OPEN: | ||
946 | stream_on_open((const char *)ev.data); | ||
947 | break; | ||
948 | |||
949 | case STREAM_CLOSE: | ||
950 | stream_on_close(); | ||
951 | break; | ||
952 | |||
953 | case STREAM_PLAY: | ||
954 | stream_on_play(); | ||
955 | break; | ||
956 | |||
957 | case STREAM_PAUSE: | ||
958 | if (ev.data) | ||
959 | stream_on_resume(); | ||
960 | else | ||
961 | stream_on_pause(); | ||
962 | break; | ||
963 | |||
964 | case STREAM_STOP: | ||
965 | stream_on_stop(true); | ||
966 | break; | ||
967 | |||
968 | case STREAM_SEEK: | ||
969 | stream_on_seek((struct stream_seek_data *)ev.data); | ||
970 | break; | ||
971 | |||
972 | case STREAM_EV_COMPLETE: | ||
973 | stream_on_ev_complete((struct stream *)ev.data); | ||
974 | break; | ||
975 | |||
976 | case STREAM_QUIT: | ||
977 | if (stream_mgr.status != STREAM_STOPPED) | ||
978 | stream_on_stop(false); | ||
979 | return; | ||
980 | } | ||
981 | } | ||
982 | } | ||
983 | |||
984 | /* Stream command interface APIs */ | ||
985 | |||
986 | /* Opens a new file */ | ||
987 | int stream_open(const char *filename) | ||
988 | { | ||
989 | if (stream_mgr.thread != 0) | ||
990 | return stream_mgr_send_msg(STREAM_OPEN, (intptr_t)filename); | ||
991 | return STREAM_ERROR; | ||
992 | } | ||
993 | |||
994 | /* Plays the current file starting at time 'start' */ | ||
995 | int stream_play(void) | ||
996 | { | ||
997 | if (stream_mgr.thread != 0) | ||
998 | return stream_mgr_send_msg(STREAM_PLAY, 0); | ||
999 | return STREAM_ERROR; | ||
1000 | } | ||
1001 | |||
1002 | /* Pauses playback if playing */ | ||
1003 | int stream_pause(void) | ||
1004 | { | ||
1005 | if (stream_mgr.thread != 0) | ||
1006 | return stream_mgr_send_msg(STREAM_PAUSE, false); | ||
1007 | return STREAM_ERROR; | ||
1008 | } | ||
1009 | |||
1010 | /* Resumes playback if paused */ | ||
1011 | int stream_resume(void) | ||
1012 | { | ||
1013 | if (stream_mgr.thread != 0) | ||
1014 | return stream_mgr_send_msg(STREAM_PAUSE, true); | ||
1015 | return STREAM_ERROR; | ||
1016 | } | ||
1017 | |||
1018 | /* Stops playback if not stopped */ | ||
1019 | int stream_stop(void) | ||
1020 | { | ||
1021 | if (stream_mgr.thread != 0) | ||
1022 | return stream_mgr_send_msg(STREAM_STOP, 0); | ||
1023 | return STREAM_ERROR; | ||
1024 | } | ||
1025 | |||
1026 | /* Seeks playback time to/by the specified time */ | ||
1027 | int stream_seek(uint32_t time, int whence) | ||
1028 | { | ||
1029 | int ret; | ||
1030 | |||
1031 | if (stream_mgr.thread == 0) | ||
1032 | return STREAM_ERROR; | ||
1033 | |||
1034 | stream_mgr_lock(); | ||
1035 | |||
1036 | stream_mgr.parms.skd.time = time; | ||
1037 | stream_mgr.parms.skd.whence = whence; | ||
1038 | |||
1039 | ret = stream_mgr_send_msg(STREAM_SEEK, (intptr_t)&stream_mgr.parms.skd); | ||
1040 | |||
1041 | stream_mgr_unlock(); | ||
1042 | |||
1043 | return ret; | ||
1044 | } | ||
1045 | |||
1046 | /* Closes the current file */ | ||
1047 | int stream_close(void) | ||
1048 | { | ||
1049 | if (stream_mgr.thread != 0) | ||
1050 | return stream_mgr_send_msg(STREAM_CLOSE, 0); | ||
1051 | return STREAM_ERROR; | ||
1052 | } | ||
1053 | |||
1054 | /* Initializes the playback engine */ | ||
1055 | int stream_init(void) | ||
1056 | { | ||
1057 | void *mem; | ||
1058 | size_t memsize; | ||
1059 | |||
1060 | stream_mgr.status = STREAM_STOPPED; | ||
1061 | stream_mgr_init_state(); | ||
1062 | |||
1063 | /* Initialize our window to the outside world first */ | ||
1064 | rb->mutex_init(&stream_mgr.str_mtx); | ||
1065 | rb->mutex_init(&stream_mgr.actl_mtx); | ||
1066 | |||
1067 | stream_mgr.q = &stream_mgr_queue; | ||
1068 | rb->queue_init(stream_mgr.q, false); | ||
1069 | |||
1070 | /* sets audiosize and returns buffer pointer */ | ||
1071 | mem = rb->plugin_get_audio_buffer(&memsize); | ||
1072 | |||
1073 | /* Initialize non-allocator blocks first */ | ||
1074 | #ifndef HAVE_LCD_COLOR | ||
1075 | long greysize; | ||
1076 | |||
1077 | /* Greylib init handles all necessary cache alignment */ | ||
1078 | if (!grey_init(mem, memsize, GREY_BUFFERED|GREY_ON_COP, | ||
1079 | LCD_WIDTH, LCD_HEIGHT, &greysize)) | ||
1080 | { | ||
1081 | rb->splash(HZ, "greylib init failed!"); | ||
1082 | return STREAM_ERROR; | ||
1083 | } | ||
1084 | |||
1085 | mem += greysize; | ||
1086 | memsize -= greysize; | ||
1087 | |||
1088 | grey_clear_display(); | ||
1089 | #endif /* !HAVE_LCD_COLOR */ | ||
1090 | |||
1091 | stream_mgr.thread = rb->create_thread(stream_mgr_thread, | ||
1092 | stream_mgr_thread_stack, sizeof(stream_mgr_thread_stack), | ||
1093 | 0, "mpgstream_mgr" IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU)); | ||
1094 | |||
1095 | rb->queue_enable_queue_send(stream_mgr.q, &stream_mgr_queue_send, | ||
1096 | stream_mgr.thread); | ||
1097 | |||
1098 | if (stream_mgr.thread == 0) | ||
1099 | { | ||
1100 | rb->splash(HZ, "Could not create stream manager thread!"); | ||
1101 | return STREAM_ERROR; | ||
1102 | } | ||
1103 | |||
1104 | /* Wait for thread to initialize */ | ||
1105 | stream_mgr_send_msg(STREAM_NULL, 0); | ||
1106 | |||
1107 | /* Initialise our malloc buffer */ | ||
1108 | if (!mpeg_alloc_init(mem, memsize)) | ||
1109 | { | ||
1110 | rb->splash(HZ, "Out of memory in stream_init"); | ||
1111 | } | ||
1112 | /* These inits use the allocator */ | ||
1113 | else if (!pcm_output_init()) | ||
1114 | { | ||
1115 | rb->splash(HZ, "Could not initialize PCM!"); | ||
1116 | } | ||
1117 | else if (!audio_thread_init()) | ||
1118 | { | ||
1119 | rb->splash(HZ, "Cannot create audio thread!"); | ||
1120 | } | ||
1121 | else if (!video_thread_init()) | ||
1122 | { | ||
1123 | rb->splash(HZ, "Cannot create video thread!"); | ||
1124 | } | ||
1125 | /* Disk buffer takes max allotment of what's left so it must be last */ | ||
1126 | else if (!disk_buf_init()) | ||
1127 | { | ||
1128 | rb->splash(HZ, "Cannot create buffering thread!"); | ||
1129 | } | ||
1130 | else if (!parser_init()) | ||
1131 | { | ||
1132 | rb->splash(HZ, "Parser init failed!"); | ||
1133 | } | ||
1134 | else | ||
1135 | { | ||
1136 | return STREAM_OK; | ||
1137 | } | ||
1138 | |||
1139 | return STREAM_ERROR; | ||
1140 | } | ||
1141 | |||
1142 | /* Cleans everything up */ | ||
1143 | void stream_exit(void) | ||
1144 | { | ||
1145 | stream_close(); | ||
1146 | |||
1147 | /* Stop the threads and wait for them to terminate */ | ||
1148 | video_thread_exit(); | ||
1149 | audio_thread_exit(); | ||
1150 | disk_buf_exit(); | ||
1151 | pcm_output_exit(); | ||
1152 | |||
1153 | if (stream_mgr.thread != 0) | ||
1154 | { | ||
1155 | stream_mgr_post_msg(STREAM_QUIT, 0); | ||
1156 | rb->thread_wait(stream_mgr.thread); | ||
1157 | stream_mgr.thread = 0; | ||
1158 | } | ||
1159 | |||
1160 | #ifndef HAVE_LCD_COLOR | ||
1161 | grey_release(); | ||
1162 | #endif | ||
1163 | } | ||
diff --git a/apps/plugins/mpegplayer/stream_mgr.h b/apps/plugins/mpegplayer/stream_mgr.h deleted file mode 100644 index 7dba9acc09..0000000000 --- a/apps/plugins/mpegplayer/stream_mgr.h +++ /dev/null | |||
@@ -1,168 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * AV stream manager decalarations | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #ifndef STREAM_MGR_H | ||
24 | #define STREAM_MGR_H | ||
25 | |||
26 | /* Basic media control interface - this handles state changes and stream | ||
27 | * coordination with assistance from the parser */ | ||
28 | struct stream_mgr | ||
29 | { | ||
30 | unsigned int thread; /* Playback control thread */ | ||
31 | struct event_queue *q; /* event queue for control thread */ | ||
32 | const char *filename; /* Current filename */ | ||
33 | uint32_t resume_time; /* The stream tick where playback was | ||
34 | stopped (or started) */ | ||
35 | bool seeked; /* A seek happened and things must be | ||
36 | resynced */ | ||
37 | int status; /* Current playback status */ | ||
38 | void *strl[MPEGPLAYER_MAX_STREAMS+1]; /* List of available streams */ | ||
39 | void *actl[MPEGPLAYER_MAX_STREAMS+1]; /* List of active streams */ | ||
40 | struct mutex str_mtx; /* Main stream manager mutex */ | ||
41 | struct mutex actl_mtx; /* Lock for current-streams list */ | ||
42 | union /* A place for reusable non-cacheable parameters */ | ||
43 | { | ||
44 | struct vo_rect rc; | ||
45 | struct stream_seek_data skd; | ||
46 | } parms; | ||
47 | }; | ||
48 | |||
49 | extern struct stream_mgr stream_mgr SHAREDBSS_ATTR; | ||
50 | |||
51 | struct stream_window | ||
52 | { | ||
53 | off_t left, right; | ||
54 | }; | ||
55 | |||
56 | /** Interface for use by streams and other internal objects **/ | ||
57 | bool stream_get_window(struct stream_window *sw); | ||
58 | void stream_clear_notify(struct stream *str, int for_msg); | ||
59 | int str_next_data_not_ready(struct stream *str); | ||
60 | /* Called by a stream to say it got its buffering notification */ | ||
61 | void str_data_notify_received(struct stream *str); | ||
62 | void stream_add_stream(struct stream *str); | ||
63 | void stream_remove_streams(void); | ||
64 | |||
65 | enum stream_events | ||
66 | { | ||
67 | __STREAM_EV_FIRST = STREAM_MESSAGE_LAST-1, | ||
68 | STREAM_EV_COMPLETE, | ||
69 | }; | ||
70 | |||
71 | void stream_generate_event(struct stream *str, long id, intptr_t data); | ||
72 | |||
73 | /** Main control functions **/ | ||
74 | |||
75 | /* Initialize the playback engine */ | ||
76 | int stream_init(void); | ||
77 | |||
78 | /* Close the playback engine */ | ||
79 | void stream_exit(void); | ||
80 | |||
81 | /* Open a new file */ | ||
82 | int stream_open(const char *filename); | ||
83 | |||
84 | /* Close the current file */ | ||
85 | int stream_close(void); | ||
86 | |||
87 | /* Plays from the current seekpoint if stopped */ | ||
88 | int stream_play(void); | ||
89 | |||
90 | /* Pauses playback if playing */ | ||
91 | int stream_pause(void); | ||
92 | |||
93 | /* Resumes playback if paused */ | ||
94 | int stream_resume(void); | ||
95 | |||
96 | /* Stops all streaming activity if playing or paused */ | ||
97 | int stream_stop(void); | ||
98 | |||
99 | /* Point stream at a particular time. | ||
100 | * whence = one of SEEK_SET, SEEK_CUR, SEEK_END */ | ||
101 | int stream_seek(uint32_t time, int whence); | ||
102 | |||
103 | /* Show/Hide the video image at the current seekpoint */ | ||
104 | bool stream_show_vo(bool show); | ||
105 | |||
106 | /* Set the visible section of video */ | ||
107 | void stream_vo_set_clip(const struct vo_rect *rc); | ||
108 | |||
109 | /* Return current visible section of video */ | ||
110 | bool stream_vo_get_clip(struct vo_rect *rc); | ||
111 | |||
112 | #ifndef HAVE_LCD_COLOR | ||
113 | void stream_gray_show(bool show); | ||
114 | #endif | ||
115 | |||
116 | /* Display thumbnail of the current seekpoint */ | ||
117 | bool stream_display_thumb(const struct vo_rect *rc); | ||
118 | |||
119 | /* Draw the frame at the current position */ | ||
120 | bool stream_draw_frame(bool no_prepare); | ||
121 | |||
122 | /* Return video dimensions */ | ||
123 | bool stream_vo_get_size(struct vo_ext *sz); | ||
124 | |||
125 | /* Returns the resume time in timestamp ticks */ | ||
126 | uint32_t stream_get_resume_time(void); | ||
127 | |||
128 | /* Returns stream_get_time if no seek is pending or else the | ||
129 | last time give to seek */ | ||
130 | uint32_t stream_get_seek_time(uint32_t *start); | ||
131 | |||
132 | /* Return the absolute stream time in clock ticks - adjusted by | ||
133 | * master clock stream via audio timestamps */ | ||
134 | static inline uint32_t stream_get_time(void) | ||
135 | { return pcm_output_get_clock(); } | ||
136 | |||
137 | /* Return the absolute clock time in clock ticks - unadjusted */ | ||
138 | static inline uint32_t stream_get_ticks(uint32_t *start) | ||
139 | { return pcm_output_get_ticks(start); } | ||
140 | |||
141 | /* Returns the current playback status */ | ||
142 | static inline int stream_status(void) | ||
143 | { return stream_mgr.status; } | ||
144 | |||
145 | /* Wait for a state transistion to complete */ | ||
146 | void stream_wait_status(void); | ||
147 | |||
148 | /* Returns the playback length of the stream */ | ||
149 | static inline uint32_t stream_get_duration(void) | ||
150 | { return str_parser.duration; } | ||
151 | |||
152 | static inline bool stream_can_seek(void) | ||
153 | { return parser_can_seek(); } | ||
154 | |||
155 | static inline void stream_video_stats(struct video_output_stats *s) | ||
156 | { video_thread_get_stats(s); } | ||
157 | |||
158 | bool stream_set_callback(long id, void * fn); | ||
159 | |||
160 | /* Keep the disk spinning (for seeking and browsing) */ | ||
161 | static inline void stream_keep_disk_active(void) | ||
162 | { | ||
163 | #ifdef HAVE_DISK_STORAGE | ||
164 | rb->storage_spin(); | ||
165 | #endif | ||
166 | } | ||
167 | |||
168 | #endif /* STREAM_MGR_H */ | ||
diff --git a/apps/plugins/mpegplayer/stream_thread.h b/apps/plugins/mpegplayer/stream_thread.h deleted file mode 100644 index dfa6e8c9a1..0000000000 --- a/apps/plugins/mpegplayer/stream_thread.h +++ /dev/null | |||
@@ -1,201 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Declarations for stream-specific threading | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #ifndef STREAM_THREAD_H | ||
24 | #define STREAM_THREAD_H | ||
25 | |||
26 | #define PKT_HAS_TS 0x1 | ||
27 | |||
28 | /* Stream header which is the minimum to receive asynchronous buffering | ||
29 | * notifications. | ||
30 | * Layed-out to allow streaming access after random-access parsing */ | ||
31 | struct stream_hdr | ||
32 | { | ||
33 | struct event_queue *q; /* Communication queue - separate to allow it | ||
34 | to be placed in another section */ | ||
35 | off_t win_left; /* Left position within data stream */ | ||
36 | union | ||
37 | { | ||
38 | off_t win_right; /* Right position within data stream */ | ||
39 | off_t pos; /* Start/current position for random-access read */ | ||
40 | }; | ||
41 | off_t limit; /* Limit for random-access read */ | ||
42 | }; | ||
43 | |||
44 | struct stream | ||
45 | { | ||
46 | struct stream_hdr hdr; /* Base stream data */ | ||
47 | unsigned int thread; /* Stream's thread */ | ||
48 | uint8_t* curr_packet; /* Current stream packet beginning */ | ||
49 | uint8_t* curr_packet_end; /* Current stream packet end */ | ||
50 | int state; /* State machine parsing mode */ | ||
51 | uint32_t start_pts; /* First timestamp for stream */ | ||
52 | uint32_t end_pts; /* Last timestamp for stream */ | ||
53 | uint32_t pts; /* Last presentation timestamp */ | ||
54 | uint32_t pkt_flags; /* PKT_* flags */ | ||
55 | unsigned id; /* Stream identifier */ | ||
56 | }; | ||
57 | |||
58 | #define STR_FROM_HDR(sh) ((struct stream *)(sh)) | ||
59 | |||
60 | /* Make sure there there is always enough data buffered ahead for | ||
61 | * the worst possible case - regardless of whether a valid stream | ||
62 | * would actually produce that */ | ||
63 | #define MIN_BUFAHEAD (21+65535+6+65535+6) /* 131103 */ | ||
64 | |||
65 | /* States that a stream's thread assumes internally */ | ||
66 | enum thread_states | ||
67 | { | ||
68 | /* Stream thread... */ | ||
69 | TSTATE_INIT = 0, /* is initialized and primed */ | ||
70 | TSTATE_DATA, /* is awaiting data to be available */ | ||
71 | TSTATE_BUFFERING, /* is buffering data */ | ||
72 | TSTATE_EOS, /* has hit the end of data */ | ||
73 | TSTATE_DECODE, /* is in a decoding state */ | ||
74 | TSTATE_RENDER, /* is in a rendering state */ | ||
75 | TSTATE_RENDER_WAIT, /* is waiting to render */ | ||
76 | }; | ||
77 | |||
78 | /* Commands that streams respond to */ | ||
79 | enum stream_message | ||
80 | { | ||
81 | STREAM_NULL = 0, /* A NULL message for whatever reason - | ||
82 | usually ignored */ | ||
83 | STREAM_PLAY, /* Start playback at current position */ | ||
84 | STREAM_PAUSE, /* Stop playing and await further commands */ | ||
85 | STREAM_RESET, /* Reset the stream for a discontinuity */ | ||
86 | STREAM_STOP, /* Stop stream - requires a reset later */ | ||
87 | STREAM_SEEK, /* Seek the current stream to a new location */ | ||
88 | STREAM_OPEN, /* Open a new file */ | ||
89 | STREAM_CLOSE, /* Close the current file */ | ||
90 | STREAM_QUIT, /* Exit the stream and thread */ | ||
91 | STREAM_NEEDS_SYNC, /* Need to sync before stream decoding? */ | ||
92 | STREAM_SYNC, /* Sync to the specified time from some key point */ | ||
93 | STREAM_FIND_END_TIME, /* Get the exact end time of an elementary | ||
94 | * stream - ie. time just after last frame is finished */ | ||
95 | /* Disk buffer */ | ||
96 | STREAM_DISK_BUF_FIRST, | ||
97 | DISK_BUF_DATA_NOTIFY = STREAM_DISK_BUF_FIRST, | ||
98 | DISK_BUF_CLEAR_DATA_NOTIFY, /* Cancel pending data notification */ | ||
99 | DISK_BUF_CACHE_RANGE, /* Cache a range of the file in the buffer */ | ||
100 | /* Audio stream */ | ||
101 | STREAM_AUDIO_FIRST, | ||
102 | /* Video stream */ | ||
103 | STREAM_VIDEO_FIRST, | ||
104 | VIDEO_DISPLAY_SHOW = STREAM_VIDEO_FIRST, /* Show/hide video output */ | ||
105 | VIDEO_DISPLAY_IS_VISIBLE, /* Is the video output visible? */ | ||
106 | VIDEO_GET_SIZE, /* Get the video dimensions */ | ||
107 | VIDEO_PRINT_FRAME, /* Print the frame at the current position */ | ||
108 | VIDEO_PRINT_THUMBNAIL, /* Print a thumbnail of the current position */ | ||
109 | VIDEO_SET_CLIP_RECT, /* Set the visible video area */ | ||
110 | VIDEO_GET_CLIP_RECT, /* Return the visible video area */ | ||
111 | VIDEO_SET_POST_FRAME_CALLBACK, /* Set a callback after frame is drawn */ | ||
112 | STREAM_MESSAGE_LAST, | ||
113 | }; | ||
114 | |||
115 | /* Data parameter for STREAM_SEEK */ | ||
116 | struct stream_seek_data | ||
117 | { | ||
118 | uint32_t time; /* Time to seek to/by */ | ||
119 | int whence; /* Specification of relationship to current position/file */ | ||
120 | }; | ||
121 | |||
122 | /* Data parameter for STREAM_SYNC */ | ||
123 | struct str_sync_data | ||
124 | { | ||
125 | uint32_t time; /* Time to sync to */ | ||
126 | struct stream_scan sk; /* Specification of start/limits/direction */ | ||
127 | }; | ||
128 | |||
129 | /* Stream status codes - not eqivalent to thread states */ | ||
130 | enum stream_status | ||
131 | { | ||
132 | /* Stream status is... */ | ||
133 | STREAM_DATA_END = -4, /* Stream has ended */ | ||
134 | STREAM_DATA_NOT_READY = -3, /* Data was not available yet */ | ||
135 | STREAM_UNSUPPORTED = -2, /* Format is unsupported */ | ||
136 | STREAM_ERROR = -1, /* some kind of error - quit it or reset it */ | ||
137 | STREAM_OK = 0, /* General inequality for success >= is OK, < error */ | ||
138 | STREAM_STOPPED = 0, /* stopped and awaiting commands - send STREAM_INIT */ | ||
139 | STREAM_PLAYING, /* playing and rendering its data */ | ||
140 | STREAM_PAUSED, /* paused and awaiting commands */ | ||
141 | /* Other status codes (> STREAM_OK) */ | ||
142 | STREAM_MATCH, /* A good match was found */ | ||
143 | STREAM_PERFECT_MATCH, /* Exactly what was wanted was found or | ||
144 | no better match is possible */ | ||
145 | STREAM_NOT_FOUND, /* Match not found */ | ||
146 | }; | ||
147 | |||
148 | /* Clip time to range for a particular stream */ | ||
149 | static inline uint32_t clip_time(struct stream *str, uint32_t time) | ||
150 | { | ||
151 | if (time < str->start_pts) | ||
152 | time = str->start_pts; | ||
153 | else if (time >= str->end_pts) | ||
154 | time = str->end_pts; | ||
155 | |||
156 | return time; | ||
157 | } | ||
158 | |||
159 | extern struct stream video_str IBSS_ATTR; | ||
160 | extern struct stream audio_str IBSS_ATTR; | ||
161 | |||
162 | bool video_thread_init(void); | ||
163 | void video_thread_exit(void); | ||
164 | |||
165 | struct video_output_stats | ||
166 | { | ||
167 | int num_drawn; /* Number of frames drawn since reset */ | ||
168 | int num_skipped; /* Number of frames skipped since reset */ | ||
169 | int fps; /* fps rate in 100ths of a frame per second */ | ||
170 | }; | ||
171 | |||
172 | void video_thread_get_stats(struct video_output_stats *s); | ||
173 | |||
174 | bool audio_thread_init(void); | ||
175 | void audio_thread_exit(void); | ||
176 | |||
177 | |||
178 | /* Some queue function wrappers to keep things clean-ish */ | ||
179 | |||
180 | /* For stream use only */ | ||
181 | static inline bool str_have_msg(struct stream *str) | ||
182 | { return !rb->queue_empty(str->hdr.q); } | ||
183 | |||
184 | static inline void str_get_msg(struct stream *str, struct queue_event *ev) | ||
185 | { rb->queue_wait(str->hdr.q, ev); } | ||
186 | |||
187 | static inline void str_get_msg_w_tmo(struct stream *str, struct queue_event *ev, | ||
188 | int timeout) | ||
189 | { rb->queue_wait_w_tmo(str->hdr.q, ev, timeout); } | ||
190 | |||
191 | static inline void str_reply_msg(struct stream *str, intptr_t reply) | ||
192 | { rb->queue_reply(str->hdr.q, reply); } | ||
193 | |||
194 | /* Public use */ | ||
195 | static inline intptr_t str_send_msg(struct stream *str, long id, intptr_t data) | ||
196 | { return rb->queue_send(str->hdr.q, id, data); } | ||
197 | |||
198 | static inline void str_post_msg(struct stream *str, long id, intptr_t data) | ||
199 | { rb->queue_post(str->hdr.q, id, data); } | ||
200 | |||
201 | #endif /* STREAM_THREAD_H */ | ||
diff --git a/apps/plugins/mpegplayer/video_out.h b/apps/plugins/mpegplayer/video_out.h deleted file mode 100644 index 2a3364c382..0000000000 --- a/apps/plugins/mpegplayer/video_out.h +++ /dev/null | |||
@@ -1,102 +0,0 @@ | |||
1 | /* | ||
2 | * video_out.h | ||
3 | * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> | ||
4 | * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> | ||
5 | * | ||
6 | * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | ||
7 | * See http://libmpeg2.sourceforge.net/ for updates. | ||
8 | * | ||
9 | * mpeg2dec is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * mpeg2dec is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | * $Id$ | ||
24 | * libmpeg2 sync history: | ||
25 | * 2008-07-01 - CVS revision 1.22 | ||
26 | */ | ||
27 | |||
28 | #ifndef VIDEO_OUT_H | ||
29 | #define VIDEO_OUT_H | ||
30 | |||
31 | #if LCD_WIDTH >= LCD_HEIGHT | ||
32 | #define SCREEN_WIDTH LCD_WIDTH | ||
33 | #define SCREEN_HEIGHT LCD_HEIGHT | ||
34 | #define LCD_LANDSCAPE | ||
35 | #else /* Assume the screen is rotated on portrait LCDs */ | ||
36 | #define SCREEN_WIDTH LCD_HEIGHT | ||
37 | #define SCREEN_HEIGHT LCD_WIDTH | ||
38 | #define LCD_PORTRAIT | ||
39 | #endif | ||
40 | |||
41 | /* Structure to hold width and height values */ | ||
42 | struct vo_ext | ||
43 | { | ||
44 | int w, h; | ||
45 | }; | ||
46 | |||
47 | /* Structure that defines a rectangle by its edges */ | ||
48 | struct vo_rect | ||
49 | { | ||
50 | int l, t, r, b; | ||
51 | }; | ||
52 | |||
53 | void vo_draw_frame (uint8_t * const * buf); | ||
54 | bool vo_draw_frame_thumb (uint8_t * const * buf, | ||
55 | const struct vo_rect *rc); | ||
56 | bool vo_init (void); | ||
57 | bool vo_show (bool show); | ||
58 | bool vo_is_visible(void); | ||
59 | void vo_setup (const mpeg2_sequence_t * sequence); | ||
60 | void vo_set_clip_rect(const struct vo_rect *rc); | ||
61 | bool vo_get_clip_rect(struct vo_rect *rc); | ||
62 | void vo_dimensions(struct vo_ext *sz); | ||
63 | void vo_cleanup (void); | ||
64 | void vo_set_post_draw_callback(void (*cb)(void)); | ||
65 | |||
66 | #if NUM_CORES > 1 | ||
67 | void vo_lock(void); | ||
68 | void vo_unlock(void); | ||
69 | #else | ||
70 | static inline void vo_lock(void) {} | ||
71 | static inline void vo_unlock(void) {} | ||
72 | #endif | ||
73 | |||
74 | /* Sets all coordinates of a vo_rect to 0 */ | ||
75 | void vo_rect_clear(struct vo_rect *rc); | ||
76 | /* Returns true if left >= right or top >= bottom */ | ||
77 | bool vo_rect_empty(const struct vo_rect *rc); | ||
78 | /* Initializes a vo_rect using upper-left corner and extents */ | ||
79 | void vo_rect_set_ext(struct vo_rect *rc, int x, int y, | ||
80 | int width, int height); | ||
81 | /* Query if two rectangles intersect | ||
82 | * If either are empty returns false */ | ||
83 | bool vo_rects_intersect(const struct vo_rect *rc1, | ||
84 | const struct vo_rect *rc2); | ||
85 | |||
86 | /* Intersect two rectangles | ||
87 | * Resulting rectangle is placed in rc_dst. | ||
88 | * rc_dst is set to empty if they don't intersect. | ||
89 | * Empty source rectangles do not intersect any rectangle. | ||
90 | * rc_dst may be the same structure as rc1 or rc2. | ||
91 | * Returns true if the resulting rectangle is not empty. */ | ||
92 | bool vo_rect_intersect(struct vo_rect *rc_dst, | ||
93 | const struct vo_rect *rc1, | ||
94 | const struct vo_rect *rc2); | ||
95 | |||
96 | bool vo_rect_union(struct vo_rect *rc_dst, | ||
97 | const struct vo_rect *rc1, | ||
98 | const struct vo_rect *rc2); | ||
99 | |||
100 | void vo_rect_offset(struct vo_rect *rc, int dx, int dy); | ||
101 | |||
102 | #endif /* VIDEO_OUT_H */ | ||
diff --git a/apps/plugins/mpegplayer/video_out_rockbox.c b/apps/plugins/mpegplayer/video_out_rockbox.c deleted file mode 100644 index 331383843b..0000000000 --- a/apps/plugins/mpegplayer/video_out_rockbox.c +++ /dev/null | |||
@@ -1,576 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * mpegplayer video output routines | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "libmpeg2/mpeg2dec_config.h" | ||
22 | |||
23 | #include "plugin.h" | ||
24 | #include "mpegplayer.h" | ||
25 | |||
26 | #define VO_NON_NULL_RECT 0x1 | ||
27 | #define VO_VISIBLE 0x2 | ||
28 | |||
29 | struct vo_data | ||
30 | { | ||
31 | int image_width; | ||
32 | int image_height; | ||
33 | int image_chroma_x; | ||
34 | int image_chroma_y; | ||
35 | int display_width; | ||
36 | int display_height; | ||
37 | int output_x; | ||
38 | int output_y; | ||
39 | int output_width; | ||
40 | int output_height; | ||
41 | unsigned flags; | ||
42 | struct vo_rect rc_vid; | ||
43 | struct vo_rect rc_clip; | ||
44 | void (*post_draw_callback)(void); | ||
45 | }; | ||
46 | |||
47 | #if NUM_CORES > 1 | ||
48 | /* Cache aligned and padded to avoid clobbering other processors' cacheable | ||
49 | * data */ | ||
50 | static union { | ||
51 | uint8_t __vo_data[CACHEALIGN_UP(sizeof(struct vo_data))]; | ||
52 | struct vo_data vo; | ||
53 | } vo_raw CACHEALIGN_ATTR; | ||
54 | #define vo vo_raw.vo | ||
55 | #else | ||
56 | static struct vo_data vo; | ||
57 | #endif | ||
58 | |||
59 | #if NUM_CORES > 1 | ||
60 | static struct mutex vo_mtx SHAREDBSS_ATTR; | ||
61 | #endif | ||
62 | |||
63 | static inline void video_lock_init(void) | ||
64 | { | ||
65 | #if NUM_CORES > 1 | ||
66 | rb->mutex_init(&vo_mtx); | ||
67 | #endif | ||
68 | } | ||
69 | |||
70 | static inline void video_lock(void) | ||
71 | { | ||
72 | #if NUM_CORES > 1 | ||
73 | rb->mutex_lock(&vo_mtx); | ||
74 | #endif | ||
75 | } | ||
76 | |||
77 | static inline void video_unlock(void) | ||
78 | { | ||
79 | #if NUM_CORES > 1 | ||
80 | rb->mutex_unlock(&vo_mtx); | ||
81 | #endif | ||
82 | } | ||
83 | |||
84 | |||
85 | /* Draw a black rectangle if no video frame is available */ | ||
86 | static void vo_draw_black(struct vo_rect *rc) | ||
87 | { | ||
88 | int foreground; | ||
89 | int x, y, w, h; | ||
90 | |||
91 | video_lock(); | ||
92 | |||
93 | foreground = mylcd_get_foreground(); | ||
94 | |||
95 | mylcd_set_foreground(MYLCD_BLACK); | ||
96 | |||
97 | if (rc) | ||
98 | { | ||
99 | x = rc->l; | ||
100 | y = rc->t; | ||
101 | w = rc->r - rc->l; | ||
102 | h = rc->b - rc->t; | ||
103 | } | ||
104 | else | ||
105 | { | ||
106 | #if LCD_WIDTH >= LCD_HEIGHT | ||
107 | x = vo.output_x; | ||
108 | y = vo.output_y; | ||
109 | w = vo.output_width; | ||
110 | h = vo.output_height; | ||
111 | #else | ||
112 | x = LCD_WIDTH - vo.output_height - vo.output_y; | ||
113 | y = vo.output_x; | ||
114 | w = vo.output_height; | ||
115 | h = vo.output_width; | ||
116 | #endif | ||
117 | } | ||
118 | |||
119 | mylcd_fillrect(x, y, w, h); | ||
120 | mylcd_update_rect(x, y, w, h); | ||
121 | |||
122 | mylcd_set_foreground(foreground); | ||
123 | |||
124 | video_unlock(); | ||
125 | } | ||
126 | |||
127 | static inline void yuv_blit(uint8_t * const * buf, int src_x, int src_y, | ||
128 | int stride, int x, int y, int width, int height) | ||
129 | { | ||
130 | video_lock(); | ||
131 | |||
132 | #ifdef HAVE_LCD_COLOR | ||
133 | rb->lcd_blit_yuv(buf, src_x, src_y, stride, x, y , width, height); | ||
134 | #else | ||
135 | grey_ub_gray_bitmap_part(buf[0], src_x, src_y, stride, x, y, width, height); | ||
136 | #endif | ||
137 | |||
138 | video_unlock(); | ||
139 | } | ||
140 | |||
141 | void vo_draw_frame(uint8_t * const * buf) | ||
142 | { | ||
143 | if ((vo.flags & (VO_NON_NULL_RECT | VO_VISIBLE)) != | ||
144 | (VO_NON_NULL_RECT | VO_VISIBLE)) | ||
145 | { | ||
146 | /* Frame is hidden - either by being set invisible or is clipped | ||
147 | * away - copout */ | ||
148 | DEBUGF("vo hidden\n"); | ||
149 | } | ||
150 | else if (buf == NULL) | ||
151 | { | ||
152 | /* No frame exists - draw black */ | ||
153 | vo_draw_black(NULL); | ||
154 | DEBUGF("vo no frame\n"); | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | yuv_blit(buf, 0, 0, vo.image_width, | ||
159 | vo.output_x, vo.output_y, vo.output_width, | ||
160 | vo.output_height); | ||
161 | } | ||
162 | |||
163 | if (vo.post_draw_callback) | ||
164 | vo.post_draw_callback(); | ||
165 | } | ||
166 | |||
167 | static inline void vo_rect_clear_inl(struct vo_rect *rc) | ||
168 | { | ||
169 | rc->l = rc->t = rc->r = rc->b = 0; | ||
170 | } | ||
171 | |||
172 | static inline bool vo_rect_empty_inl(const struct vo_rect *rc) | ||
173 | { | ||
174 | return rc == NULL || rc->l >= rc->r || rc->t >= rc->b; | ||
175 | } | ||
176 | |||
177 | static inline bool vo_rects_intersect_inl(const struct vo_rect *rc1, | ||
178 | const struct vo_rect *rc2) | ||
179 | { | ||
180 | return !vo_rect_empty_inl(rc1) && | ||
181 | !vo_rect_empty_inl(rc2) && | ||
182 | rc1->l < rc2->r && rc1->r > rc2->l && | ||
183 | rc1->t < rc2->b && rc1->b > rc2->t; | ||
184 | } | ||
185 | |||
186 | /* Sets all coordinates of a vo_rect to 0 */ | ||
187 | void vo_rect_clear(struct vo_rect *rc) | ||
188 | { | ||
189 | vo_rect_clear_inl(rc); | ||
190 | } | ||
191 | |||
192 | /* Returns true if left >= right or top >= bottom */ | ||
193 | bool vo_rect_empty(const struct vo_rect *rc) | ||
194 | { | ||
195 | return vo_rect_empty_inl(rc); | ||
196 | } | ||
197 | |||
198 | /* Initializes a vo_rect using upper-left corner and extents */ | ||
199 | void vo_rect_set_ext(struct vo_rect *rc, int x, int y, | ||
200 | int width, int height) | ||
201 | { | ||
202 | rc->l = x; | ||
203 | rc->t = y; | ||
204 | rc->r = x + width; | ||
205 | rc->b = y + height; | ||
206 | } | ||
207 | |||
208 | /* Query if two rectangles intersect */ | ||
209 | bool vo_rects_intersect(const struct vo_rect *rc1, | ||
210 | const struct vo_rect *rc2) | ||
211 | { | ||
212 | return vo_rects_intersect_inl(rc1, rc2); | ||
213 | } | ||
214 | |||
215 | /* Intersect two rectangles, placing the result in rc_dst */ | ||
216 | bool vo_rect_intersect(struct vo_rect *rc_dst, | ||
217 | const struct vo_rect *rc1, | ||
218 | const struct vo_rect *rc2) | ||
219 | { | ||
220 | if (rc_dst != NULL) | ||
221 | { | ||
222 | if (vo_rects_intersect_inl(rc1, rc2)) | ||
223 | { | ||
224 | rc_dst->l = MAX(rc1->l, rc2->l); | ||
225 | rc_dst->r = MIN(rc1->r, rc2->r); | ||
226 | rc_dst->t = MAX(rc1->t, rc2->t); | ||
227 | rc_dst->b = MIN(rc1->b, rc2->b); | ||
228 | return true; | ||
229 | } | ||
230 | |||
231 | vo_rect_clear_inl(rc_dst); | ||
232 | } | ||
233 | |||
234 | return false; | ||
235 | } | ||
236 | |||
237 | bool vo_rect_union(struct vo_rect *rc_dst, | ||
238 | const struct vo_rect *rc1, | ||
239 | const struct vo_rect *rc2) | ||
240 | { | ||
241 | if (rc_dst != NULL) | ||
242 | { | ||
243 | if (!vo_rect_empty_inl(rc1)) | ||
244 | { | ||
245 | if (!vo_rect_empty_inl(rc2)) | ||
246 | { | ||
247 | rc_dst->l = MIN(rc1->l, rc2->l); | ||
248 | rc_dst->t = MIN(rc1->t, rc2->t); | ||
249 | rc_dst->r = MAX(rc1->r, rc2->r); | ||
250 | rc_dst->b = MAX(rc1->b, rc2->b); | ||
251 | } | ||
252 | else | ||
253 | { | ||
254 | *rc_dst = *rc1; | ||
255 | } | ||
256 | |||
257 | return true; | ||
258 | } | ||
259 | else if (!vo_rect_empty_inl(rc2)) | ||
260 | { | ||
261 | *rc_dst = *rc2; | ||
262 | return true; | ||
263 | } | ||
264 | |||
265 | vo_rect_clear_inl(rc_dst); | ||
266 | } | ||
267 | |||
268 | return false; | ||
269 | } | ||
270 | |||
271 | void vo_rect_offset(struct vo_rect *rc, int dx, int dy) | ||
272 | { | ||
273 | rc->l += dx; | ||
274 | rc->t += dy; | ||
275 | rc->r += dx; | ||
276 | rc->b += dy; | ||
277 | } | ||
278 | |||
279 | /* Shink or stretch each axis - rotate counter-clockwise to retain upright | ||
280 | * orientation on rotated displays (they rotate clockwise) */ | ||
281 | void stretch_image_plane(const uint8_t * src, uint8_t *dst, int stride, | ||
282 | int src_w, int src_h, int dst_w, int dst_h) | ||
283 | { | ||
284 | uint8_t *dst_end = dst + dst_w*dst_h; | ||
285 | |||
286 | #if LCD_WIDTH >= LCD_HEIGHT | ||
287 | int src_w2 = src_w*2; /* 2x dimensions (for rounding before division) */ | ||
288 | int dst_w2 = dst_w*2; | ||
289 | int src_h2 = src_h*2; | ||
290 | int dst_h2 = dst_h*2; | ||
291 | int qw = src_w2 / dst_w2; /* src-dst width ratio quotient */ | ||
292 | int rw = src_w2 - qw*dst_w2; /* src-dst width ratio remainder */ | ||
293 | int qh = src_h2 / dst_h2; /* src-dst height ratio quotient */ | ||
294 | int rh = src_h2 - qh*dst_h2; /* src-dst height ratio remainder */ | ||
295 | int dw = dst_w; /* Width error accumulator */ | ||
296 | int dh = dst_h; /* Height error accumulator */ | ||
297 | #else | ||
298 | int src_w2 = src_w*2; | ||
299 | int dst_w2 = dst_h*2; | ||
300 | int src_h2 = src_h*2; | ||
301 | int dst_h2 = dst_w*2; | ||
302 | int qw = src_h2 / dst_w2; | ||
303 | int rw = src_h2 - qw*dst_w2; | ||
304 | int qh = src_w2 / dst_h2; | ||
305 | int rh = src_w2 - qh*dst_h2; | ||
306 | int dw = dst_h; | ||
307 | int dh = dst_w; | ||
308 | |||
309 | src += src_w - 1; | ||
310 | #endif | ||
311 | |||
312 | while (1) | ||
313 | { | ||
314 | const uint8_t *s = src; | ||
315 | #if LCD_WIDTH >= LCD_HEIGHT | ||
316 | uint8_t * const dst_line_end = dst + dst_w; | ||
317 | #else | ||
318 | uint8_t * const dst_line_end = dst + dst_h; | ||
319 | #endif | ||
320 | while (1) | ||
321 | { | ||
322 | *dst++ = *s; | ||
323 | |||
324 | if (dst >= dst_line_end) | ||
325 | { | ||
326 | dw = dst_w; | ||
327 | break; | ||
328 | } | ||
329 | |||
330 | #if LCD_WIDTH >= LCD_HEIGHT | ||
331 | s += qw; | ||
332 | #else | ||
333 | s += qw*stride; | ||
334 | #endif | ||
335 | dw += rw; | ||
336 | |||
337 | if (dw >= dst_w2) | ||
338 | { | ||
339 | dw -= dst_w2; | ||
340 | #if LCD_WIDTH >= LCD_HEIGHT | ||
341 | s++; | ||
342 | #else | ||
343 | s += stride; | ||
344 | #endif | ||
345 | } | ||
346 | } | ||
347 | |||
348 | if (dst >= dst_end) | ||
349 | break; | ||
350 | #if LCD_WIDTH >= LCD_HEIGHT | ||
351 | src += qh*stride; | ||
352 | #else | ||
353 | src -= qh; | ||
354 | #endif | ||
355 | dh += rh; | ||
356 | |||
357 | if (dh >= dst_h2) | ||
358 | { | ||
359 | dh -= dst_h2; | ||
360 | #if LCD_WIDTH >= LCD_HEIGHT | ||
361 | src += stride; | ||
362 | #else | ||
363 | src--; | ||
364 | #endif | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 | |||
369 | bool vo_draw_frame_thumb(uint8_t * const * buf, const struct vo_rect *rc) | ||
370 | { | ||
371 | void *mem; | ||
372 | size_t bufsize = 0; | ||
373 | uint8_t *yuv[3]; | ||
374 | struct vo_rect thumb_rc; | ||
375 | int thumb_width, thumb_height; | ||
376 | #ifdef HAVE_LCD_COLOR | ||
377 | int thumb_uv_width, thumb_uv_height; | ||
378 | #endif | ||
379 | |||
380 | /* Obtain rectangle as clipped to the screen */ | ||
381 | vo_rect_set_ext(&thumb_rc, 0, 0, LCD_WIDTH, LCD_HEIGHT); | ||
382 | if (!vo_rect_intersect(&thumb_rc, rc, &thumb_rc)) | ||
383 | return true; | ||
384 | |||
385 | if (buf == NULL) | ||
386 | goto no_thumb_exit; | ||
387 | |||
388 | DEBUGF("thumb_rc: %d, %d, %d, %d\n", thumb_rc.l, thumb_rc.t, | ||
389 | thumb_rc.r, thumb_rc.b); | ||
390 | |||
391 | thumb_width = rc->r - rc->l; | ||
392 | thumb_height = rc->b - rc->t; | ||
393 | #ifdef HAVE_LCD_COLOR | ||
394 | thumb_uv_width = thumb_width / 2; | ||
395 | thumb_uv_height = thumb_height / 2; | ||
396 | |||
397 | DEBUGF("thumb: w: %d h: %d uvw: %d uvh: %d\n", thumb_width, | ||
398 | thumb_height, thumb_uv_width, thumb_uv_height); | ||
399 | #else | ||
400 | DEBUGF("thumb: w: %d h: %d\n", thumb_width, thumb_height); | ||
401 | #endif | ||
402 | |||
403 | /* Use remaining mpeg2 buffer as temp space */ | ||
404 | mem = mpeg2_get_buf(&bufsize); | ||
405 | |||
406 | if (bufsize < (size_t)(thumb_width*thumb_height) | ||
407 | #ifdef HAVE_LCD_COLOR | ||
408 | + 2u*(thumb_uv_width * thumb_uv_height) | ||
409 | #endif | ||
410 | ) | ||
411 | { | ||
412 | DEBUGF("thumb: insufficient buffer\n"); | ||
413 | goto no_thumb_exit; | ||
414 | } | ||
415 | |||
416 | yuv[0] = mem; | ||
417 | stretch_image_plane(buf[0], yuv[0], vo.image_width, | ||
418 | vo.display_width, vo.display_height, | ||
419 | thumb_width, thumb_height); | ||
420 | |||
421 | #ifdef HAVE_LCD_COLOR | ||
422 | yuv[1] = yuv[0] + thumb_width*thumb_height; | ||
423 | yuv[2] = yuv[1] + thumb_uv_width*thumb_uv_height; | ||
424 | |||
425 | stretch_image_plane(buf[1], yuv[1], vo.image_width / 2, | ||
426 | vo.display_width / 2, vo.display_height / 2, | ||
427 | thumb_uv_width, thumb_uv_height); | ||
428 | |||
429 | stretch_image_plane(buf[2], yuv[2], vo.image_width / 2, | ||
430 | vo.display_width / 2, vo.display_height / 2, | ||
431 | thumb_uv_width, thumb_uv_height); | ||
432 | #endif | ||
433 | |||
434 | #if LCD_WIDTH >= LCD_HEIGHT | ||
435 | yuv_blit(yuv, 0, 0, thumb_width, | ||
436 | thumb_rc.l, thumb_rc.t, | ||
437 | thumb_rc.r - thumb_rc.l, | ||
438 | thumb_rc.b - thumb_rc.t); | ||
439 | #else | ||
440 | yuv_blit(yuv, 0, 0, thumb_height, | ||
441 | thumb_rc.t, thumb_rc.l, | ||
442 | thumb_rc.b - thumb_rc.t, | ||
443 | thumb_rc.r - thumb_rc.l); | ||
444 | #endif /* LCD_WIDTH >= LCD_HEIGHT */ | ||
445 | |||
446 | return true; | ||
447 | |||
448 | no_thumb_exit: | ||
449 | vo_draw_black(&thumb_rc); | ||
450 | return false; | ||
451 | } | ||
452 | |||
453 | void vo_setup(const mpeg2_sequence_t * sequence) | ||
454 | { | ||
455 | vo.image_width = sequence->width; | ||
456 | vo.image_height = sequence->height; | ||
457 | vo.display_width = sequence->display_width; | ||
458 | vo.display_height = sequence->display_height; | ||
459 | |||
460 | DEBUGF("vo_setup - w:%d h:%d\n", vo.display_width, vo.display_height); | ||
461 | |||
462 | vo.image_chroma_x = vo.image_width / sequence->chroma_width; | ||
463 | vo.image_chroma_y = vo.image_height / sequence->chroma_height; | ||
464 | |||
465 | if (sequence->display_width >= SCREEN_WIDTH) | ||
466 | { | ||
467 | vo.rc_vid.l = 0; | ||
468 | vo.rc_vid.r = SCREEN_WIDTH; | ||
469 | } | ||
470 | else | ||
471 | { | ||
472 | vo.rc_vid.l = (SCREEN_WIDTH - sequence->display_width) / 2; | ||
473 | #ifdef HAVE_LCD_COLOR | ||
474 | vo.rc_vid.l &= ~1; | ||
475 | #endif | ||
476 | vo.rc_vid.r = vo.rc_vid.l + sequence->display_width; | ||
477 | } | ||
478 | |||
479 | if (sequence->display_height >= SCREEN_HEIGHT) | ||
480 | { | ||
481 | vo.rc_vid.t = 0; | ||
482 | vo.rc_vid.b = SCREEN_HEIGHT; | ||
483 | } | ||
484 | else | ||
485 | { | ||
486 | vo.rc_vid.t = (SCREEN_HEIGHT - sequence->display_height) / 2; | ||
487 | #ifdef HAVE_LCD_COLOR | ||
488 | vo.rc_vid.t &= ~1; | ||
489 | #endif | ||
490 | vo.rc_vid.b = vo.rc_vid.t + sequence->display_height; | ||
491 | } | ||
492 | |||
493 | vo_set_clip_rect(&vo.rc_clip); | ||
494 | } | ||
495 | |||
496 | void vo_dimensions(struct vo_ext *sz) | ||
497 | { | ||
498 | sz->w = vo.display_width; | ||
499 | sz->h = vo.display_height; | ||
500 | } | ||
501 | |||
502 | bool vo_init(void) | ||
503 | { | ||
504 | vo.flags = 0; | ||
505 | vo_rect_set_ext(&vo.rc_clip, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); | ||
506 | video_lock_init(); | ||
507 | return true; | ||
508 | } | ||
509 | |||
510 | bool vo_show(bool show) | ||
511 | { | ||
512 | bool vis = vo.flags & VO_VISIBLE; | ||
513 | |||
514 | if (show) | ||
515 | vo.flags |= VO_VISIBLE; | ||
516 | else | ||
517 | vo.flags &= ~VO_VISIBLE; | ||
518 | |||
519 | return vis; | ||
520 | } | ||
521 | |||
522 | bool vo_is_visible(void) | ||
523 | { | ||
524 | return vo.flags & VO_VISIBLE; | ||
525 | } | ||
526 | |||
527 | void vo_cleanup(void) | ||
528 | { | ||
529 | vo.flags = 0; | ||
530 | } | ||
531 | |||
532 | void vo_set_clip_rect(const struct vo_rect *rc) | ||
533 | { | ||
534 | struct vo_rect rc_out; | ||
535 | |||
536 | if (rc == NULL) | ||
537 | vo_rect_set_ext(&vo.rc_clip, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); | ||
538 | else | ||
539 | vo.rc_clip = *rc; | ||
540 | |||
541 | if (!vo_rect_intersect(&rc_out, &vo.rc_vid, &vo.rc_clip)) | ||
542 | vo.flags &= ~VO_NON_NULL_RECT; | ||
543 | else | ||
544 | vo.flags |= VO_NON_NULL_RECT; | ||
545 | |||
546 | vo.output_x = rc_out.l; | ||
547 | vo.output_y = rc_out.t; | ||
548 | vo.output_width = rc_out.r - rc_out.l; | ||
549 | vo.output_height = rc_out.b - rc_out.t; | ||
550 | } | ||
551 | |||
552 | bool vo_get_clip_rect(struct vo_rect *rc) | ||
553 | { | ||
554 | rc->l = vo.output_x; | ||
555 | rc->t = vo.output_y; | ||
556 | rc->r = rc->l + vo.output_width; | ||
557 | rc->b = rc->t + vo.output_height; | ||
558 | return (vo.flags & VO_NON_NULL_RECT) != 0; | ||
559 | } | ||
560 | |||
561 | void vo_set_post_draw_callback(void (*cb)(void)) | ||
562 | { | ||
563 | vo.post_draw_callback = cb; | ||
564 | } | ||
565 | |||
566 | #if NUM_CORES > 1 | ||
567 | void vo_lock(void) | ||
568 | { | ||
569 | video_lock(); | ||
570 | } | ||
571 | |||
572 | void vo_unlock(void) | ||
573 | { | ||
574 | video_unlock(); | ||
575 | } | ||
576 | #endif | ||
diff --git a/apps/plugins/mpegplayer/video_thread.c b/apps/plugins/mpegplayer/video_thread.c deleted file mode 100644 index 392cc6179f..0000000000 --- a/apps/plugins/mpegplayer/video_thread.c +++ /dev/null | |||
@@ -1,1059 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * mpegplayer video thread implementation | ||
11 | * | ||
12 | * Copyright (c) 2007 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #include "plugin.h" | ||
24 | #include "mpegplayer.h" | ||
25 | #include "libmpeg2/mpeg2dec_config.h" | ||
26 | #include "lib/grey.h" | ||
27 | #include "video_out.h" | ||
28 | #include "mpeg_settings.h" | ||
29 | |||
30 | /** Video stream and thread **/ | ||
31 | |||
32 | /* Video thread data passed around to its various functions */ | ||
33 | struct video_thread_data | ||
34 | { | ||
35 | /* Stream data */ | ||
36 | mpeg2dec_t *mpeg2dec; /* Our video decoder */ | ||
37 | const mpeg2_info_t *info; /* Info about video stream */ | ||
38 | int state; /* Thread state */ | ||
39 | int status; /* Media status */ | ||
40 | struct queue_event ev;/* Our event queue to receive commands */ | ||
41 | /* Operational info */ | ||
42 | uint32_t stream_time; /* Current time from beginning of stream */ | ||
43 | uint32_t goal_time; /* Scheduled time of current frame */ | ||
44 | int32_t remain_time; /* T-minus value to frame_time (-:early, +:late) */ | ||
45 | int skip_ref_pics; /* Severe skipping - wait for I-frame */ | ||
46 | int skip_level; /* Number of frames still to skip */ | ||
47 | int num_picture; /* Number of picture headers read */ | ||
48 | int num_intra; /* Number of I-picture headers read */ | ||
49 | int group_est; /* Estmated number remaining as of last I */ | ||
50 | long last_render; /* Last time a frame was drawn */ | ||
51 | /* Sync info */ | ||
52 | uint32_t frame_time; /* Current due time of frame (unadjusted) */ | ||
53 | uint32_t frame_period; /* Frame period in clock ticks */ | ||
54 | int num_ref_pics; /* Number of I and P frames since sync/skip */ | ||
55 | int syncf_perfect; /* Last sync fit result */ | ||
56 | }; | ||
57 | |||
58 | /* Number drawn since reset */ | ||
59 | static int video_num_drawn SHAREDBSS_ATTR; | ||
60 | /* Number skipped since reset */ | ||
61 | static int video_num_skipped SHAREDBSS_ATTR; | ||
62 | |||
63 | /* TODO: Check if 4KB is appropriate - it works for my test streams, | ||
64 | so maybe we can reduce it. */ | ||
65 | #define VIDEO_STACKSIZE (4*1024) | ||
66 | static uint32_t video_stack[VIDEO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR; | ||
67 | static struct event_queue video_str_queue SHAREDBSS_ATTR; | ||
68 | static struct queue_sender_list video_str_queue_send SHAREDBSS_ATTR; | ||
69 | struct stream video_str IBSS_ATTR; | ||
70 | |||
71 | #define DEFAULT_GOP_SIZE INT_MAX /* no I/P skips until it learns */ | ||
72 | #define DROP_THRESHOLD (100*TS_SECOND/1000) | ||
73 | #define MAX_EARLINESS (120*TS_SECOND/1000) | ||
74 | |||
75 | #if defined(DEBUG) || defined(SIMULATOR) | ||
76 | static unsigned char pic_coding_type_char(unsigned type) | ||
77 | { | ||
78 | switch (type) | ||
79 | { | ||
80 | case PIC_FLAG_CODING_TYPE_I: | ||
81 | return 'I'; /* Intra-coded */ | ||
82 | case PIC_FLAG_CODING_TYPE_P: | ||
83 | return 'P'; /* Forward-predicted */ | ||
84 | case PIC_FLAG_CODING_TYPE_B: | ||
85 | return 'B'; /* Bidirectionally-predicted */ | ||
86 | case PIC_FLAG_CODING_TYPE_D: | ||
87 | return 'D'; /* DC-coded */ | ||
88 | default: | ||
89 | return '?'; /* Say what? */ | ||
90 | } | ||
91 | } | ||
92 | #endif /* defined(DEBUG) || defined(SIMULATOR) */ | ||
93 | |||
94 | /* Multi-use: | ||
95 | * 1) Find the sequence header and initialize video out | ||
96 | * 2) Find the end of the final frame | ||
97 | */ | ||
98 | static int video_str_scan(struct video_thread_data *td, | ||
99 | struct str_sync_data *sd) | ||
100 | { | ||
101 | int retval = STREAM_ERROR; | ||
102 | uint32_t time = INVALID_TIMESTAMP; | ||
103 | uint32_t period = 0; | ||
104 | struct stream tmp_str; | ||
105 | |||
106 | tmp_str.id = video_str.id; | ||
107 | tmp_str.hdr.pos = sd->sk.pos; | ||
108 | tmp_str.hdr.limit = sd->sk.pos + sd->sk.len; | ||
109 | |||
110 | /* Fully reset if obtaining size for a new stream */ | ||
111 | mpeg2_reset(td->mpeg2dec, td->ev.id == VIDEO_GET_SIZE); | ||
112 | mpeg2_skip(td->mpeg2dec, 1); | ||
113 | |||
114 | while (1) | ||
115 | { | ||
116 | mpeg2_state_t mp2state = mpeg2_parse(td->mpeg2dec); | ||
117 | rb->yield(); | ||
118 | |||
119 | switch (mp2state) | ||
120 | { | ||
121 | case STATE_BUFFER: | ||
122 | switch (parser_get_next_data(&tmp_str, STREAM_PM_RANDOM_ACCESS)) | ||
123 | { | ||
124 | case STREAM_DATA_END: | ||
125 | DEBUGF("video_stream_scan:STREAM_DATA_END\n"); | ||
126 | goto scan_finished; | ||
127 | |||
128 | case STREAM_OK: | ||
129 | if (tmp_str.pkt_flags & PKT_HAS_TS) | ||
130 | mpeg2_tag_picture(td->mpeg2dec, tmp_str.pts, 0); | ||
131 | |||
132 | mpeg2_buffer(td->mpeg2dec, tmp_str.curr_packet, | ||
133 | tmp_str.curr_packet_end); | ||
134 | td->info = mpeg2_info(td->mpeg2dec); | ||
135 | break; | ||
136 | } | ||
137 | break; | ||
138 | |||
139 | case STATE_SEQUENCE: | ||
140 | DEBUGF("video_stream_scan:STATE_SEQUENCE\n"); | ||
141 | vo_setup(td->info->sequence); | ||
142 | |||
143 | if (td->ev.id == VIDEO_GET_SIZE) | ||
144 | { | ||
145 | retval = STREAM_OK; | ||
146 | goto scan_finished; | ||
147 | } | ||
148 | break; | ||
149 | |||
150 | case STATE_SLICE: | ||
151 | case STATE_END: | ||
152 | case STATE_INVALID_END: | ||
153 | { | ||
154 | if (td->info->display_picture == NULL) | ||
155 | break; | ||
156 | |||
157 | switch (td->ev.id) | ||
158 | { | ||
159 | case STREAM_SYNC: | ||
160 | retval = STREAM_OK; | ||
161 | goto scan_finished; | ||
162 | |||
163 | case STREAM_FIND_END_TIME: | ||
164 | if (td->info->display_picture->flags & PIC_FLAG_TAGS) | ||
165 | time = td->info->display_picture->tag; | ||
166 | else if (time != INVALID_TIMESTAMP) | ||
167 | time += period; | ||
168 | |||
169 | period = TC_TO_TS(td->info->sequence->frame_period); | ||
170 | break; | ||
171 | } | ||
172 | |||
173 | break; | ||
174 | } | ||
175 | |||
176 | default: | ||
177 | break; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | scan_finished: | ||
182 | |||
183 | if (td->ev.id == STREAM_FIND_END_TIME) | ||
184 | { | ||
185 | if (time != INVALID_TIMESTAMP) | ||
186 | { | ||
187 | sd->time = time + period; | ||
188 | retval = STREAM_PERFECT_MATCH; | ||
189 | } | ||
190 | else | ||
191 | { | ||
192 | retval = STREAM_NOT_FOUND; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | mpeg2_skip(td->mpeg2dec, 0); | ||
197 | return retval; | ||
198 | } | ||
199 | |||
200 | static bool init_sequence(struct video_thread_data *td) | ||
201 | { | ||
202 | struct str_sync_data sd; | ||
203 | |||
204 | sd.time = 0; /* Ignored */ | ||
205 | sd.sk.pos = 0; | ||
206 | sd.sk.len = 1024*1024; | ||
207 | sd.sk.dir = SSCAN_FORWARD; | ||
208 | |||
209 | return video_str_scan(td, &sd) == STREAM_OK; | ||
210 | } | ||
211 | |||
212 | static bool check_needs_sync(struct video_thread_data *td, uint32_t time) | ||
213 | { | ||
214 | uint32_t end_time; | ||
215 | |||
216 | DEBUGF("check_needs_sync:\n"); | ||
217 | if (td->info == NULL || td->info->display_fbuf == NULL) | ||
218 | { | ||
219 | DEBUGF(" no fbuf\n"); | ||
220 | return true; | ||
221 | } | ||
222 | |||
223 | if (td->syncf_perfect == 0) | ||
224 | { | ||
225 | DEBUGF(" no frame\n"); | ||
226 | return true; | ||
227 | } | ||
228 | |||
229 | time = clip_time(&video_str, time); | ||
230 | end_time = td->frame_time + td->frame_period; | ||
231 | |||
232 | DEBUGF(" sft:%u t:%u sfte:%u\n", (unsigned)td->frame_time, | ||
233 | (unsigned)time, (unsigned)end_time); | ||
234 | |||
235 | if (time < td->frame_time) | ||
236 | return true; | ||
237 | |||
238 | if (time >= end_time) | ||
239 | return time < video_str.end_pts || end_time < video_str.end_pts; | ||
240 | |||
241 | return false; | ||
242 | } | ||
243 | |||
244 | /* Do any needed decoding/slide up to the specified time */ | ||
245 | static int sync_decoder(struct video_thread_data *td, | ||
246 | struct str_sync_data *sd) | ||
247 | { | ||
248 | int retval = STREAM_ERROR; | ||
249 | uint32_t time = clip_time(&video_str, sd->time); | ||
250 | |||
251 | td->syncf_perfect = 0; | ||
252 | td->frame_time = 0; | ||
253 | td->frame_period = 0; | ||
254 | td->num_ref_pics = 0; | ||
255 | |||
256 | /* Sometimes theres no sequence headers nearby and libmpeg2 may have reset | ||
257 | * fully at some point */ | ||
258 | if ((td->info == NULL || td->info->sequence == NULL) && !init_sequence(td)) | ||
259 | { | ||
260 | DEBUGF("sync_decoder=>init_sequence failed\n"); | ||
261 | goto sync_finished; | ||
262 | } | ||
263 | |||
264 | video_str.hdr.pos = sd->sk.pos; | ||
265 | video_str.hdr.limit = sd->sk.pos + sd->sk.len; | ||
266 | mpeg2_reset(td->mpeg2dec, false); | ||
267 | mpeg2_skip(td->mpeg2dec, 1); | ||
268 | |||
269 | while (1) | ||
270 | { | ||
271 | mpeg2_state_t mp2state = mpeg2_parse(td->mpeg2dec); | ||
272 | |||
273 | switch (mp2state) | ||
274 | { | ||
275 | case STATE_BUFFER: | ||
276 | switch (parser_get_next_data(&video_str, STREAM_PM_RANDOM_ACCESS)) | ||
277 | { | ||
278 | case STREAM_DATA_END: | ||
279 | DEBUGF("sync_decoder:STR_DATA_END\n"); | ||
280 | if (td->info && td->info->display_picture && | ||
281 | !(td->info->display_picture->flags & PIC_FLAG_SKIP)) | ||
282 | { | ||
283 | /* No frame matching the time was found up to the end of | ||
284 | * the stream - consider a perfect match since no better | ||
285 | * can be made */ | ||
286 | retval = STREAM_PERFECT_MATCH; | ||
287 | td->syncf_perfect = 1; | ||
288 | } | ||
289 | goto sync_finished; | ||
290 | |||
291 | case STREAM_OK: | ||
292 | if (video_str.pkt_flags & PKT_HAS_TS) | ||
293 | mpeg2_tag_picture(td->mpeg2dec, video_str.pts, 0); | ||
294 | mpeg2_buffer(td->mpeg2dec, video_str.curr_packet, | ||
295 | video_str.curr_packet_end); | ||
296 | td->info = mpeg2_info(td->mpeg2dec); | ||
297 | break; | ||
298 | } | ||
299 | break; | ||
300 | |||
301 | case STATE_SEQUENCE: | ||
302 | DEBUGF(" STATE_SEQUENCE\n"); | ||
303 | vo_setup(td->info->sequence); | ||
304 | break; | ||
305 | |||
306 | case STATE_GOP: | ||
307 | DEBUGF(" STATE_GOP: (%s)\n", | ||
308 | (td->info->gop->flags & GOP_FLAG_CLOSED_GOP) ? | ||
309 | "closed" : "open"); | ||
310 | break; | ||
311 | |||
312 | case STATE_PICTURE: | ||
313 | { | ||
314 | int type = td->info->current_picture->flags | ||
315 | & PIC_MASK_CODING_TYPE; | ||
316 | |||
317 | switch (type) | ||
318 | { | ||
319 | case PIC_FLAG_CODING_TYPE_I: | ||
320 | /* I-frame; start decoding */ | ||
321 | mpeg2_skip(td->mpeg2dec, 0); | ||
322 | td->num_ref_pics++; | ||
323 | break; | ||
324 | |||
325 | case PIC_FLAG_CODING_TYPE_P: | ||
326 | /* P-frames don't count without I-frames */ | ||
327 | if (td->num_ref_pics > 0) | ||
328 | td->num_ref_pics++; | ||
329 | break; | ||
330 | } | ||
331 | |||
332 | if (td->info->current_picture->flags & PIC_FLAG_TAGS) | ||
333 | { | ||
334 | DEBUGF(" STATE_PICTURE (%c): %u\n", pic_coding_type_char(type), | ||
335 | (unsigned)td->info->current_picture->tag); | ||
336 | } | ||
337 | else | ||
338 | { | ||
339 | DEBUGF(" STATE_PICTURE (%c): -\n", pic_coding_type_char(type)); | ||
340 | } | ||
341 | |||
342 | break; | ||
343 | } | ||
344 | |||
345 | case STATE_SLICE: | ||
346 | case STATE_END: | ||
347 | case STATE_INVALID_END: | ||
348 | { | ||
349 | uint32_t end_time; | ||
350 | |||
351 | if (td->info->display_picture == NULL) | ||
352 | { | ||
353 | DEBUGF(" td->info->display_picture == NULL\n"); | ||
354 | break; /* No picture */ | ||
355 | } | ||
356 | |||
357 | int type = td->info->display_picture->flags | ||
358 | & PIC_MASK_CODING_TYPE; | ||
359 | |||
360 | if (td->info->display_picture->flags & PIC_FLAG_TAGS) | ||
361 | { | ||
362 | td->frame_time = td->info->display_picture->tag; | ||
363 | DEBUGF(" frame tagged:%u (%c%s)\n", (unsigned)td->frame_time, | ||
364 | pic_coding_type_char(type), | ||
365 | (td->info->display_picture->flags & PIC_FLAG_SKIP) ? | ||
366 | " skipped" : ""); | ||
367 | } | ||
368 | else | ||
369 | { | ||
370 | td->frame_time += td->frame_period; | ||
371 | DEBUGF(" add frame_period:%u (%c%s)\n", (unsigned)td->frame_time, | ||
372 | pic_coding_type_char(type), | ||
373 | (td->info->display_picture->flags & PIC_FLAG_SKIP) ? | ||
374 | " skipped" : ""); | ||
375 | } | ||
376 | |||
377 | td->frame_period = TC_TO_TS(td->info->sequence->frame_period); | ||
378 | end_time = td->frame_time + td->frame_period; | ||
379 | |||
380 | DEBUGF(" ft:%u t:%u fe:%u (%c%s)", | ||
381 | (unsigned)td->frame_time, | ||
382 | (unsigned)time, | ||
383 | (unsigned)end_time, | ||
384 | pic_coding_type_char(type), | ||
385 | (td->info->display_picture->flags & PIC_FLAG_SKIP) ? | ||
386 | " skipped" : ""); | ||
387 | |||
388 | if (end_time <= time && end_time < video_str.end_pts) | ||
389 | { | ||
390 | /* Still too early and have not hit at EOS */ | ||
391 | DEBUGF(" too early\n"); | ||
392 | break; | ||
393 | } | ||
394 | else if (!(td->info->display_picture->flags & PIC_FLAG_SKIP)) | ||
395 | { | ||
396 | /* One perfect point if dependent frames were decoded */ | ||
397 | switch (type) | ||
398 | { | ||
399 | case PIC_FLAG_CODING_TYPE_B: | ||
400 | if (td->num_ref_pics > 1) | ||
401 | { | ||
402 | case PIC_FLAG_CODING_TYPE_P: | ||
403 | if (td->num_ref_pics > 0) | ||
404 | { | ||
405 | case PIC_FLAG_CODING_TYPE_I: | ||
406 | td->syncf_perfect = 1; | ||
407 | break; | ||
408 | } | ||
409 | } | ||
410 | } | ||
411 | |||
412 | if ((td->frame_time <= time && time < end_time) || | ||
413 | end_time >= video_str.end_pts) | ||
414 | { | ||
415 | /* One perfect point for matching time goal */ | ||
416 | DEBUGF(" ft<=t<fe\n"); | ||
417 | td->syncf_perfect++; | ||
418 | } | ||
419 | else | ||
420 | { | ||
421 | DEBUGF(" ft>t\n"); | ||
422 | } | ||
423 | |||
424 | /* Two or more perfect points = perfect match - yay! */ | ||
425 | retval = (td->syncf_perfect >= 2) ? | ||
426 | STREAM_PERFECT_MATCH : STREAM_MATCH; | ||
427 | } | ||
428 | else | ||
429 | { | ||
430 | /* Too late, no I-Frame yet */ | ||
431 | DEBUGF("\n"); | ||
432 | } | ||
433 | |||
434 | goto sync_finished; | ||
435 | } | ||
436 | |||
437 | default: | ||
438 | break; | ||
439 | } | ||
440 | |||
441 | rb->yield(); | ||
442 | } /* end while */ | ||
443 | |||
444 | sync_finished: | ||
445 | mpeg2_skip(td->mpeg2dec, 0); | ||
446 | return retval; | ||
447 | } | ||
448 | |||
449 | static bool frame_print_handler(struct video_thread_data *td) | ||
450 | { | ||
451 | bool retval; | ||
452 | uint8_t * const * buf = NULL; | ||
453 | |||
454 | if (td->info != NULL && td->info->display_fbuf != NULL && | ||
455 | td->syncf_perfect > 0) | ||
456 | buf = td->info->display_fbuf->buf; | ||
457 | |||
458 | if (td->ev.id == VIDEO_PRINT_THUMBNAIL) | ||
459 | { | ||
460 | /* Print a thumbnail of whatever was last decoded - scale and | ||
461 | * position to fill the specified rectangle */ | ||
462 | retval = vo_draw_frame_thumb(buf, (struct vo_rect *)td->ev.data); | ||
463 | } | ||
464 | else | ||
465 | { | ||
466 | /* Print the last frame decoded */ | ||
467 | vo_draw_frame(buf); | ||
468 | retval = buf != NULL; | ||
469 | } | ||
470 | |||
471 | return retval; | ||
472 | } | ||
473 | |||
474 | /* This only returns to play or quit */ | ||
475 | static void video_thread_msg(struct video_thread_data *td) | ||
476 | { | ||
477 | while (1) | ||
478 | { | ||
479 | intptr_t reply = 0; | ||
480 | |||
481 | switch (td->ev.id) | ||
482 | { | ||
483 | case STREAM_PLAY: | ||
484 | td->status = STREAM_PLAYING; | ||
485 | |||
486 | switch (td->state) | ||
487 | { | ||
488 | case TSTATE_INIT: | ||
489 | /* Begin decoding state */ | ||
490 | td->state = TSTATE_DECODE; | ||
491 | /* */ | ||
492 | case TSTATE_DECODE: | ||
493 | if (td->syncf_perfect <= 0) | ||
494 | break; | ||
495 | /* There should be a frame already, just draw it */ | ||
496 | td->goal_time = td->frame_time; | ||
497 | td->state = TSTATE_RENDER_WAIT; | ||
498 | /* */ | ||
499 | case TSTATE_RENDER_WAIT: | ||
500 | /* Settings may have changed to nonlimited - just draw | ||
501 | * what was previously being waited for */ | ||
502 | td->stream_time = TICKS_TO_TS(stream_get_time()); | ||
503 | if (!settings.limitfps) | ||
504 | td->state = TSTATE_RENDER; | ||
505 | /* */ | ||
506 | case TSTATE_RENDER: | ||
507 | break; | ||
508 | |||
509 | case TSTATE_EOS: | ||
510 | /* At end of stream - no playback possible so fire the | ||
511 | * completion event */ | ||
512 | stream_generate_event(&video_str, STREAM_EV_COMPLETE, 0); | ||
513 | break; | ||
514 | } | ||
515 | |||
516 | reply = td->state != TSTATE_EOS; | ||
517 | break; | ||
518 | |||
519 | case STREAM_PAUSE: | ||
520 | td->status = STREAM_PAUSED; | ||
521 | reply = td->state != TSTATE_EOS; | ||
522 | break; | ||
523 | |||
524 | case STREAM_STOP: | ||
525 | if (td->state == TSTATE_DATA) | ||
526 | stream_clear_notify(&video_str, DISK_BUF_DATA_NOTIFY); | ||
527 | |||
528 | td->status = STREAM_STOPPED; | ||
529 | td->state = TSTATE_EOS; | ||
530 | reply = true; | ||
531 | break; | ||
532 | |||
533 | case VIDEO_DISPLAY_IS_VISIBLE: | ||
534 | reply = vo_is_visible(); | ||
535 | break; | ||
536 | |||
537 | case VIDEO_DISPLAY_SHOW: | ||
538 | /* Show video and draw the last frame we had if any or reveal the | ||
539 | * underlying framebuffer if hiding */ | ||
540 | reply = vo_show(!!td->ev.data); | ||
541 | |||
542 | #ifdef HAVE_LCD_COLOR | ||
543 | /* Match graylib behavior as much as possible */ | ||
544 | if (!td->ev.data == !reply) | ||
545 | break; | ||
546 | |||
547 | if (td->ev.data) | ||
548 | { | ||
549 | frame_print_handler(td); | ||
550 | } | ||
551 | else | ||
552 | { | ||
553 | IF_COP(rb->commit_discard_dcache()); | ||
554 | vo_lock(); | ||
555 | rb->lcd_update(); | ||
556 | vo_unlock(); | ||
557 | } | ||
558 | #endif | ||
559 | break; | ||
560 | |||
561 | case STREAM_RESET: | ||
562 | if (td->state == TSTATE_DATA) | ||
563 | stream_clear_notify(&video_str, DISK_BUF_DATA_NOTIFY); | ||
564 | |||
565 | td->state = TSTATE_INIT; | ||
566 | td->status = STREAM_STOPPED; | ||
567 | |||
568 | /* Reset operational info but not sync info */ | ||
569 | td->stream_time = UINT32_MAX; | ||
570 | td->goal_time = 0; | ||
571 | td->remain_time = 0; | ||
572 | td->skip_ref_pics = 0; | ||
573 | td->skip_level = 0; | ||
574 | td->num_picture = 0; | ||
575 | td->num_intra = 0; | ||
576 | td->group_est = DEFAULT_GOP_SIZE; | ||
577 | td->last_render = *rb->current_tick - HZ; | ||
578 | video_num_drawn = 0; | ||
579 | video_num_skipped = 0; | ||
580 | |||
581 | reply = true; | ||
582 | break; | ||
583 | |||
584 | case STREAM_NEEDS_SYNC: | ||
585 | reply = check_needs_sync(td, td->ev.data); | ||
586 | break; | ||
587 | |||
588 | case STREAM_SYNC: | ||
589 | if (td->state == TSTATE_INIT) | ||
590 | reply = sync_decoder(td, (struct str_sync_data *)td->ev.data); | ||
591 | break; | ||
592 | |||
593 | case DISK_BUF_DATA_NOTIFY: | ||
594 | /* Our bun is done */ | ||
595 | if (td->state != TSTATE_DATA) | ||
596 | break; | ||
597 | |||
598 | td->state = TSTATE_DECODE; | ||
599 | str_data_notify_received(&video_str); | ||
600 | break; | ||
601 | |||
602 | case VIDEO_PRINT_FRAME: | ||
603 | case VIDEO_PRINT_THUMBNAIL: | ||
604 | reply = frame_print_handler(td); | ||
605 | break; | ||
606 | |||
607 | case VIDEO_SET_CLIP_RECT: | ||
608 | vo_set_clip_rect((const struct vo_rect *)td->ev.data); | ||
609 | break; | ||
610 | |||
611 | case VIDEO_GET_CLIP_RECT: | ||
612 | reply = vo_get_clip_rect((struct vo_rect *)td->ev.data); | ||
613 | break; | ||
614 | |||
615 | case VIDEO_GET_SIZE: | ||
616 | { | ||
617 | if (td->state != TSTATE_INIT) | ||
618 | break; /* Can only use after a reset was issued */ | ||
619 | |||
620 | /* This will reset the decoder in full for this particular event */ | ||
621 | if (init_sequence(td)) | ||
622 | { | ||
623 | reply = true; | ||
624 | vo_dimensions((struct vo_ext *)td->ev.data); | ||
625 | } | ||
626 | break; | ||
627 | } | ||
628 | |||
629 | case STREAM_FIND_END_TIME: | ||
630 | if (td->state != TSTATE_INIT) | ||
631 | { | ||
632 | reply = STREAM_ERROR; | ||
633 | break; | ||
634 | } | ||
635 | |||
636 | reply = video_str_scan(td, (struct str_sync_data *)td->ev.data); | ||
637 | break; | ||
638 | |||
639 | case VIDEO_SET_POST_FRAME_CALLBACK: | ||
640 | vo_set_post_draw_callback((void (*)(void))td->ev.data); | ||
641 | reply = true; | ||
642 | break; | ||
643 | |||
644 | case STREAM_QUIT: | ||
645 | /* Time to go - make thread exit */ | ||
646 | td->state = TSTATE_EOS; | ||
647 | return; | ||
648 | } | ||
649 | |||
650 | str_reply_msg(&video_str, reply); | ||
651 | |||
652 | if (td->status == STREAM_PLAYING) | ||
653 | { | ||
654 | switch (td->state) | ||
655 | { | ||
656 | case TSTATE_DECODE: | ||
657 | case TSTATE_RENDER: | ||
658 | case TSTATE_RENDER_WAIT: | ||
659 | /* These return when in playing state */ | ||
660 | return; | ||
661 | } | ||
662 | } | ||
663 | |||
664 | str_get_msg(&video_str, &td->ev); | ||
665 | } | ||
666 | } | ||
667 | |||
668 | static void video_thread(void) | ||
669 | { | ||
670 | struct video_thread_data td; | ||
671 | |||
672 | memset(&td, 0, sizeof (td)); | ||
673 | td.mpeg2dec = mpeg2_init(); | ||
674 | td.status = STREAM_STOPPED; | ||
675 | td.state = TSTATE_EOS; | ||
676 | |||
677 | if (td.mpeg2dec == NULL) | ||
678 | { | ||
679 | td.status = STREAM_ERROR; | ||
680 | /* Loop and wait for quit message */ | ||
681 | while (1) | ||
682 | { | ||
683 | str_get_msg(&video_str, &td.ev); | ||
684 | if (td.ev.id == STREAM_QUIT) | ||
685 | return; | ||
686 | str_reply_msg(&video_str, STREAM_ERROR); | ||
687 | } | ||
688 | } | ||
689 | |||
690 | vo_init(); | ||
691 | |||
692 | goto message_wait; | ||
693 | |||
694 | while (1) | ||
695 | { | ||
696 | mpeg2_state_t mp2state; | ||
697 | td.state = TSTATE_DECODE; | ||
698 | |||
699 | /* Check for any pending messages and process them */ | ||
700 | if (str_have_msg(&video_str)) | ||
701 | { | ||
702 | message_wait: | ||
703 | /* Wait for a message to be queued */ | ||
704 | str_get_msg(&video_str, &td.ev); | ||
705 | |||
706 | message_process: | ||
707 | /* Process a message already dequeued */ | ||
708 | video_thread_msg(&td); | ||
709 | |||
710 | switch (td.state) | ||
711 | { | ||
712 | /* These states are the only ones that should return */ | ||
713 | case TSTATE_DECODE: goto picture_decode; | ||
714 | case TSTATE_RENDER: goto picture_draw; | ||
715 | case TSTATE_RENDER_WAIT: goto picture_wait; | ||
716 | /* Anything else is interpreted as an exit */ | ||
717 | default: goto video_exit; | ||
718 | } | ||
719 | } | ||
720 | |||
721 | picture_decode: | ||
722 | mp2state = mpeg2_parse (td.mpeg2dec); | ||
723 | |||
724 | switch (mp2state) | ||
725 | { | ||
726 | case STATE_BUFFER: | ||
727 | /* Request next packet data */ | ||
728 | switch (parser_get_next_data(&video_str, STREAM_PM_STREAMING)) | ||
729 | { | ||
730 | case STREAM_DATA_NOT_READY: | ||
731 | /* Wait for data to be buffered */ | ||
732 | td.state = TSTATE_DATA; | ||
733 | goto message_wait; | ||
734 | |||
735 | case STREAM_DATA_END: | ||
736 | /* No more data. */ | ||
737 | td.state = TSTATE_EOS; | ||
738 | if (td.status == STREAM_PLAYING) | ||
739 | stream_generate_event(&video_str, STREAM_EV_COMPLETE, 0); | ||
740 | goto message_wait; | ||
741 | |||
742 | case STREAM_OK: | ||
743 | if (video_str.pkt_flags & PKT_HAS_TS) | ||
744 | mpeg2_tag_picture(td.mpeg2dec, video_str.pts, 0); | ||
745 | |||
746 | mpeg2_buffer(td.mpeg2dec, video_str.curr_packet, | ||
747 | video_str.curr_packet_end); | ||
748 | td.info = mpeg2_info(td.mpeg2dec); | ||
749 | break; | ||
750 | } | ||
751 | break; | ||
752 | |||
753 | case STATE_SEQUENCE: | ||
754 | /* New video sequence, inform output of any changes */ | ||
755 | vo_setup(td.info->sequence); | ||
756 | break; | ||
757 | |||
758 | case STATE_PICTURE: | ||
759 | { | ||
760 | /* This is not in presentation order - do our best anyway */ | ||
761 | int skip = td.skip_ref_pics; | ||
762 | |||
763 | /* Frame type: I/P/B/D */ | ||
764 | switch (td.info->current_picture->flags & PIC_MASK_CODING_TYPE) | ||
765 | { | ||
766 | case PIC_FLAG_CODING_TYPE_I: | ||
767 | if (++td.num_intra >= 2) | ||
768 | td.group_est = td.num_picture / (td.num_intra - 1); | ||
769 | |||
770 | /* Things are extremely late and all frames will be | ||
771 | dropped until the next key frame */ | ||
772 | if (td.skip_level > 0 && td.skip_level >= td.group_est) | ||
773 | { | ||
774 | td.skip_level--; /* skip frame */ | ||
775 | skip = td.skip_ref_pics = 1; /* wait for I-frame */ | ||
776 | td.num_ref_pics = 0; | ||
777 | } | ||
778 | else if (skip != 0) | ||
779 | { | ||
780 | skip = td.skip_ref_pics = 0; /* now, decode */ | ||
781 | td.num_ref_pics = 1; | ||
782 | } | ||
783 | break; | ||
784 | |||
785 | case PIC_FLAG_CODING_TYPE_P: | ||
786 | if (skip == 0) | ||
787 | { | ||
788 | td.num_ref_pics++; | ||
789 | |||
790 | /* If skip_level at least the estimated number of frames | ||
791 | left in I-I span, skip until next I-frame */ | ||
792 | if (td.group_est > 0 && td.skip_level >= td.group_est) | ||
793 | { | ||
794 | skip = td.skip_ref_pics = 1; /* wait for I-frame */ | ||
795 | td.num_ref_pics = 0; | ||
796 | } | ||
797 | } | ||
798 | |||
799 | if (skip != 0) | ||
800 | td.skip_level--; | ||
801 | break; | ||
802 | |||
803 | case PIC_FLAG_CODING_TYPE_B: | ||
804 | /* We want to drop something, so this B-frame won't even be | ||
805 | decoded. Drawing can happen on the next frame if so desired | ||
806 | so long as the B-frames were not dependent upon those from | ||
807 | a previous open GOP where the needed reference frames were | ||
808 | skipped */ | ||
809 | if (td.skip_level > 0 || td.num_ref_pics < 2) | ||
810 | { | ||
811 | skip = 1; | ||
812 | td.skip_level--; | ||
813 | } | ||
814 | break; | ||
815 | |||
816 | default: | ||
817 | skip = 1; | ||
818 | break; | ||
819 | } | ||
820 | |||
821 | if (td.num_intra > 0) | ||
822 | td.num_picture++; | ||
823 | |||
824 | td.group_est--; | ||
825 | |||
826 | mpeg2_skip(td.mpeg2dec, skip); | ||
827 | break; | ||
828 | } | ||
829 | |||
830 | case STATE_SLICE: | ||
831 | case STATE_END: | ||
832 | case STATE_INVALID_END: | ||
833 | { | ||
834 | int32_t offset; /* Tick adjustment to keep sync */ | ||
835 | |||
836 | if (td.info->display_fbuf == NULL) | ||
837 | break; /* No picture */ | ||
838 | |||
839 | /* Get presentation times in audio samples - quite accurate | ||
840 | enough - add previous frame duration if not stamped */ | ||
841 | if (td.info->display_picture->flags & PIC_FLAG_TAGS) | ||
842 | td.frame_time = td.info->display_picture->tag; | ||
843 | else | ||
844 | td.frame_time += td.frame_period; | ||
845 | |||
846 | td.frame_period = TC_TO_TS(td.info->sequence->frame_period); | ||
847 | |||
848 | if (!settings.limitfps) | ||
849 | { | ||
850 | /* No limiting => no dropping or waiting - draw this frame */ | ||
851 | td.remain_time = 0; | ||
852 | td.skip_level = 0; | ||
853 | td.syncf_perfect = 1; /* have frame */ | ||
854 | goto picture_draw; | ||
855 | } | ||
856 | |||
857 | td.goal_time = td.frame_time; | ||
858 | td.stream_time = TICKS_TO_TS(stream_get_time()); | ||
859 | |||
860 | /* How early/late are we? > 0 = late, < 0 early */ | ||
861 | offset = td.stream_time - td.goal_time; | ||
862 | |||
863 | if (offset >= 0) | ||
864 | { | ||
865 | /* Late or on-time */ | ||
866 | if (td.remain_time < 0) | ||
867 | td.remain_time = 0; /* now, late */ | ||
868 | |||
869 | offset = AVERAGE(td.remain_time, offset, 4); | ||
870 | td.remain_time = offset; | ||
871 | } | ||
872 | else | ||
873 | { | ||
874 | /* Early */ | ||
875 | if (td.remain_time >= 0) | ||
876 | td.remain_time = 0; /* now, early */ | ||
877 | else if (offset > td.remain_time) | ||
878 | td.remain_time = MAX(offset, -MAX_EARLINESS); /* less early */ | ||
879 | else if (td.remain_time != 0) | ||
880 | td.remain_time = AVERAGE(td.remain_time, 0, 8); /* earlier/same */ | ||
881 | /* else there's been no frame drop */ | ||
882 | |||
883 | offset = -td.remain_time; | ||
884 | } | ||
885 | |||
886 | /* Skip anything not decoded */ | ||
887 | if (td.info->display_picture->flags & PIC_FLAG_SKIP) | ||
888 | goto picture_skip; | ||
889 | |||
890 | td.syncf_perfect = 1; /* have frame (assume so from now on) */ | ||
891 | |||
892 | /* Keep goal_time >= 0 */ | ||
893 | if ((uint32_t)offset > td.goal_time) | ||
894 | offset = td.goal_time; | ||
895 | |||
896 | td.goal_time -= offset; | ||
897 | |||
898 | if (!settings.skipframes) | ||
899 | { | ||
900 | /* No skipping - just wait if we're early and correct for | ||
901 | lateness as much as possible. */ | ||
902 | td.skip_level = 0; | ||
903 | goto picture_wait; | ||
904 | } | ||
905 | |||
906 | /** Possibly skip this frame **/ | ||
907 | |||
908 | /* Frameskipping has the following order of preference: | ||
909 | * | ||
910 | * Frame Type Who Notes/Rationale | ||
911 | * B decoder arbitrarily drop - no decode or draw | ||
912 | * Any renderer arbitrarily drop - I/P unless B decoded | ||
913 | * P decoder must wait for I-frame | ||
914 | * I decoder must wait for I-frame | ||
915 | * | ||
916 | * If a frame can be drawn and it has been at least 1/2 second, | ||
917 | * the image will be updated no matter how late it is just to | ||
918 | * avoid looking stuck. | ||
919 | */ | ||
920 | if (td.skip_level > 0 && | ||
921 | TIME_BEFORE(*rb->current_tick, td.last_render + HZ/2)) | ||
922 | { | ||
923 | /* Frame skip was set previously but either there wasn't anything | ||
924 | dropped yet or not dropped enough. So we quit at least rendering | ||
925 | the actual frame to avoid further increase of a/v-drift. */ | ||
926 | td.skip_level--; | ||
927 | goto picture_skip; | ||
928 | } | ||
929 | |||
930 | /* At this point a frame _will_ be drawn - a skip may happen on | ||
931 | the next however */ | ||
932 | |||
933 | /* Calculate number of frames to drop/skip - allow brief periods | ||
934 | of lateness before producing skips */ | ||
935 | td.skip_level = 0; | ||
936 | if (td.remain_time > 0 && (uint32_t)offset > DROP_THRESHOLD) | ||
937 | { | ||
938 | td.skip_level = (offset - DROP_THRESHOLD + td.frame_period) | ||
939 | / td.frame_period; | ||
940 | } | ||
941 | |||
942 | picture_wait: | ||
943 | td.state = TSTATE_RENDER_WAIT; | ||
944 | |||
945 | /* Wait until time catches up */ | ||
946 | while (1) | ||
947 | { | ||
948 | int32_t twait = td.goal_time - td.stream_time; | ||
949 | /* Watch for messages while waiting for the frame time */ | ||
950 | |||
951 | if (twait <= 0) | ||
952 | break; | ||
953 | |||
954 | if (twait > TS_SECOND/HZ) | ||
955 | { | ||
956 | /* Several ticks to wait - do some sleeping */ | ||
957 | int timeout = (twait - HZ) / (TS_SECOND/HZ); | ||
958 | str_get_msg_w_tmo(&video_str, &td.ev, MAX(timeout, 1)); | ||
959 | if (td.ev.id != SYS_TIMEOUT) | ||
960 | goto message_process; | ||
961 | } | ||
962 | else | ||
963 | { | ||
964 | /* Just a little left - spin and be accurate */ | ||
965 | rb->yield(); | ||
966 | if (str_have_msg(&video_str)) | ||
967 | goto message_wait; | ||
968 | } | ||
969 | |||
970 | td.stream_time = TICKS_TO_TS(stream_get_time()); | ||
971 | } | ||
972 | |||
973 | picture_draw: | ||
974 | /* Record last frame time */ | ||
975 | td.last_render = *rb->current_tick; | ||
976 | |||
977 | vo_draw_frame(td.info->display_fbuf->buf); | ||
978 | video_num_drawn++; | ||
979 | break; | ||
980 | |||
981 | picture_skip: | ||
982 | if (td.remain_time <= DROP_THRESHOLD) | ||
983 | { | ||
984 | td.skip_level = 0; | ||
985 | if (td.remain_time <= 0) | ||
986 | td.remain_time = INT32_MIN; | ||
987 | } | ||
988 | |||
989 | video_num_skipped++; | ||
990 | break; | ||
991 | } | ||
992 | |||
993 | default: | ||
994 | break; | ||
995 | } | ||
996 | |||
997 | rb->yield(); | ||
998 | } /* end while */ | ||
999 | |||
1000 | video_exit: | ||
1001 | vo_cleanup(); | ||
1002 | mpeg2_close(td.mpeg2dec); | ||
1003 | } | ||
1004 | |||
1005 | /* Initializes the video thread */ | ||
1006 | bool video_thread_init(void) | ||
1007 | { | ||
1008 | intptr_t rep; | ||
1009 | |||
1010 | IF_COP(rb->commit_dcache()); | ||
1011 | |||
1012 | video_str.hdr.q = &video_str_queue; | ||
1013 | rb->queue_init(video_str.hdr.q, false); | ||
1014 | |||
1015 | /* We put the video thread on another processor for multi-core targets. */ | ||
1016 | video_str.thread = rb->create_thread( | ||
1017 | video_thread, video_stack, VIDEO_STACKSIZE, 0, | ||
1018 | "mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK) IF_COP(, COP)); | ||
1019 | |||
1020 | rb->queue_enable_queue_send(video_str.hdr.q, &video_str_queue_send, | ||
1021 | video_str.thread); | ||
1022 | |||
1023 | if (video_str.thread == 0) | ||
1024 | return false; | ||
1025 | |||
1026 | /* Wait for thread to initialize */ | ||
1027 | rep = str_send_msg(&video_str, STREAM_NULL, 0); | ||
1028 | IF_COP(rb->commit_discard_dcache()); | ||
1029 | |||
1030 | return rep == 0; /* Normally STREAM_NULL should be ignored */ | ||
1031 | } | ||
1032 | |||
1033 | /* Terminates the video thread */ | ||
1034 | void video_thread_exit(void) | ||
1035 | { | ||
1036 | if (video_str.thread != 0) | ||
1037 | { | ||
1038 | str_post_msg(&video_str, STREAM_QUIT, 0); | ||
1039 | rb->thread_wait(video_str.thread); | ||
1040 | IF_COP(rb->commit_discard_dcache()); | ||
1041 | video_str.thread = 0; | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | |||
1046 | /** Misc **/ | ||
1047 | void video_thread_get_stats(struct video_output_stats *s) | ||
1048 | { | ||
1049 | uint32_t start; | ||
1050 | uint32_t now = stream_get_ticks(&start); | ||
1051 | s->num_drawn = video_num_drawn; | ||
1052 | s->num_skipped = video_num_skipped; | ||
1053 | |||
1054 | s->fps = 0; | ||
1055 | |||
1056 | if (now > start) | ||
1057 | s->fps = muldiv_uint32(CLOCK_RATE*100, s->num_drawn, now - start); | ||
1058 | } | ||
1059 | |||
diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config index 8d266966d0..26c1543fdd 100644 --- a/apps/plugins/viewers.config +++ b/apps/plugins/viewers.config | |||
@@ -71,10 +71,6 @@ wav,viewers/wavview,10 | |||
71 | wav,viewers/wav2wv,- | 71 | wav,viewers/wav2wv,- |
72 | wav,viewers/mp3_encoder,- | 72 | wav,viewers/mp3_encoder,- |
73 | wav,viewers/test_codec,- | 73 | wav,viewers/test_codec,- |
74 | mpg,viewers/mpegplayer,4 | ||
75 | mpeg,viewers/mpegplayer,4 | ||
76 | mpv,viewers/mpegplayer,4 | ||
77 | m2v,viewers/mpegplayer,4 | ||
78 | iriver,viewers/iriver_flash,3 | 74 | iriver,viewers/iriver_flash,3 |
79 | tap,viewers/zxbox,12 | 75 | tap,viewers/zxbox,12 |
80 | opx,viewers/open_plugins,- | 76 | opx,viewers/open_plugins,- |