blob: af0567c0d1e03af93fd990d4a6a04cca23746666 [file] [log] [blame]
Dave Chapman4b801b22007-01-01 12:59:32 +00001/*
2 * mpegplayer.c - based on :
3 * - mpeg2dec.c
4 * - m2psd.c (http://www.brouhaha.com/~eric/software/m2psd/)
Dave Chapmanc9d66562006-08-07 22:11:07 +00005 *
6 * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
7 * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
Michael Sevakis6689cb02007-04-10 14:18:30 +00008 *
Dave Chapman4b801b22007-01-01 12:59:32 +00009 * m2psd: MPEG 2 Program Stream Demultiplexer
10 * Copyright (C) 2003 Eric Smith <eric@brouhaha.com>
Dave Chapmanc9d66562006-08-07 22:11:07 +000011 *
12 * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
13 * See http://libmpeg2.sourceforge.net/ for updates.
14 *
15 * mpeg2dec is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * mpeg2dec is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 */
29
Dave Chapman4b801b22007-01-01 12:59:32 +000030/*
31
32NOTES:
33
34mpegplayer is structured as follows:
35
361) Video thread (running on the COP for PortalPlayer targets).
372) Audio thread (running on the main CPU to maintain consistency with
38 the audio FIQ hander on PP).
393) The main thread which takes care of buffering.
40
41Using the main thread for buffering wastes the 8KB main stack which is
42in IRAM. However, 8KB is not enough for the audio thread to run (it
43needs somewhere between 8KB and 9KB), so we create a new thread in
44order to`give it a larger stack.
45
46We use 4.5KB of the main stack for a libmad buffer (making use of
47otherwise unused IRAM). There is also the possiblity of stealing the
48main Rockbox codec thread's 9KB of IRAM stack and using that for
49mpegplayer's audio thread - but we should only implement that if we
50can put the IRAM to good use.
51
52The button loop (and hence pause/resume, main menu and, in the future,
53seeking) is placed in the audio thread. This keeps it on the main CPU
54in PP targets and also allows buffering to continue in the background
55whilst the main thread is filling the buffer.
56
57A/V sync is not yet implemented but is planned to be achieved by
58syncing the master clock with the audio, and then (as is currently
59implemented), syncing video with the master clock. This can happen in
60the audio thread, along with resyncing after pause.
61
62Seeking should probably happen in the main thread, as that's where the
63buffering happens.
64
65On PortalPlayer targets, the main CPU is not being fully utilised -
66the bottleneck is the video decoding on the COP. One way to improve
67that might be to move the rendering of the frames (i.e. the
68lcd_yuv_blit() call) from the COP back to the main CPU. Ideas and
69patches for that are welcome!
70
71Notes about MPEG files:
72
73MPEG System Clock is 27MHz - i.e. 27000000 ticks/second.
74
75FPS is represented in terms of a frame period - this is always an
76integer number of 27MHz ticks.
77
78e.g. 29.97fps (30000/1001) NTSC video has an exact frame period of
79900900 27MHz ticks.
80
81In libmpeg2, info->sequence->frame_period contains the frame_period.
82
83Working with Rockbox's 100Hz tick, the common frame rates would need
84to be as follows:
85
Dave Chapman83108482007-03-22 09:18:46 +000086FPS | 27Mhz | 100Hz | 44.1KHz | 48KHz
87--------|-----------------------------------------------------------
8810* | 2700000 | 10 | 4410 | 4800
8912* | 2250000 | 8.3333 | 3675 | 4000
9015* | 1800000 | 6.6667 | 2940 | 3200
9123.9760 | 1126125 | 4.170833333 | 1839.3375 | 2002
9224 | 1125000 | 4.166667 | 1837.5 | 2000
9325 | 1080000 | 4 | 1764 | 1920
9429.9700 | 900900 | 3.336667 | 1471,47 | 1601.6
9530 | 900000 | 3.333333 | 1470 | 1600
Dave Chapman4b801b22007-01-01 12:59:32 +000096
97
98*Unofficial framerates
99
100*/
101
102
Dave Chapmanc9d66562006-08-07 22:11:07 +0000103#include "mpeg2dec_config.h"
104
105#include "plugin.h"
Dave Chapmana5675712007-03-26 01:32:31 +0000106#include "gray.h"
Peter D'Hoyea5d4d672007-08-13 22:31:11 +0000107#include "helper.h"
Dave Chapmanc9d66562006-08-07 22:11:07 +0000108
109#include "mpeg2.h"
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000110#include "mpeg_settings.h"
Dave Chapmanc9d66562006-08-07 22:11:07 +0000111#include "video_out.h"
Dave Chapman4b801b22007-01-01 12:59:32 +0000112#include "../../codecs/libmad/mad.h"
Dave Chapmanc9d66562006-08-07 22:11:07 +0000113
114PLUGIN_HEADER
Michael Sevakisacc29d92006-11-18 02:18:29 +0000115PLUGIN_IRAM_DECLARE
Dave Chapmanc9d66562006-08-07 22:11:07 +0000116
Dave Chapman8d642c32006-08-09 10:47:22 +0000117/* button definitions */
118#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000119#define MPEG_MENU BUTTON_MODE
Dave Chapman8d642c32006-08-09 10:47:22 +0000120#define MPEG_STOP BUTTON_OFF
121#define MPEG_PAUSE BUTTON_ON
Dave Chapmanf1bf7982007-03-18 17:04:44 +0000122#define MPEG_VOLDOWN BUTTON_DOWN
123#define MPEG_VOLUP BUTTON_UP
Dave Chapmanc9d66562006-08-07 22:11:07 +0000124
Jens Arnoldb7013222007-07-27 09:57:27 +0000125#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
126 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000127#define MPEG_MENU BUTTON_MENU
128#define MPEG_PAUSE (BUTTON_PLAY | BUTTON_REL)
129#define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT)
Dave Chapmanf1bf7982007-03-18 17:04:44 +0000130#define MPEG_VOLDOWN BUTTON_SCROLL_BACK
131#define MPEG_VOLUP BUTTON_SCROLL_FWD
Dave Chapman8d642c32006-08-09 10:47:22 +0000132
Jens Arnold85a226d2007-03-16 23:02:39 +0000133#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000134#define MPEG_MENU (BUTTON_REC | BUTTON_REL)
Dave Chapman8d642c32006-08-09 10:47:22 +0000135#define MPEG_STOP BUTTON_POWER
136#define MPEG_PAUSE BUTTON_PLAY
Dave Chapmanf1bf7982007-03-18 17:04:44 +0000137#define MPEG_VOLDOWN BUTTON_DOWN
138#define MPEG_VOLUP BUTTON_UP
Dave Chapman8d642c32006-08-09 10:47:22 +0000139
Marcoen Hirschberg91022732006-08-09 13:25:43 +0000140#elif CONFIG_KEYPAD == GIGABEAT_PAD
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000141#define MPEG_MENU BUTTON_MENU
Marcoen Hirschberga7168fe2007-05-19 23:38:09 +0000142#define MPEG_STOP BUTTON_POWER
Marcoen Hirschberg91022732006-08-09 13:25:43 +0000143#define MPEG_PAUSE BUTTON_SELECT
Tom Ross79df16a2007-03-28 23:09:59 +0000144#define MPEG_VOLDOWN BUTTON_LEFT
145#define MPEG_VOLUP BUTTON_RIGHT
Dave Chapmanf1bf7982007-03-18 17:04:44 +0000146#define MPEG_VOLDOWN2 BUTTON_VOL_DOWN
147#define MPEG_VOLUP2 BUTTON_VOL_UP
Marcoen Hirschberg91022732006-08-09 13:25:43 +0000148
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000149#elif CONFIG_KEYPAD == IRIVER_H10_PAD
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000150#define MPEG_MENU (BUTTON_REW | BUTTON_REL)
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000151#define MPEG_STOP BUTTON_POWER
152#define MPEG_PAUSE BUTTON_PLAY
Dave Chapmanf1bf7982007-03-18 17:04:44 +0000153#define MPEG_VOLDOWN BUTTON_SCROLL_DOWN
154#define MPEG_VOLUP BUTTON_SCROLL_UP
Hristo Kovachev9dc0e622006-08-11 08:35:27 +0000155
Barry Wardell24f4a2a2006-10-26 13:38:09 +0000156#elif CONFIG_KEYPAD == SANSA_E200_PAD
157#define MPEG_MENU BUTTON_SELECT
158#define MPEG_STOP BUTTON_POWER
159#define MPEG_PAUSE BUTTON_UP
Dave Chapmanf1bf7982007-03-18 17:04:44 +0000160#define MPEG_VOLDOWN BUTTON_SCROLL_UP
161#define MPEG_VOLUP BUTTON_SCROLL_DOWN
Barry Wardell24f4a2a2006-10-26 13:38:09 +0000162
Marianne Arnold12ddb8e2007-09-20 10:49:48 +0000163#elif CONFIG_KEYPAD == SANSA_C200_PAD
164#define MPEG_MENU BUTTON_SELECT
165#define MPEG_STOP BUTTON_POWER
166#define MPEG_PAUSE BUTTON_UP
167#define MPEG_VOLDOWN BUTTON_VOL_DOWN
168#define MPEG_VOLUP BUTTON_VOL_UP
169
Dave Chapman8d642c32006-08-09 10:47:22 +0000170#else
171#error MPEGPLAYER: Unsupported keypad
172#endif
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000173
Dave Chapman4b801b22007-01-01 12:59:32 +0000174struct plugin_api* rb;
175
176static mpeg2dec_t * mpeg2dec;
177static int total_offset = 0;
Marcoen Hirschberg3585ee72007-06-19 21:30:45 +0000178static int num_drawn = 0;
179static int count_start = 0;
Dave Chapman4b801b22007-01-01 12:59:32 +0000180
181/* Streams */
182typedef struct
183{
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000184 struct thread_entry *thread; /* Stream's thread */
185 int status; /* Current stream status */
186 struct event ev; /* Event sent to steam */
187 int have_msg; /* 1=event pending */
188 int replied; /* 1=replied to last event */
189 int reply; /* reply value */
190 struct mutex msg_lock; /* serialization for event senders */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000191 uint8_t* curr_packet; /* Current stream packet beginning */
192 uint8_t* curr_packet_end; /* Current stream packet end */
Dave Chapman4b801b22007-01-01 12:59:32 +0000193
Michael Sevakis6689cb02007-04-10 14:18:30 +0000194 uint8_t* prev_packet; /* Previous stream packet beginning */
195 uint8_t* next_packet; /* Next stream packet beginning */
Dave Chapman465820d2007-03-25 18:05:14 +0000196
Michael Sevakis6689cb02007-04-10 14:18:30 +0000197 size_t guard_bytes; /* Number of bytes in guardbuf used */
198 size_t buffer_remaining; /* How much data is left in the buffer */
199 uint32_t curr_pts; /* Current presentation timestamp */
200 uint32_t curr_time; /* Current time in samples */
201 uint32_t tagged; /* curr_pts is valid */
202
203 int id;
Dave Chapman4b801b22007-01-01 12:59:32 +0000204} Stream;
205
Dave Chapman83108482007-03-22 09:18:46 +0000206static Stream audio_str IBSS_ATTR;
207static Stream video_str IBSS_ATTR;
Dave Chapman4b801b22007-01-01 12:59:32 +0000208
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000209/* Messages */
210enum
211{
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000212 STREAM_PLAY,
213 STREAM_PAUSE,
Michael Sevakis930278b2007-07-20 03:56:59 +0000214 STREAM_QUIT
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000215};
216
217/* Status */
218enum
219{
220 STREAM_ERROR = -4,
221 STREAM_STOPPED = -3,
222 STREAM_TERMINATED = -2,
223 STREAM_DONE = -1,
224 STREAM_PLAYING = 0,
225 STREAM_PAUSED,
226 STREAM_BUFFERING
227};
228
229/* Returns true if a message is waiting */
230static inline bool str_have_msg(Stream *str)
231{
232 return str->have_msg != 0;
233}
234
235/* Waits until a message is sent */
236static void str_wait_msg(Stream *str)
237{
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000238 int spin_count = 0;
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000239
240 while (str->have_msg == 0)
241 {
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000242 if (spin_count < 100)
243 {
244 rb->yield();
245 spin_count++;
246 continue;
247 }
248
249 rb->sleep(0);
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000250 }
251}
252
253/* Returns a message waiting or blocks until one is available - removes the
254 event */
Michael Sevakis930278b2007-07-20 03:56:59 +0000255static void str_get_msg(Stream *str, struct event *ev)
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000256{
257 str_wait_msg(str);
258 ev->id = str->ev.id;
259 ev->data = str->ev.data;
260 str->have_msg = 0;
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000261}
262
263/* Peeks at the current message without blocking, returns the data but
264 does not remove the event */
265static bool str_look_msg(Stream *str, struct event *ev)
266{
267 if (!str_have_msg(str))
268 return false;
269
270 ev->id = str->ev.id;
271 ev->data = str->ev.data;
272 return true;
273}
274
275/* Replies to the last message pulled - has no effect if last message has not
276 been pulled or already replied */
277static void str_reply_msg(Stream *str, int reply)
278{
279 if (str->replied == 1 || str->have_msg != 0)
280 return;
281
282 str->reply = reply;
283 str->replied = 1;
284}
285
286/* Sends a message to a stream and waits for a reply */
287static intptr_t str_send_msg(Stream *str, int id, intptr_t data)
288{
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000289 int spin_count = 0;
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000290 intptr_t reply;
291
292#if 0
293 if (str->thread == rb->thread_get_current())
294 return str->dispatch_fn(str, msg);
295#endif
296
297 /* Only one thread at a time, please */
298 rb->spinlock_lock(&str->msg_lock);
299
300 str->ev.id = id;
301 str->ev.data = data;
302 str->reply = 0;
303 str->replied = 0;
304 str->have_msg = 1;
305
306 while (str->replied == 0 && str->status != STREAM_TERMINATED)
307 {
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000308 if (spin_count < 100)
309 {
310 rb->yield();
311 spin_count++;
312 continue;
313 }
314
315 rb->sleep(0);
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000316 }
317
318 reply = str->reply;
319
320 rb->spinlock_unlock(&str->msg_lock);
321
322 return reply;
323}
324
Dave Chapman83108482007-03-22 09:18:46 +0000325/* NOTE: Putting the following variables in IRAM cause audio corruption
326 on the ipod (reason unknown)
327*/
Michael Sevakis9bfa2372007-04-14 02:46:15 +0000328static uint8_t *disk_buf IBSS_ATTR;
329static uint8_t *disk_buf_end IBSS_ATTR;
Dave Chapman465820d2007-03-25 18:05:14 +0000330static uint8_t *disk_buf_tail IBSS_ATTR;
Michael Sevakis9bfa2372007-04-14 02:46:15 +0000331static size_t buffer_size IBSS_ATTR;
332#if NUM_CORES > 1
333/* Some stream variables are shared between cores */
334struct mutex stream_lock IBSS_ATTR;
335static inline void init_stream_lock(void)
336 { rb->spinlock_init(&stream_lock); }
337static inline void lock_stream(void)
338 { rb->spinlock_lock(&stream_lock); }
339static inline void unlock_stream(void)
340 { rb->spinlock_unlock(&stream_lock); }
341#else
342/* No RMW issue here */
343static inline void init_stream_lock(void)
344 { }
345static inline void lock_stream(void)
346 { }
347static inline void unlock_stream(void)
348 { }
349#endif
Dave Chapman4b801b22007-01-01 12:59:32 +0000350
351/* Events */
352static struct event_queue msg_queue IBSS_ATTR;
353
354#define MSG_BUFFER_NEARLY_EMPTY 1
355#define MSG_EXIT_REQUESTED 2
356
Dave Chapman4b801b22007-01-01 12:59:32 +0000357/* Various buffers */
358/* TODO: Can we reduce the PCM buffer size? */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000359#define PCMBUFFER_SIZE ((512*1024)-PCMBUFFER_GUARD_SIZE)
360#define PCMBUFFER_GUARD_SIZE (1152*4 + sizeof (struct pcm_frame_header))
Michael Sevakis8b9df972007-04-12 11:36:12 +0000361#define MPA_MAX_FRAME_SIZE 1729 /* Largest frame - MPEG1, Layer II, 384kbps, 32kHz, pad */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000362#define MPABUF_SIZE (64*1024 + ALIGN_UP(MPA_MAX_FRAME_SIZE + 2*MAD_BUFFER_GUARD, 4))
363#define LIBMPEG2BUFFER_SIZE (2*1024*1024)
Dave Chapman4b801b22007-01-01 12:59:32 +0000364
Michael Sevakis6689cb02007-04-10 14:18:30 +0000365/* 65536+6 is required since each PES has a 6 byte header with a 16 bit packet length field */
Michael Sevakis8b9df972007-04-12 11:36:12 +0000366#define MPEG_GUARDBUF_SIZE (64*1024+1024) /* Keep a bit extra - excessive for now */
Dave Chapman465820d2007-03-25 18:05:14 +0000367#define MPEG_LOW_WATERMARK (1024*1024)
368
Michael Sevakis6689cb02007-04-10 14:18:30 +0000369static void pcm_playback_play_pause(bool play);
370
Dave Chapman4b801b22007-01-01 12:59:32 +0000371/* libmad related functions/definitions */
372#define INPUT_CHUNK_SIZE 8192
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000373
Dave Chapman4b801b22007-01-01 12:59:32 +0000374struct mad_stream stream IBSS_ATTR;
375struct mad_frame frame IBSS_ATTR;
376struct mad_synth synth IBSS_ATTR;
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000377
Dave Chapman4b801b22007-01-01 12:59:32 +0000378unsigned char mad_main_data[MAD_BUFFER_MDLEN]; /* 2567 bytes */
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000379
Dave Chapmanb97c00d2007-07-23 23:01:47 +0000380/* There isn't enough room for this in IRAM on PortalPlayer, but there
381 is for Coldfire. */
382
383#ifdef CPU_COLDFIRE
384static mad_fixed_t mad_frame_overlap[2][32][18] IBSS_ATTR; /* 4608 bytes */
385#else
386static mad_fixed_t mad_frame_overlap[2][32][18]; /* 4608 bytes */
387#endif
388
Dave Chapman4b801b22007-01-01 12:59:32 +0000389static void init_mad(void* mad_frame_overlap)
390{
391 rb->memset(&stream, 0, sizeof(struct mad_stream));
392 rb->memset(&frame, 0, sizeof(struct mad_frame));
393 rb->memset(&synth, 0, sizeof(struct mad_synth));
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000394
Dave Chapman4b801b22007-01-01 12:59:32 +0000395 mad_stream_init(&stream);
396 mad_frame_init(&frame);
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000397
Dave Chapman4b801b22007-01-01 12:59:32 +0000398 /* We do this so libmad doesn't try to call codec_calloc() */
399 frame.overlap = mad_frame_overlap;
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000400
Dave Chapman4b801b22007-01-01 12:59:32 +0000401 rb->memset(mad_main_data, 0, sizeof(mad_main_data));
402 stream.main_data = &mad_main_data;
403}
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000404
Dave Chapman4b801b22007-01-01 12:59:32 +0000405/* MPEG related headers */
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000406
Michael Sevakis6689cb02007-04-10 14:18:30 +0000407/* Macros for comparing memory bytes to a series of constant bytes in an
408 efficient manner - evaluate to true if corresponding bytes match */
409#if defined (CPU_ARM)
410/* ARM must load 32-bit values at addres % 4 == 0 offsets but this data
411 isn't aligned nescessarily, so just byte compare */
412#define CMP_3_CONST(_a, _b) \
413 ({ \
414 int _x; \
415 asm volatile ( \
416 "ldrb %[x], [%[a], #0] \r\n" \
417 "eors %[x], %[x], %[b0] \r\n" \
418 "ldreqb %[x], [%[a], #1] \r\n" \
419 "eoreqs %[x], %[x], %[b1] \r\n" \
420 "ldreqb %[x], [%[a], #2] \r\n" \
421 "eoreqs %[x], %[x], %[b2] \r\n" \
422 : [x]"=&r"(_x) \
423 : [a]"r"(_a), \
424 [b0]"i"((_b) >> 24), \
425 [b1]"i"((_b) << 8 >> 24), \
426 [b2]"i"((_b) << 16 >> 24) \
427 ); \
428 _x == 0; \
429 })
430#define CMP_4_CONST(_a, _b) \
431 ({ \
432 int _x; \
433 asm volatile ( \
434 "ldrb %[x], [%[a], #0] \r\n" \
435 "eors %[x], %[x], %[b0] \r\n" \
436 "ldreqb %[x], [%[a], #1] \r\n" \
437 "eoreqs %[x], %[x], %[b1] \r\n" \
438 "ldreqb %[x], [%[a], #2] \r\n" \
439 "eoreqs %[x], %[x], %[b2] \r\n" \
440 "ldreqb %[x], [%[a], #3] \r\n" \
441 "eoreqs %[x], %[x], %[b3] \r\n" \
442 : [x]"=&r"(_x) \
443 : [a]"r"(_a), \
444 [b0]"i"((_b) >> 24), \
445 [b1]"i"((_b) << 8 >> 24), \
446 [b2]"i"((_b) << 16 >> 24), \
447 [b3]"i"((_b) << 24 >> 24) \
448 ); \
449 _x == 0; \
450 })
451#elif defined (CPU_COLDFIRE)
452/* Coldfire can just load a 32 bit value at any offset but ASM is not the best way
453 to integrate this with the C code */
454#define CMP_3_CONST(a, b) \
455 (((*(uint32_t *)(a) >> 8) ^ ((uint32_t)(b) >> 8)) == 0)
456#define CMP_4_CONST(a, b) \
457 ((*(uint32_t *)(a) ^ (b)) == 0)
458#else
459/* Don't know what this is - use bytewise comparisons */
460#define CMP_3_CONST(a, b) \
Jens Arnold2e305c62007-09-09 22:47:28 +0000461 (( ((a)[0] ^ (((b) >> 24) & 0xff)) | \
462 ((a)[1] ^ (((b) >> 16) & 0xff)) | \
463 ((a)[2] ^ (((b) >> 8) & 0xff)) ) == 0)
Michael Sevakis6689cb02007-04-10 14:18:30 +0000464#define CMP_4_CONST(a, b) \
Jens Arnold2e305c62007-09-09 22:47:28 +0000465 (( ((a)[0] ^ (((b) >> 24) & 0xff)) | \
466 ((a)[1] ^ (((b) >> 16) & 0xff)) | \
467 ((a)[2] ^ (((b) >> 8) & 0xff)) | \
468 ((a)[3] ^ ((b) & 0xff)) ) == 0)
Michael Sevakis6689cb02007-04-10 14:18:30 +0000469#endif
470
471/* Codes for various header byte sequences - MSB represents lowest memory
472 address */
473#define PACKET_START_CODE_PREFIX 0x00000100ul
474#define END_CODE 0x000001b9ul
475#define PACK_START_CODE 0x000001baul
476#define SYSTEM_HEADER_START_CODE 0x000001bbul
477
478/* p = base pointer, b0 - b4 = byte offsets from p */
Michael Sevakiseb4dcd82007-04-16 03:34:56 +0000479/* We only care about the MS 32 bits of the 33 and so the ticks are 45kHz */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000480#define TS_FROM_HEADER(p, b0, b1, b2, b3, b4) \
Michael Sevakiseb4dcd82007-04-16 03:34:56 +0000481 ((uint32_t)(((p)[b0] >> 1 << 29) | \
482 ((p)[b1] << 21) | \
483 ((p)[b2] >> 1 << 14) | \
484 ((p)[b3] << 6) | \
485 ((p)[b4] >> 2 )))
Michael Sevakis6689cb02007-04-10 14:18:30 +0000486
487/* This function demuxes the streams and gives the next stream data pointer */
Dave Chapman4b801b22007-01-01 12:59:32 +0000488static void get_next_data( Stream* str )
489{
490 uint8_t *p;
491 uint8_t *header;
492 int stream;
Dave Chapman465820d2007-03-25 18:05:14 +0000493
Michael Sevakis6689cb02007-04-10 14:18:30 +0000494 static int mpeg1_skip_table[16] =
495 { 0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
496
497 if (str->curr_packet_end == NULL)
498 {
Dave Chapman83108482007-03-22 09:18:46 +0000499 /* What does this do? */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000500 while ((p = disk_buf) == NULL)
Dave Chapman4b801b22007-01-01 12:59:32 +0000501 {
Dave Chapman83108482007-03-22 09:18:46 +0000502 rb->lcd_putsxy(0,LCD_HEIGHT-10,"FREEZE!");
503 rb->lcd_update();
Michael Sevakis6689cb02007-04-10 14:18:30 +0000504 rb->sleep(HZ);
Dave Chapman4b801b22007-01-01 12:59:32 +0000505 }
Michael Sevakis6689cb02007-04-10 14:18:30 +0000506 }
507 else
508 {
Dave Chapman4b801b22007-01-01 12:59:32 +0000509 p = str->curr_packet_end;
510 }
Dave Chapman465820d2007-03-25 18:05:14 +0000511
Michael Sevakis6689cb02007-04-10 14:18:30 +0000512 while (1)
Dave Chapman4b801b22007-01-01 12:59:32 +0000513 {
514 int length, bytes;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000515
516 if (p >= disk_buf_end)
517 {
518 p = disk_buf + (p - disk_buf_end);
519 }
Dave Chapman465820d2007-03-25 18:05:14 +0000520
Dave Chapman4b801b22007-01-01 12:59:32 +0000521 /* Pack header, skip it */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000522 if (CMP_4_CONST(p, PACK_START_CODE))
Dave Chapman4b801b22007-01-01 12:59:32 +0000523 {
Michael Sevakis6689cb02007-04-10 14:18:30 +0000524 if ((p[4] & 0xc0) == 0x40) /* mpeg-2 */
525 {
Dave Chapman4b801b22007-01-01 12:59:32 +0000526 p += 14 + (p[13] & 7);
Michael Sevakis6689cb02007-04-10 14:18:30 +0000527 }
528 else if ((p[4] & 0xf0) == 0x20) /* mpeg-1 */
529 {
Dave Chapman4b801b22007-01-01 12:59:32 +0000530 p += 12;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000531 }
532 else
533 {
Jens Arnold4d6374c2007-03-16 21:56:08 +0000534 rb->splash( 30, "Weird Pack header!" );
Dave Chapman4b801b22007-01-01 12:59:32 +0000535 p += 5;
536 }
Jens Arnold4d6374c2007-03-16 21:56:08 +0000537 /*rb->splash( 30, "Pack header" );*/
Dave Chapman4b801b22007-01-01 12:59:32 +0000538 }
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000539
Michael Sevakis6689cb02007-04-10 14:18:30 +0000540 /* System header, parse and skip it - four bytes */
541 if (CMP_4_CONST(p, SYSTEM_HEADER_START_CODE))
Dave Chapman4b801b22007-01-01 12:59:32 +0000542 {
543 int header_length;
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000544
Dave Chapman4b801b22007-01-01 12:59:32 +0000545 p += 4; /*skip start code*/
Michael Sevakis6689cb02007-04-10 14:18:30 +0000546 header_length = *p++ << 8;
547 header_length += *p++;
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000548
Dave Chapman4b801b22007-01-01 12:59:32 +0000549 p += header_length;
Michael Sevakis8b9df972007-04-12 11:36:12 +0000550
551 if (p >= disk_buf_end)
552 {
553 p = disk_buf + (p - disk_buf_end);
554 }
Jens Arnold4d6374c2007-03-16 21:56:08 +0000555 /*rb->splash( 30, "System header" );*/
Dave Chapman4b801b22007-01-01 12:59:32 +0000556 }
Michael Sevakis6689cb02007-04-10 14:18:30 +0000557
Dave Chapman4b801b22007-01-01 12:59:32 +0000558 /* Packet header, parse it */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000559 if (!CMP_3_CONST(p, PACKET_START_CODE_PREFIX))
Dave Chapman4b801b22007-01-01 12:59:32 +0000560 {
561 /* Problem */
Jens Arnold4d6374c2007-03-16 21:56:08 +0000562 //rb->splash( HZ*3, "missing packet start code prefix : %X%X at %X", *p, *(p+2), p-disk_buf );
Dave Chapman4b801b22007-01-01 12:59:32 +0000563 str->curr_packet_end = str->curr_packet = NULL;
Michael Sevakis9bfa2372007-04-14 02:46:15 +0000564 break;
Dave Chapman4b801b22007-01-01 12:59:32 +0000565 //++p;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000566 //break;
567 }
568
Dave Chapman4b801b22007-01-01 12:59:32 +0000569 /* We retrieve basic infos */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000570 stream = p[3];
571 length = (p[4] << 8) | p[5];
572
Jens Arnold4d6374c2007-03-16 21:56:08 +0000573 /*rb->splash( 100, "Stream : %X", stream );*/
Dave Chapman4b801b22007-01-01 12:59:32 +0000574 if (stream != str->id)
575 {
576 /* End of stream ? */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000577 if (stream == 0xB9)
Dave Chapman4b801b22007-01-01 12:59:32 +0000578 {
579 str->curr_packet_end = str->curr_packet = NULL;
Michael Sevakis9bfa2372007-04-14 02:46:15 +0000580 break;
Dave Chapman4b801b22007-01-01 12:59:32 +0000581 }
Michael Sevakis6689cb02007-04-10 14:18:30 +0000582
583 /* It's not the packet we're looking for, skip it */
584 p += length + 6;
Dave Chapman4b801b22007-01-01 12:59:32 +0000585 continue;
586 }
Michael Sevakis6689cb02007-04-10 14:18:30 +0000587
Dave Chapman4b801b22007-01-01 12:59:32 +0000588 /* Ok, it's our packet */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000589 str->curr_packet_end = p + length+6;
Dave Chapman4b801b22007-01-01 12:59:32 +0000590 header = p;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000591
592 if ((header[6] & 0xc0) == 0x80) /* mpeg2 */
593 {
Dave Chapman4b801b22007-01-01 12:59:32 +0000594 length = 9 + header[8];
Michael Sevakis6689cb02007-04-10 14:18:30 +0000595
Dave Chapman4b801b22007-01-01 12:59:32 +0000596 /* header points to the mpeg2 pes header */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000597 if (header[7] & 0x80)
598 {
Michael Sevakiseb4dcd82007-04-16 03:34:56 +0000599 /* header has a pts */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000600 uint32_t pts = TS_FROM_HEADER(header, 9, 10, 11, 12, 13);
Dave Chapmanc8e69df2006-08-20 23:12:56 +0000601
Michael Sevakis6689cb02007-04-10 14:18:30 +0000602 if (stream >= 0xe0)
603 {
Michael Sevakiseb4dcd82007-04-16 03:34:56 +0000604 /* video stream - header may have a dts as well */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000605 uint32_t dts = (header[7] & 0x40) == 0 ?
606 pts : TS_FROM_HEADER(header, 14, 15, 16, 17, 18);
Dave Chapman704b7932007-03-26 19:37:48 +0000607
Dave Chapman4b801b22007-01-01 12:59:32 +0000608 mpeg2_tag_picture (mpeg2dec, pts, dts);
Michael Sevakis6689cb02007-04-10 14:18:30 +0000609 }
610 else
611 {
612 str->curr_pts = pts;
613 str->tagged = 1;
614 }
Dave Chapman4b801b22007-01-01 12:59:32 +0000615 }
Michael Sevakis6689cb02007-04-10 14:18:30 +0000616 }
617 else /* mpeg1 */
618 {
Dave Chapman4b801b22007-01-01 12:59:32 +0000619 int len_skip;
620 uint8_t * ptsbuf;
621
622 length = 7;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000623
624 while (header[length - 1] == 0xff)
Dave Chapman4b801b22007-01-01 12:59:32 +0000625 {
626 length++;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000627 if (length > 23)
Dave Chapman4b801b22007-01-01 12:59:32 +0000628 {
Jens Arnold4d6374c2007-03-16 21:56:08 +0000629 rb->splash( 30, "Too much stuffing" );
Dave Chapman465820d2007-03-25 18:05:14 +0000630 DEBUGF("Too much stuffing" );
Dave Chapman4b801b22007-01-01 12:59:32 +0000631 break;
632 }
633 }
Michael Sevakis6689cb02007-04-10 14:18:30 +0000634
635 if ((header[length - 1] & 0xc0) == 0x40)
Dave Chapman4b801b22007-01-01 12:59:32 +0000636 {
637 length += 2;
638 }
Michael Sevakis6689cb02007-04-10 14:18:30 +0000639
Dave Chapman4b801b22007-01-01 12:59:32 +0000640 len_skip = length;
641 length += mpeg1_skip_table[header[length - 1] >> 4];
642
643 /* header points to the mpeg1 pes header */
644 ptsbuf = header + len_skip;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000645
Dave Chapman4b801b22007-01-01 12:59:32 +0000646 if ((ptsbuf[-1] & 0xe0) == 0x20)
647 {
Michael Sevakiseb4dcd82007-04-16 03:34:56 +0000648 /* header has a pts */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000649 uint32_t pts = TS_FROM_HEADER(ptsbuf, -1, 0, 1, 2, 3);
Dave Chapman4b801b22007-01-01 12:59:32 +0000650
Michael Sevakis6689cb02007-04-10 14:18:30 +0000651 if (stream >= 0xe0)
652 {
Michael Sevakiseb4dcd82007-04-16 03:34:56 +0000653 /* video stream - header may have a dts as well */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000654 uint32_t dts = (ptsbuf[-1] & 0xf0) != 0x30 ?
655 pts : TS_FROM_HEADER(ptsbuf, 4, 5, 6, 7, 18);
Dave Chapman16fa5a92007-03-30 00:03:07 +0000656
Dave Chapman4b801b22007-01-01 12:59:32 +0000657 mpeg2_tag_picture (mpeg2dec, pts, dts);
Michael Sevakis6689cb02007-04-10 14:18:30 +0000658 }
659 else
660 {
661 str->curr_pts = pts;
662 str->tagged = 1;
663 }
Dave Chapman4b801b22007-01-01 12:59:32 +0000664 }
665 }
Dave Chapman465820d2007-03-25 18:05:14 +0000666
Dave Chapman4b801b22007-01-01 12:59:32 +0000667 p += length;
668 bytes = 6 + (header[4] << 8) + header[5] - length;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000669
670 if (bytes > 0)
671 {
672 str->curr_packet_end = p + bytes;
Dave Chapman465820d2007-03-25 18:05:14 +0000673 //DEBUGF("prev = %d, curr = %d\n",str->prev_packet,str->curr_packet);
674
Michael Sevakis6689cb02007-04-10 14:18:30 +0000675 if (str->curr_packet != NULL)
676 {
Michael Sevakis9bfa2372007-04-14 02:46:15 +0000677 lock_stream();
678
Michael Sevakis6689cb02007-04-10 14:18:30 +0000679 if (str->curr_packet < str->prev_packet)
680 {
681 str->buffer_remaining -= (disk_buf_end - str->prev_packet) +
682 (str->curr_packet - disk_buf);
Dave Chapman465820d2007-03-25 18:05:14 +0000683 str->buffer_remaining -= str->guard_bytes;
684 str->guard_bytes = 0;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000685 }
686 else
687 {
Dave Chapman465820d2007-03-25 18:05:14 +0000688 str->buffer_remaining -= (str->curr_packet - str->prev_packet);
689 }
690
Michael Sevakis9bfa2372007-04-14 02:46:15 +0000691 unlock_stream();
692
Dave Chapman465820d2007-03-25 18:05:14 +0000693 str->prev_packet = str->curr_packet;
694 }
695
Dave Chapman4b801b22007-01-01 12:59:32 +0000696 str->curr_packet = p;
Dave Chapman465820d2007-03-25 18:05:14 +0000697
Michael Sevakis6689cb02007-04-10 14:18:30 +0000698 if (str->curr_packet_end > disk_buf_end)
Dave Chapman465820d2007-03-25 18:05:14 +0000699 {
Michael Sevakis6689cb02007-04-10 14:18:30 +0000700 str->guard_bytes = str->curr_packet_end - disk_buf_end;
701 rb->memcpy(disk_buf_end, disk_buf, str->guard_bytes);
Dave Chapman465820d2007-03-25 18:05:14 +0000702 }
Dave Chapman4b801b22007-01-01 12:59:32 +0000703 }
Michael Sevakis6689cb02007-04-10 14:18:30 +0000704
Dave Chapman4b801b22007-01-01 12:59:32 +0000705 break;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000706 } /* end while */
Dave Chapman4b801b22007-01-01 12:59:32 +0000707}
708
Michael Sevakis6689cb02007-04-10 14:18:30 +0000709/* Our clock rate in ticks/second - this won't be a constant for long */
710#define CLOCK_RATE 44100
711
712/* For simple lowpass filtering of sync variables */
713#define AVERAGE(var, x, count) (((var) * (count-1) + (x)) / (count))
Michael Sevakiseb4dcd82007-04-16 03:34:56 +0000714/* Convert 45kHz PTS/DTS ticks to our clock ticks */
715#define TS_TO_TICKS(pts) ((uint64_t)CLOCK_RATE*(pts) / 45000)
Michael Sevakis6689cb02007-04-10 14:18:30 +0000716/* Convert 27MHz ticks to our clock ticks */
717#define TIME_TO_TICKS(stamp) ((uint64_t)CLOCK_RATE*(stamp) / 27000000)
718
719/** MPEG audio stream buffer */
Dave Chapman4b801b22007-01-01 12:59:32 +0000720uint8_t* mpa_buffer;
Dave Chapman4b801b22007-01-01 12:59:32 +0000721
Michael Sevakis6689cb02007-04-10 14:18:30 +0000722static bool init_mpabuf(void)
Dave Chapman4b801b22007-01-01 12:59:32 +0000723{
Michael Sevakis6689cb02007-04-10 14:18:30 +0000724 mpa_buffer = mpeg2_malloc(MPABUF_SIZE,-2);
725 return mpa_buffer != NULL;
726}
727
Michael Sevakiseb4dcd82007-04-16 03:34:56 +0000728#define PTS_QUEUE_LEN (1 << 5) /* 32 should be way more than sufficient -
Michael Sevakis6689cb02007-04-10 14:18:30 +0000729 if not, the case is handled */
730#define PTS_QUEUE_MASK (PTS_QUEUE_LEN-1)
731struct pts_queue_slot
732{
733 uint32_t pts; /* Time stamp for packet */
734 ssize_t size; /* Number of bytes left in packet */
Michael Sevakiseb4dcd82007-04-16 03:34:56 +0000735} pts_queue[PTS_QUEUE_LEN];
Michael Sevakis6689cb02007-04-10 14:18:30 +0000736
737 /* This starts out wr == rd but will never be emptied to zero during
738 streaming again in order to support initializing the first packet's
739 pts value without a special case */
740static unsigned pts_queue_rd;
741static unsigned pts_queue_wr;
742
Michael Sevakis6689cb02007-04-10 14:18:30 +0000743/* Increments the queue head postion - should be used to preincrement */
744static bool pts_queue_add_head(void)
745{
746 if (pts_queue_wr - pts_queue_rd >= PTS_QUEUE_LEN-1)
747 return false;
748
749 pts_queue_wr++;
750 return true;
751}
752
753/* Increments the queue tail position - leaves one slot as current */
754static bool pts_queue_remove_tail(void)
755{
756 if (pts_queue_wr - pts_queue_rd <= 1u)
757 return false;
758
759 pts_queue_rd++;
760 return true;
761}
762
763/* Returns the "head" at the index just behind the write index */
764static struct pts_queue_slot * pts_queue_head(void)
765{
766 return &pts_queue[(pts_queue_wr - 1) & PTS_QUEUE_MASK];
767}
768
769/* Returns a pointer to the current tail */
770static struct pts_queue_slot * pts_queue_tail(void)
771{
772 return &pts_queue[pts_queue_rd & PTS_QUEUE_MASK];
773}
774
Michael Sevakiseb4dcd82007-04-16 03:34:56 +0000775/* Resets the pts queue - call when starting and seeking */
776static void pts_queue_reset(void)
777{
778 struct pts_queue_slot *pts;
779 pts_queue_rd = pts_queue_wr;
780 pts = pts_queue_tail();
781 pts->pts = 0;
782 pts->size = 0;
783}
784
Michael Sevakis6689cb02007-04-10 14:18:30 +0000785struct pcm_frame_header /* Header added to pcm data every time a decoded
786 mpa frame is sent out */
787{
788 uint32_t size; /* size of this frame - including header */
789 uint32_t time; /* timestamp for this frame - derived from PTS */
790 unsigned char data[]; /* open array of audio data */
791};
792
793#define PCMBUF_PLAY_ALL 1l /* Forces buffer to play back all data */
794#define PCMBUF_PLAY_NONE LONG_MAX /* Keeps buffer from playing any data */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000795static volatile uint64_t pcmbuf_read IBSS_ATTR;
796static volatile uint64_t pcmbuf_written IBSS_ATTR;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000797static volatile ssize_t pcmbuf_threshold IBSS_ATTR;
798static struct pcm_frame_header *pcm_buffer IBSS_ATTR;
799static struct pcm_frame_header *pcmbuf_end IBSS_ATTR;
800static struct pcm_frame_header * volatile pcmbuf_head IBSS_ATTR;
801static struct pcm_frame_header * volatile pcmbuf_tail IBSS_ATTR;
802
803static volatile uint32_t samplesplayed IBSS_ATTR; /* Our base clock */
Michael Sevakis4bd827b2007-04-12 06:02:47 +0000804static volatile uint32_t samplestart IBSS_ATTR; /* Clock at playback start */
Michael Sevakis6689cb02007-04-10 14:18:30 +0000805static volatile int32_t sampleadjust IBSS_ATTR; /* Clock drift adjustment */
806
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000807static ssize_t pcmbuf_used(void)
808{
809 return (ssize_t)(pcmbuf_written - pcmbuf_read);
810}
811
Michael Sevakis6689cb02007-04-10 14:18:30 +0000812static bool init_pcmbuf(void)
813{
814 pcm_buffer = mpeg2_malloc(PCMBUFFER_SIZE + PCMBUFFER_GUARD_SIZE, -2);
815
816 if (pcm_buffer == NULL)
817 return false;
818
Dave Chapman4b801b22007-01-01 12:59:32 +0000819 pcmbuf_head = pcm_buffer;
Dave Chapman4b801b22007-01-01 12:59:32 +0000820 pcmbuf_tail = pcm_buffer;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000821 pcmbuf_end = SKIPBYTES(pcm_buffer, PCMBUFFER_SIZE);
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000822 pcmbuf_read = 0;
823 pcmbuf_written = 0;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000824
825 return true;
826}
827
828/* Advance a PCM buffer pointer by size bytes circularly */
829static inline void pcm_advance_buffer(struct pcm_frame_header * volatile *p,
830 size_t size)
831{
832 *p = SKIPBYTES(*p, size);
833 if (*p >= pcmbuf_end)
834 *p = pcm_buffer;
Dave Chapman4b801b22007-01-01 12:59:32 +0000835}
836
837static void get_more(unsigned char** start, size_t* size)
838{
Michael Sevakis6689cb02007-04-10 14:18:30 +0000839 /* 25ms @ 44.1kHz */
840 static unsigned char silence[4412] __attribute__((aligned (4))) = { 0 };
841 size_t sz;
Dave Chapman83108482007-03-22 09:18:46 +0000842
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000843 if (pcmbuf_used() >= pcmbuf_threshold)
Michael Sevakis6689cb02007-04-10 14:18:30 +0000844 {
845 uint32_t time = pcmbuf_tail->time;
846 sz = pcmbuf_tail->size;
847
848 *start = (unsigned char *)pcmbuf_tail->data;
849
850 pcm_advance_buffer(&pcmbuf_tail, sz);
851
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000852 pcmbuf_read += sz;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000853
854 sz -= sizeof (*pcmbuf_tail);
855
856 *size = sz;
857
858 /* Drift the clock towards the audio timestamp values */
859 sampleadjust = AVERAGE(sampleadjust, (int32_t)(time - samplesplayed), 8);
860
861 /* Update master clock */
862 samplesplayed += sz >> 2;
863 return;
864 }
865
866 /* Keep clock going at all times */
867 sz = sizeof (silence);
868 *start = silence;
869 *size = sz;
870
871 samplesplayed += sz >> 2;
872
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000873 if (pcmbuf_read > pcmbuf_written)
874 pcmbuf_read = pcmbuf_written;
Dave Chapman4b801b22007-01-01 12:59:32 +0000875}
876
Michael Sevakis6689cb02007-04-10 14:18:30 +0000877/* Flushes the buffer - clock keeps counting */
878static void pcm_playback_flush(void)
879{
880 bool was_playing = rb->pcm_is_playing();
Dave Chapman4b801b22007-01-01 12:59:32 +0000881
Michael Sevakis6689cb02007-04-10 14:18:30 +0000882 if (was_playing)
883 rb->pcm_play_stop();
884
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000885 pcmbuf_read = 0;
886 pcmbuf_written = 0;
Michael Sevakis6689cb02007-04-10 14:18:30 +0000887 pcmbuf_head = pcmbuf_tail;
888
889 if (was_playing)
890 rb->pcm_play_data(get_more, NULL, 0);
891}
892
893/* Seek the reference clock to the specified time - next audio data ready to
894 go to DMA should be on the buffer with the same time index or else the PCM
895 buffer should be empty */
896static void pcm_playback_seek_time(uint32_t time)
897{
898 bool was_playing = rb->pcm_is_playing();
899
900 if (was_playing)
901 rb->pcm_play_stop();
902
903 samplesplayed = time;
904 samplestart = time;
905 sampleadjust = 0;
906
907 if (was_playing)
908 rb->pcm_play_data(get_more, NULL, 0);
909}
910
911/* Start pcm playback with the reference clock set to the specified time */
912static void pcm_playback_play(uint32_t time)
913{
914 pcm_playback_seek_time(time);
915
916 if (!rb->pcm_is_playing())
917 rb->pcm_play_data(get_more, NULL, 0);
918}
919
920/* Pauses playback - and the clock */
921static void pcm_playback_play_pause(bool play)
922{
923 rb->pcm_play_pause(play);
924}
925
926/* Stops all playback and resets the clock */
927static void pcm_playback_stop(void)
928{
929 if (rb->pcm_is_playing())
930 rb->pcm_play_stop();
931
932 pcm_playback_flush();
933
934 sampleadjust =
935 samplestart =
936 samplesplayed = 0;
937}
938
939static uint32_t get_stream_time(void)
940{
941 return samplesplayed + sampleadjust - (rb->pcm_get_bytes_waiting() >> 2);
942}
943
944static uint32_t get_playback_time(void)
945{
946 return samplesplayed + sampleadjust -
947 samplestart - (rb->pcm_get_bytes_waiting() >> 2);
948}
949
950static inline int32_t clip_sample(int32_t sample)
951{
952 if ((int16_t)sample != sample)
953 sample = 0x7fff ^ (sample >> 31);
954
955 return sample;
956}
957
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000958static int button_loop(void)
Marcoen Hirschberg95d41452007-06-19 21:29:34 +0000959{
960 bool result;
961 int vol, minvol, maxvol;
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000962 int button;
963
964 if (str_have_msg(&audio_str))
965 {
966 struct event ev;
967 str_get_msg(&audio_str, &ev);
968
Michael Sevakis930278b2007-07-20 03:56:59 +0000969 if (ev.id == STREAM_QUIT)
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000970 {
971 audio_str.status = STREAM_STOPPED;
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +0000972 goto quit;
973 }
974 else
975 {
976 str_reply_msg(&audio_str, 0);
977 }
978 }
979
980 button = rb->button_get(false);
Marcoen Hirschberg95d41452007-06-19 21:29:34 +0000981
982 switch (button)
983 {
984 case MPEG_VOLUP:
985 case MPEG_VOLUP|BUTTON_REPEAT:
986#ifdef MPEG_VOLUP2
987 case MPEG_VOLUP2:
988 case MPEG_VOLUP2|BUTTON_REPEAT:
989#endif
990 vol = rb->global_settings->volume;
991 maxvol = rb->sound_max(SOUND_VOLUME);
992
993 if (vol < maxvol) {
994 vol++;
995 rb->sound_set(SOUND_VOLUME, vol);
996 rb->global_settings->volume = vol;
997 }
998 break;
999
1000 case MPEG_VOLDOWN:
1001 case MPEG_VOLDOWN|BUTTON_REPEAT:
1002#ifdef MPEG_VOLDOWN2
1003 case MPEG_VOLDOWN2:
1004 case MPEG_VOLDOWN2|BUTTON_REPEAT:
1005#endif
1006 vol = rb->global_settings->volume;
1007 minvol = rb->sound_min(SOUND_VOLUME);
1008
1009 if (vol > minvol) {
1010 vol--;
1011 rb->sound_set(SOUND_VOLUME, vol);
1012 rb->global_settings->volume = vol;
1013 }
1014 break;
1015
1016 case MPEG_MENU:
1017 pcm_playback_play_pause(false);
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001018 audio_str.status = STREAM_PAUSED;
1019 str_send_msg(&video_str, STREAM_PAUSE, 0);
Marcoen Hirschberg95d41452007-06-19 21:29:34 +00001020#ifndef HAVE_LCD_COLOR
1021 gray_show(false);
1022#endif
1023 result = mpeg_menu();
Marcoen Hirschberg3585ee72007-06-19 21:30:45 +00001024 count_start = get_playback_time();
1025 num_drawn = 0;
Marcoen Hirschberg95d41452007-06-19 21:29:34 +00001026
1027#ifndef HAVE_LCD_COLOR
1028 gray_show(true);
1029#endif
1030
1031 /* The menu can change the font, so restore */
1032 rb->lcd_setfont(FONT_SYSFIXED);
1033
1034 if (result) {
Michael Sevakis930278b2007-07-20 03:56:59 +00001035 str_send_msg(&video_str, STREAM_QUIT, 0);
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001036 audio_str.status = STREAM_STOPPED;
Marcoen Hirschberg95d41452007-06-19 21:29:34 +00001037 } else {
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001038 audio_str.status = STREAM_PLAYING;
1039 str_send_msg(&video_str, STREAM_PLAY, 0);
Marcoen Hirschberg95d41452007-06-19 21:29:34 +00001040 pcm_playback_play_pause(true);
1041 }
1042 break;
1043
1044 case MPEG_STOP:
Michael Sevakis930278b2007-07-20 03:56:59 +00001045 str_send_msg(&video_str, STREAM_QUIT, 0);
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001046 audio_str.status = STREAM_STOPPED;
Marcoen Hirschberg95d41452007-06-19 21:29:34 +00001047 break;
1048
1049 case MPEG_PAUSE:
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001050 str_send_msg(&video_str, STREAM_PAUSE, 0);
1051 audio_str.status = STREAM_PAUSED;
Marcoen Hirschberg95d41452007-06-19 21:29:34 +00001052 pcm_playback_play_pause(false);
1053
1054 button = BUTTON_NONE;
1055#ifdef HAVE_ADJUSTABLE_CPU_FREQ
1056 rb->cpu_boost(false);
1057#endif
1058 do {
1059 button = rb->button_get(true);
1060 if (button == MPEG_STOP) {
Michael Sevakis930278b2007-07-20 03:56:59 +00001061 str_send_msg(&video_str, STREAM_QUIT, 0);
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001062 audio_str.status = STREAM_STOPPED;
1063 goto quit;
Marcoen Hirschberg95d41452007-06-19 21:29:34 +00001064 }
1065 } while (button != MPEG_PAUSE);
1066
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001067 str_send_msg(&video_str, STREAM_PLAY, 0);
1068 audio_str.status = STREAM_PLAYING;
Marcoen Hirschberg95d41452007-06-19 21:29:34 +00001069 pcm_playback_play_pause(true);
1070#ifdef HAVE_ADJUSTABLE_CPU_FREQ
1071 rb->cpu_boost(true);
1072#endif
1073 break;
1074
1075 default:
1076 if(rb->default_event_handler(button) == SYS_USB_CONNECTED) {
Michael Sevakis930278b2007-07-20 03:56:59 +00001077 str_send_msg(&video_str, STREAM_QUIT, 0);
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001078 audio_str.status = STREAM_STOPPED;
Marcoen Hirschberg95d41452007-06-19 21:29:34 +00001079 }
1080 }
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001081
1082quit:
1083 return audio_str.status;
Marcoen Hirschberg95d41452007-06-19 21:29:34 +00001084}
1085
Dave Chapman83108482007-03-22 09:18:46 +00001086static void audio_thread(void)
Dave Chapman4b801b22007-01-01 12:59:32 +00001087{
Michael Sevakis6689cb02007-04-10 14:18:30 +00001088 uint8_t *mpabuf = mpa_buffer;
1089 ssize_t mpabuf_used = 0;
1090 int mad_errors = 0; /* A count of the errors in each frame */
1091 struct pts_queue_slot *pts;
Dave Chapman4b801b22007-01-01 12:59:32 +00001092
Dave Chapman53952462007-01-02 13:36:17 +00001093 /* We need this here to init the EMAC for Coldfire targets */
1094 mad_synth_init(&synth);
1095
Michael Sevakis6689cb02007-04-10 14:18:30 +00001096 /* Init pts queue */
1097 pts_queue_reset();
1098 pts = pts_queue_tail();
1099
1100 /* Keep buffer from playing */
1101 pcmbuf_threshold = PCMBUF_PLAY_NONE;
1102
1103 /* Start clock */
1104 pcm_playback_play(0);
1105
1106 /* Get first packet */
1107 get_next_data(&audio_str);
1108
1109 if (audio_str.curr_packet == NULL)
1110 goto done;
Dave Chapman4b801b22007-01-01 12:59:32 +00001111
1112 /* This is the decoding loop. */
Michael Sevakis6689cb02007-04-10 14:18:30 +00001113 while (1)
1114 {
1115 int mad_stat;
1116 size_t len;
1117
Michael Sevakis930278b2007-07-20 03:56:59 +00001118 if (button_loop() == STREAM_STOPPED)
1119 goto audio_thread_quit;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001120
Michael Sevakiseb4dcd82007-04-16 03:34:56 +00001121 if (pts->size <= 0)
1122 {
1123 /* Carry any overshoot to the next size since we're technically
1124 -pts->size bytes into it already. If size is negative an audio
1125 frame was split accross packets. Old has to be saved before
1126 moving the tail. */
1127 if (pts_queue_remove_tail())
1128 {
1129 struct pts_queue_slot *old = pts;
1130 pts = pts_queue_tail();
1131 pts->size += old->size;
1132 old->size = 0;
1133 }
1134 }
1135
Michael Sevakis6689cb02007-04-10 14:18:30 +00001136 /** Buffering **/
1137 if (mpabuf_used >= MPA_MAX_FRAME_SIZE + MAD_BUFFER_GUARD)
1138 {
1139 /* Above low watermark - do nothing */
Dave Chapman4b801b22007-01-01 12:59:32 +00001140 }
Michael Sevakis6689cb02007-04-10 14:18:30 +00001141 else if (audio_str.curr_packet != NULL)
1142 {
Michael Sevakiseb4dcd82007-04-16 03:34:56 +00001143 do
Michael Sevakis6689cb02007-04-10 14:18:30 +00001144 {
Michael Sevakiseb4dcd82007-04-16 03:34:56 +00001145 /* Get data from next audio packet */
1146 len = audio_str.curr_packet_end - audio_str.curr_packet;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001147
Michael Sevakiseb4dcd82007-04-16 03:34:56 +00001148 if (audio_str.tagged)
Michael Sevakis6689cb02007-04-10 14:18:30 +00001149 {
Michael Sevakiseb4dcd82007-04-16 03:34:56 +00001150 struct pts_queue_slot *stamp = pts;
1151
1152 if (pts_queue_add_head())
1153 {
1154 stamp = pts_queue_head();
1155 stamp->pts = TS_TO_TICKS(audio_str.curr_pts);
1156 /* pts->size should have been zeroed when slot was
1157 freed */
1158 }
1159 /* else queue full - just count up from the last to make
1160 it look like more data in the same packet */
1161 stamp->size += len;
1162 audio_str.tagged = 0;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001163 }
Michael Sevakiseb4dcd82007-04-16 03:34:56 +00001164 else
1165 {
1166 /* Add to the one just behind the head - this may be the
1167 tail or the previouly added head - whether or not we'll
1168 ever reach this is quite in question since audio always
1169 seems to have every packet timestamped */
1170 pts_queue_head()->size += len;
1171 }
1172
1173 /* Slide any remainder over to beginning - avoid function
1174 call overhead if no data remaining as well */
1175 if (mpabuf > mpa_buffer && mpabuf_used > 0)
1176 rb->memmove(mpa_buffer, mpabuf, mpabuf_used);
1177
1178 /* Splice this packet onto any remainder */
1179 rb->memcpy(mpa_buffer + mpabuf_used, audio_str.curr_packet,
1180 len);
1181
1182 mpabuf_used += len;
1183 mpabuf = mpa_buffer;
1184
1185 /* Get data from next audio packet */
1186 get_next_data(&audio_str);
Dave Chapman4b801b22007-01-01 12:59:32 +00001187 }
Michael Sevakiseb4dcd82007-04-16 03:34:56 +00001188 while (audio_str.curr_packet != NULL &&
1189 mpabuf_used < MPA_MAX_FRAME_SIZE + MAD_BUFFER_GUARD);
Michael Sevakis6689cb02007-04-10 14:18:30 +00001190 }
1191 else if (mpabuf_used <= 0)
1192 {
1193 /* Used up remainder of mpa buffer so quit */
Dave Chapman4b801b22007-01-01 12:59:32 +00001194 break;
1195 }
1196
Michael Sevakis6689cb02007-04-10 14:18:30 +00001197 /** Decoding **/
Michael Sevakis8b9df972007-04-12 11:36:12 +00001198 mad_stream_buffer(&stream, mpabuf, mpabuf_used);
Dave Chapman4b801b22007-01-01 12:59:32 +00001199
Michael Sevakis6689cb02007-04-10 14:18:30 +00001200 mad_stat = mad_frame_decode(&frame, &stream);
1201
Michael Sevakiseb4dcd82007-04-16 03:34:56 +00001202 if (stream.next_frame == NULL)
1203 {
1204 /* What to do here? (This really is fatal) */
1205 DEBUGF("/* What to do here? */\n");
1206 break;
1207 }
1208
Michael Sevakis6689cb02007-04-10 14:18:30 +00001209 /* Next mad stream buffer is the next frame postion */
1210 mpabuf = (uint8_t *)stream.next_frame;
1211
1212 /* Adjust sizes by the frame size */
1213 len = stream.next_frame - stream.this_frame;
1214 mpabuf_used -= len;
1215 pts->size -= len;
1216
Michael Sevakis6689cb02007-04-10 14:18:30 +00001217 if (mad_stat != 0)
1218 {
1219 DEBUGF("Audio stream error - %d\n", stream.error);
1220
1221 if (stream.error == MAD_FLAG_INCOMPLETE
1222 || stream.error == MAD_ERROR_BUFLEN)
1223 {
1224 /* This makes the codec support partially corrupted files */
Michael Sevakis8b9df972007-04-12 11:36:12 +00001225 if (++mad_errors > 30)
Michael Sevakis6689cb02007-04-10 14:18:30 +00001226 break;
1227
1228 stream.error = 0;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001229 rb->priority_yield();
1230 continue;
1231 }
1232 else if (MAD_RECOVERABLE(stream.error))
1233 {
Michael Sevakis8b9df972007-04-12 11:36:12 +00001234 stream.error = 0;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001235 rb->priority_yield();
1236 continue;
1237 }
1238 else
1239 {
1240 /* Some other unrecoverable error */
1241 DEBUGF("Unrecoverable error\n");
1242 }
1243
1244 break;
1245 }
1246
1247 mad_errors = 0; /* Clear errors */
1248
1249 /* Generate the pcm samples */
Dave Chapman4b801b22007-01-01 12:59:32 +00001250 mad_synth_frame(&synth, &frame);
1251
Michael Sevakis6689cb02007-04-10 14:18:30 +00001252 /** Output **/
Dave Chapman4b801b22007-01-01 12:59:32 +00001253
Michael Sevakis6689cb02007-04-10 14:18:30 +00001254 /* TODO: Output through core dsp. We'll still use our own PCM buffer
1255 since the core pcm buffer has no timestamping or clock facilities */
1256
1257 /* Add a frame of audio to the pcm buffer. Maximum is 1152 samples. */
1258 if (synth.pcm.length > 0)
1259 {
1260 int16_t *audio_data = (int16_t *)pcmbuf_head->data;
1261 size_t size = sizeof (*pcmbuf_head) + synth.pcm.length*4;
1262 size_t wait_for = size + 32*1024;
1263
1264 /* Leave at least 32KB free (this will be the currently
1265 playing chunk) */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001266 while (pcmbuf_used() + wait_for > PCMBUFFER_SIZE)
Michael Sevakis6689cb02007-04-10 14:18:30 +00001267 {
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001268 if (str_have_msg(&audio_str))
1269 {
1270 struct event ev;
1271 str_look_msg(&audio_str, &ev);
1272
Michael Sevakis930278b2007-07-20 03:56:59 +00001273 if (ev.id == STREAM_QUIT)
1274 goto audio_thread_quit;
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001275 }
1276
Michael Sevakis6689cb02007-04-10 14:18:30 +00001277 rb->priority_yield();
1278 }
1279
1280 /* TODO: This part will be replaced with dsp calls soon */
1281 if (MAD_NCHANNELS(&frame.header) == 2)
1282 {
1283 int32_t *left = &synth.pcm.samples[0][0];
1284 int32_t *right = &synth.pcm.samples[1][0];
1285 int i = synth.pcm.length;
1286
1287 do
1288 {
Dave Chapman8b407692007-03-22 22:47:04 +00001289 /* libmad outputs s3.28 */
Michael Sevakis6689cb02007-04-10 14:18:30 +00001290 *audio_data++ = clip_sample(*left++ >> 13);
1291 *audio_data++ = clip_sample(*right++ >> 13);
Dave Chapman4b801b22007-01-01 12:59:32 +00001292 }
Michael Sevakis6689cb02007-04-10 14:18:30 +00001293 while (--i > 0);
Dave Chapman4b801b22007-01-01 12:59:32 +00001294 }
Michael Sevakis6689cb02007-04-10 14:18:30 +00001295 else /* mono */
1296 {
1297 int32_t *mono = &synth.pcm.samples[0][0];
1298 int i = synth.pcm.length;
Dave Chapman4b801b22007-01-01 12:59:32 +00001299
Michael Sevakis6689cb02007-04-10 14:18:30 +00001300 do
1301 {
1302 int32_t s = clip_sample(*mono++ >> 13);
1303 *audio_data++ = s;
1304 *audio_data++ = s;
1305 }
1306 while (--i > 0);
1307 }
1308 /**/
Dave Chapman4b801b22007-01-01 12:59:32 +00001309
Michael Sevakis6689cb02007-04-10 14:18:30 +00001310 pcmbuf_head->time = pts->pts;
1311 pcmbuf_head->size = size;
Dave Chapman4b801b22007-01-01 12:59:32 +00001312
Michael Sevakis6689cb02007-04-10 14:18:30 +00001313 /* As long as we're on this timestamp, the time is just incremented
1314 by the number of samples */
1315 pts->pts += synth.pcm.length;
1316
1317 pcm_advance_buffer(&pcmbuf_head, size);
1318
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001319 if (pcmbuf_threshold != PCMBUF_PLAY_ALL && pcmbuf_used() >= 64*1024)
Michael Sevakis6689cb02007-04-10 14:18:30 +00001320 {
1321 /* We've reached our size treshold so start playing back the
1322 audio in the buffer and set the buffer to play all data */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001323 audio_str.status = STREAM_PLAYING;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001324 pcmbuf_threshold = PCMBUF_PLAY_ALL;
1325 pcm_playback_seek_time(pcmbuf_tail->time);
Dave Chapman4b801b22007-01-01 12:59:32 +00001326 }
Michael Sevakis6689cb02007-04-10 14:18:30 +00001327
1328 /* Make this data available to DMA */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001329 pcmbuf_written += size;
Dave Chapman4b801b22007-01-01 12:59:32 +00001330 }
Michael Sevakis6689cb02007-04-10 14:18:30 +00001331
Dave Chapman4b801b22007-01-01 12:59:32 +00001332 rb->yield();
Michael Sevakis6689cb02007-04-10 14:18:30 +00001333 } /* end decoding loop */
Dave Chapman4b801b22007-01-01 12:59:32 +00001334
1335done:
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001336 if (audio_str.status == STREAM_STOPPED)
Michael Sevakis930278b2007-07-20 03:56:59 +00001337 goto audio_thread_quit;
Dave Chapman4b801b22007-01-01 12:59:32 +00001338
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001339 /* Force any residue to play if audio ended before reaching the
1340 threshold */
1341 if (pcmbuf_threshold != PCMBUF_PLAY_ALL && pcmbuf_used() > 0)
1342 {
1343 pcm_playback_play(pcmbuf_tail->time);
1344 pcmbuf_threshold = PCMBUF_PLAY_ALL;
1345 }
1346
1347 if (rb->pcm_is_playing() && !rb->pcm_is_paused())
1348 {
1349 /* Wait for audio to finish */
1350 while (pcmbuf_used() > 0)
Michael Sevakis4bd827b2007-04-12 06:02:47 +00001351 {
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001352 if (button_loop() == STREAM_STOPPED)
Michael Sevakis930278b2007-07-20 03:56:59 +00001353 goto audio_thread_quit;
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001354 rb->sleep(HZ/10);
Michael Sevakis4bd827b2007-04-12 06:02:47 +00001355 }
Michael Sevakis6689cb02007-04-10 14:18:30 +00001356 }
1357
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001358 audio_str.status = STREAM_DONE;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001359
1360 /* Process events until finished */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001361 while (button_loop() != STREAM_STOPPED)
Dave Chapman83108482007-03-22 09:18:46 +00001362 rb->sleep(HZ/4);
Michael Sevakis6689cb02007-04-10 14:18:30 +00001363
Michael Sevakis930278b2007-07-20 03:56:59 +00001364audio_thread_quit:
Michael Sevakisdfa9f442007-04-11 11:02:45 +00001365 pcm_playback_stop();
Michael Sevakis6689cb02007-04-10 14:18:30 +00001366
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001367 audio_str.status = STREAM_TERMINATED;
Michael Sevakisdfa9f442007-04-11 11:02:45 +00001368 rb->remove_thread(NULL);
Dave Chapman4b801b22007-01-01 12:59:32 +00001369}
1370
1371/* End of libmad stuff */
1372
Dave Chapman4b801b22007-01-01 12:59:32 +00001373/* TODO: Running in the main thread, libmad needs 8.25KB of stack.
1374 The codec thread uses a 9KB stack. So we can probable reduce this a
1375 little, but leave at 9KB for now to be safe. */
1376#define AUDIO_STACKSIZE (9*1024)
1377uint32_t audio_stack[AUDIO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR;
1378
1379/* TODO: Check if 4KB is appropriate - it works for my test streams,
1380 so maybe we can reduce it. */
1381#define VIDEO_STACKSIZE (4*1024)
1382static uint32_t video_stack[VIDEO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR;
1383
Dave Chapman83108482007-03-22 09:18:46 +00001384static void video_thread(void)
Dave Chapmanc9d66562006-08-07 22:11:07 +00001385{
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001386 struct event ev;
Dave Chapmanc9d66562006-08-07 22:11:07 +00001387 const mpeg2_info_t * info;
1388 mpeg2_state_t state;
Dave Chapmanc8e69df2006-08-20 23:12:56 +00001389 char str[80];
Michael Sevakis6689cb02007-04-10 14:18:30 +00001390 uint32_t curr_time = 0;
Michael Sevakiseb4dcd82007-04-16 03:34:56 +00001391 uint32_t period = 0; /* Frame period in clock ticks */
Michael Sevakis6689cb02007-04-10 14:18:30 +00001392 uint32_t eta_audio = UINT_MAX, eta_video = 0;
1393 int32_t eta_early = 0, eta_late = 0;
1394 int frame_drop_level = 0;
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001395 int skip_level = 0;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001396 int num_skipped = 0;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001397 /* Used to decide when to display FPS */
1398 unsigned long last_showfps = *rb->current_tick - HZ;
1399 /* Used to decide whether or not to force a frame update */
1400 unsigned long last_render = last_showfps;
Dave Chapmanc8e69df2006-08-20 23:12:56 +00001401
Michael Sevakis6689cb02007-04-10 14:18:30 +00001402 mpeg2dec = mpeg2_init();
1403 if (mpeg2dec == NULL)
1404 {
Dave Chapman83108482007-03-22 09:18:46 +00001405 rb->splash(0, "mpeg2_init failed");
1406 /* Commit suicide */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001407 video_str.status = STREAM_TERMINATED;
Dave Chapman83108482007-03-22 09:18:46 +00001408 rb->remove_thread(NULL);
Dave Chapmanc8e69df2006-08-20 23:12:56 +00001409 }
Dave Chapmanc9d66562006-08-07 22:11:07 +00001410
Dave Chapman83108482007-03-22 09:18:46 +00001411 /* Clear the display - this is mainly just to indicate that the
1412 video thread has started successfully. */
1413 rb->lcd_clear_display();
1414 rb->lcd_update();
1415
Dave Chapman4b801b22007-01-01 12:59:32 +00001416 /* Request the first packet data */
1417 get_next_data( &video_str );
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001418
1419 if (video_str.curr_packet == NULL)
1420 goto done;
1421
Dave Chapman4b801b22007-01-01 12:59:32 +00001422 mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end);
1423 total_offset += video_str.curr_packet_end - video_str.curr_packet;
Dave Chapmanc9d66562006-08-07 22:11:07 +00001424
1425 info = mpeg2_info (mpeg2dec);
Michael Sevakis6689cb02007-04-10 14:18:30 +00001426
1427 /* Wait if the audio thread is buffering - i.e. before
1428 the first frames are decoded */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001429 while (audio_str.status == STREAM_BUFFERING)
Michael Sevakis6689cb02007-04-10 14:18:30 +00001430 rb->priority_yield();
1431
1432 while (1)
1433 {
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001434 /* quickly check mailbox first */
1435 if (str_have_msg(&video_str))
Michael Sevakis6689cb02007-04-10 14:18:30 +00001436 {
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001437 while (1)
1438 {
1439 str_get_msg(&video_str, &ev);
Michael Sevakis9bfa2372007-04-14 02:46:15 +00001440
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001441 switch (ev.id)
1442 {
Michael Sevakis930278b2007-07-20 03:56:59 +00001443 case STREAM_QUIT:
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001444 video_str.status = STREAM_STOPPED;
Michael Sevakis930278b2007-07-20 03:56:59 +00001445 goto video_thread_quit;
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001446 case STREAM_PAUSE:
1447 flush_icache();
1448 video_str.status = STREAM_PAUSED;
1449 str_reply_msg(&video_str, 1);
1450 continue;
1451 }
Michael Sevakiseb4dcd82007-04-16 03:34:56 +00001452
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001453 break;
1454 }
1455
1456 video_str.status = STREAM_PLAYING;
1457 str_reply_msg(&video_str, 1);
Michael Sevakis6689cb02007-04-10 14:18:30 +00001458 }
1459
Dave Chapmanc9d66562006-08-07 22:11:07 +00001460 state = mpeg2_parse (mpeg2dec);
Dave Chapman4b801b22007-01-01 12:59:32 +00001461 rb->yield();
Dave Chapmanc9d66562006-08-07 22:11:07 +00001462
Linus Nielsen Feltzingfcbc6992007-05-19 17:02:55 +00001463 /* Prevent idle poweroff */
1464 rb->reset_poweroff_timer();
1465
Michael Sevakis6689cb02007-04-10 14:18:30 +00001466 switch (state)
1467 {
Dave Chapmanc9d66562006-08-07 22:11:07 +00001468 case STATE_BUFFER:
Dave Chapman4b801b22007-01-01 12:59:32 +00001469 /* Request next packet data */
1470 get_next_data( &video_str );
1471 mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end);
1472 total_offset += video_str.curr_packet_end - video_str.curr_packet;
1473 info = mpeg2_info (mpeg2dec);
Michael Sevakis6689cb02007-04-10 14:18:30 +00001474
1475 if (video_str.curr_packet == NULL)
1476 {
Dave Chapman4b801b22007-01-01 12:59:32 +00001477 /* No more data. */
1478 goto done;
1479 }
1480 continue;
1481
Dave Chapmanc9d66562006-08-07 22:11:07 +00001482 case STATE_SEQUENCE:
Michael Sevakis6689cb02007-04-10 14:18:30 +00001483 /* New GOP, inform output of any changes */
Marcoen Hirschberg4d9c0012007-04-04 22:51:57 +00001484 vo_setup(info->sequence);
Michael Sevakis6689cb02007-04-10 14:18:30 +00001485 break;
Dave Chapmanc8e69df2006-08-20 23:12:56 +00001486
Dave Chapmanc9d66562006-08-07 22:11:07 +00001487 case STATE_PICTURE:
Michael Sevakis6689cb02007-04-10 14:18:30 +00001488 {
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001489 int skip = 0; /* Assume no skip */
1490
1491 if (frame_drop_level >= 1 || skip_level > 0)
1492 {
1493 /* A frame will be dropped in the decoder */
1494
1495 /* Frame type: I/P/B/D */
1496 int type = info->current_picture->flags & PIC_MASK_CODING_TYPE;
1497
1498 switch (type)
1499 {
1500 case PIC_FLAG_CODING_TYPE_I:
1501 case PIC_FLAG_CODING_TYPE_D:
1502 /* Level 5: Things are extremely late and all frames will be
1503 dropped until the next key frame */
1504 if (frame_drop_level >= 1)
1505 frame_drop_level = 0; /* Key frame - reset drop level */
1506 if (skip_level >= 5)
1507 {
1508 frame_drop_level = 1;
1509 skip_level = 0; /* reset */
1510 }
1511 break;
1512 case PIC_FLAG_CODING_TYPE_P:
1513 /* Level 4: Things are very late and all frames will be
1514 dropped until the next key frame */
1515 if (skip_level >= 4)
1516 {
1517 frame_drop_level = 1;
1518 skip_level = 0; /* reset */
1519 }
1520 break;
1521 case PIC_FLAG_CODING_TYPE_B:
1522 /* We want to drop something, so this B frame won't even
1523 be decoded. Drawing can happen on the next frame if so
1524 desired. Bring the level down as skips are done. */
1525 skip = 1;
1526 if (skip_level > 0)
1527 skip_level--;
1528 }
1529
1530 skip |= frame_drop_level;
1531 }
1532
1533 mpeg2_skip(mpeg2dec, skip);
1534 break;
1535 }
1536
1537 case STATE_SLICE:
1538 case STATE_END:
1539 case STATE_INVALID_END:
1540 {
Michael Sevakis6689cb02007-04-10 14:18:30 +00001541 int32_t offset; /* Tick adjustment to keep sync */
Michael Sevakis6689cb02007-04-10 14:18:30 +00001542
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001543 /* draw current picture */
1544 if (!info->display_fbuf)
1545 break;
1546
1547 /* No limiting => no dropping - draw this frame */
Michael Sevakis6689cb02007-04-10 14:18:30 +00001548 if (!settings.limitfps)
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001549 goto picture_draw;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001550
Michael Sevakis6689cb02007-04-10 14:18:30 +00001551 /* Get presentation times in audio samples - quite accurate
Michael Sevakiseb4dcd82007-04-16 03:34:56 +00001552 enough - add previous frame duration if not stamped */
1553 curr_time = (info->display_picture->flags & PIC_FLAG_TAGS) ?
1554 TS_TO_TICKS(info->display_picture->tag) : (curr_time + period);
1555
1556 period = TIME_TO_TICKS(info->sequence->frame_period);
Michael Sevakis6689cb02007-04-10 14:18:30 +00001557
1558 eta_video = curr_time;
1559 eta_audio = get_stream_time();
1560
1561 /* How early/late are we? > 0 = late, < 0 early */
1562 offset = eta_audio - eta_video;
1563
1564 if (!settings.skipframes)
1565 {
1566 /* Make no effort to determine whether this frame should be
1567 drawn or not since no action can be taken to correct the
1568 situation. We'll just wait if we're early and correct for
1569 lateness as much as possible. */
1570 if (offset < 0)
1571 offset = 0;
1572
1573 eta_late = AVERAGE(eta_late, offset, 4);
1574 offset = eta_late;
1575
1576 if ((uint32_t)offset > eta_video)
1577 offset = eta_video;
1578
1579 eta_video -= offset;
Michael Sevakis045d3cc2007-04-21 05:27:45 +00001580 goto picture_wait;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001581 }
1582
1583 /** Possibly skip this frame **/
1584
1585 /* Frameskipping has the following order of preference:
1586 *
1587 * Frame Type Who Notes/Rationale
1588 * B decoder arbitrarily drop - no decode or draw
1589 * Any renderer arbitrarily drop - will be I/D/P
1590 * P decoder must wait for I/D-frame - choppy
1591 * I/D decoder must wait for I/D-frame - choppy
1592 *
1593 * If a frame can be drawn and it has been at least 1/2 second,
1594 * the image will be updated no matter how late it is just to
1595 * avoid looking stuck.
1596 */
1597
1598 /* If we're late, set the eta to play the frame early so
1599 we may catch up. If early, especially because of a drop,
1600 mitigate a "snap" by moving back gradually. */
1601 if (offset >= 0) /* late or on time */
1602 {
1603 eta_early = 0; /* Not early now :( */
1604
1605 eta_late = AVERAGE(eta_late, offset, 4);
1606 offset = eta_late;
1607
1608 if ((uint32_t)offset > eta_video)
1609 offset = eta_video;
1610
1611 eta_video -= offset;
1612 }
1613 else
1614 {
1615 eta_late = 0; /* Not late now :) */
1616
1617 if (offset > eta_early)
1618 {
1619 /* Just dropped a frame and we're now early or we're
1620 coming back from being early */
1621 eta_early = offset;
1622 if ((uint32_t)-offset > eta_video)
1623 offset = -eta_video;
1624
1625 eta_video += offset;
1626 }
1627 else
1628 {
1629 /* Just early with an offset, do exponential drift back */
1630 if (eta_early != 0)
1631 {
1632 eta_early = AVERAGE(eta_early, 0, 8);
1633 eta_video = ((uint32_t)-eta_early > eta_video) ?
1634 0 : (eta_video + eta_early);
1635 }
1636
1637 offset = eta_early;
1638 }
1639 }
1640
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001641 if (info->display_picture->flags & PIC_FLAG_SKIP)
Michael Sevakis6689cb02007-04-10 14:18:30 +00001642 {
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001643 /* This frame was set to skip so skip it after having updated
1644 timing information */
1645 num_skipped++;
1646 eta_early = INT32_MIN;
1647 goto picture_skip;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001648 }
1649
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001650 if (skip_level == 3 && TIME_BEFORE(*rb->current_tick, last_render + HZ/2))
Michael Sevakis6689cb02007-04-10 14:18:30 +00001651 {
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001652 /* Render drop was set previously but nothing was dropped in the
1653 decoder or it's been to long since drawing the last frame. */
1654 skip_level = 0;
1655 num_skipped++;
1656 eta_early = INT32_MIN;
1657 goto picture_skip;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001658 }
1659
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001660 /* At this point a frame _will_ be drawn - a skip may happen on
1661 the next however */
1662 skip_level = 0;
1663
1664 if (offset > CLOCK_RATE*110/1000)
1665 {
1666 /* Decide which skip level is needed in order to catch up */
1667
1668 /* TODO: Calculate this rather than if...else - this is rather
1669 exponential though */
1670 if (offset > CLOCK_RATE*367/1000)
1671 skip_level = 5; /* Decoder skip: I/D */
1672 if (offset > CLOCK_RATE*233/1000)
1673 skip_level = 4; /* Decoder skip: P */
1674 else if (offset > CLOCK_RATE*167/1000)
1675 skip_level = 3; /* Render skip */
1676 else if (offset > CLOCK_RATE*133/1000)
1677 skip_level = 2; /* Decoder skip: B */
1678 else
1679 skip_level = 1; /* Decoder skip: B */
1680 }
1681
Michael Sevakis045d3cc2007-04-21 05:27:45 +00001682 picture_wait:
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001683 /* Wait until audio catches up */
1684 while (eta_video > eta_audio)
1685 {
1686 rb->priority_yield();
1687
1688 /* Make sure not to get stuck waiting here forever */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001689 if (str_have_msg(&video_str))
1690 {
1691 str_look_msg(&video_str, &ev);
1692
Michael Sevakis930278b2007-07-20 03:56:59 +00001693 /* If not to play, process up top */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001694 if (ev.id != STREAM_PLAY)
1695 goto rendering_finished;
1696
Michael Sevakis930278b2007-07-20 03:56:59 +00001697 /* Told to play but already playing */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001698 str_get_msg(&video_str, &ev);
1699 str_reply_msg(&video_str, 1);
1700 }
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001701
1702 eta_audio = get_stream_time();
1703 }
1704
1705 picture_draw:
1706 /* Record last frame time */
1707 last_render = *rb->current_tick;
1708
Michael Sevakis6689cb02007-04-10 14:18:30 +00001709 vo_draw_frame(info->display_fbuf->buf);
1710 num_drawn++;
1711
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001712 picture_skip:
Michael Sevakis6689cb02007-04-10 14:18:30 +00001713 if (!settings.showfps)
1714 break;
1715
1716 /* Calculate and display fps */
1717 if (TIME_AFTER(*rb->current_tick, last_showfps + HZ))
1718 {
Marcoen Hirschberg3585ee72007-06-19 21:30:45 +00001719 uint32_t clock_ticks = get_playback_time() - count_start;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001720 int fps = 0;
1721
1722 if (clock_ticks != 0)
1723 fps = num_drawn*CLOCK_RATE*10ll / clock_ticks;
1724
Michael Sevakiseb4dcd82007-04-16 03:34:56 +00001725 rb->snprintf(str, sizeof(str), "%d.%d %d %d ",
Michael Sevakis6689cb02007-04-10 14:18:30 +00001726 fps / 10, fps % 10, num_skipped,
1727 info->display_picture->temporal_reference);
1728 rb->lcd_putsxy(0, 0, str);
1729 rb->lcd_update_rect(0, 0, LCD_WIDTH, 8);
1730
1731 last_showfps = *rb->current_tick;
Dave Chapmanc8e69df2006-08-20 23:12:56 +00001732 }
Dave Chapmanc9d66562006-08-07 22:11:07 +00001733 break;
Michael Sevakis01c0fb42007-04-18 23:23:18 +00001734 }
1735
Dave Chapmanc9d66562006-08-07 22:11:07 +00001736 default:
1737 break;
1738 }
Michael Sevakis6689cb02007-04-10 14:18:30 +00001739 rendering_finished:
Dave Chapmanc9d66562006-08-07 22:11:07 +00001740
1741 rb->yield();
1742 }
Dave Chapmanc9d66562006-08-07 22:11:07 +00001743
Dave Chapman4b801b22007-01-01 12:59:32 +00001744done:
Michael Sevakis9bfa2372007-04-14 02:46:15 +00001745 flush_icache();
1746
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001747 video_str.status = STREAM_DONE;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001748
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001749 while (1)
1750 {
1751 str_get_msg(&video_str, &ev);
Michael Sevakis6689cb02007-04-10 14:18:30 +00001752
Michael Sevakis930278b2007-07-20 03:56:59 +00001753 if (ev.id == STREAM_QUIT)
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001754 break;
1755
1756 str_reply_msg(&video_str, 0);
1757 }
1758
Michael Sevakis930278b2007-07-20 03:56:59 +00001759video_thread_quit:
1760 flush_icache();
1761
Dave Chapman83108482007-03-22 09:18:46 +00001762 /* Commit suicide */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001763 video_str.status = STREAM_TERMINATED;
Dave Chapman83108482007-03-22 09:18:46 +00001764 rb->remove_thread(NULL);
Dave Chapmanc9d66562006-08-07 22:11:07 +00001765}
1766
1767enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1768{
Michael Sevakis6689cb02007-04-10 14:18:30 +00001769 int status = PLUGIN_ERROR; /* assume failure */
Dave Chapmanc9d66562006-08-07 22:11:07 +00001770 void* audiobuf;
Michael Sevakis26d242a2007-04-21 18:38:25 +00001771 ssize_t audiosize;
Dave Chapmanc9d66562006-08-07 22:11:07 +00001772 int in_file;
Dave Chapman8d642c32006-08-09 10:47:22 +00001773 uint8_t* buffer;
Dave Chapman465820d2007-03-25 18:05:14 +00001774 size_t file_remaining;
Dave Chapman465820d2007-03-25 18:05:14 +00001775 size_t disk_buf_len;
Dave Chapmana5675712007-03-26 01:32:31 +00001776#ifndef HAVE_LCD_COLOR
1777 long graysize;
1778 int grayscales;
1779#endif
Dave Chapmanc9d66562006-08-07 22:11:07 +00001780
Michael Sevakis6689cb02007-04-10 14:18:30 +00001781 if (parameter == NULL)
1782 {
1783 api->splash(HZ*2, "No File");
1784 return PLUGIN_ERROR;
1785 }
Tomasz Malesinski80da8b12006-11-26 18:31:41 +00001786
Michael Sevakis6689cb02007-04-10 14:18:30 +00001787 /* Initialize IRAM - stops audio and voice as well */
Tomasz Malesinski80da8b12006-11-26 18:31:41 +00001788 PLUGIN_IRAM_INIT(api)
Michael Sevakis6689cb02007-04-10 14:18:30 +00001789
Tomasz Malesinski80da8b12006-11-26 18:31:41 +00001790 rb = api;
Dave Chapmanc9d66562006-08-07 22:11:07 +00001791
Michael Sevakis5f1abee2007-04-12 07:57:01 +00001792 audiobuf = rb->plugin_get_audio_buffer(&audiosize);
1793
Michael Sevakis4597ebe2007-06-10 02:10:47 +00001794#if INPUT_SRC_CAPS != 0
1795 /* Select playback */
1796 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
1797 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
1798#endif
1799
1800 rb->pcm_set_frequency(SAMPR_44);
1801
Dave Chapman4b801b22007-01-01 12:59:32 +00001802 /* Set disk pointers to NULL */
1803 disk_buf_end = disk_buf = NULL;
Michael Sevakis6689cb02007-04-10 14:18:30 +00001804
Dave Chapman4b801b22007-01-01 12:59:32 +00001805 /* Stream construction */
1806 /* We take the first stream of each (audio and video) */
1807 /* TODO : Search for these in the file first */
1808 audio_str.curr_packet_end = audio_str.curr_packet = audio_str.next_packet = NULL;
1809 video_str = audio_str;
1810 video_str.id = 0xe0;
1811 audio_str.id = 0xc0;
1812
Dave Chapmanc9d66562006-08-07 22:11:07 +00001813 /* Initialise our malloc buffer */
1814 mpeg2_alloc_init(audiobuf,audiosize);
1815
Michael Sevakis6689cb02007-04-10 14:18:30 +00001816 /* Grab most of the buffer for the compressed video - leave some for
Dave Chapman53952462007-01-02 13:36:17 +00001817 PCM audio data and some for libmpeg2 malloc use. */
Michael Sevakis6689cb02007-04-10 14:18:30 +00001818 buffer_size = audiosize - (PCMBUFFER_SIZE+PCMBUFFER_GUARD_SIZE+
1819 MPABUF_SIZE+LIBMPEG2BUFFER_SIZE);
Dave Chapman465820d2007-03-25 18:05:14 +00001820
Michael Sevakis26d242a2007-04-21 18:38:25 +00001821 DEBUGF("audiosize=%ld, buffer_size=%ld\n",audiosize,buffer_size);
Dave Chapman4b801b22007-01-01 12:59:32 +00001822 buffer = mpeg2_malloc(buffer_size,-1);
Dave Chapman8d642c32006-08-09 10:47:22 +00001823
1824 if (buffer == NULL)
1825 return PLUGIN_ERROR;
1826
Dave Chapmana5675712007-03-26 01:32:31 +00001827#ifndef HAVE_LCD_COLOR
1828 /* initialize the grayscale buffer: 32 bitplanes for 33 shades of gray. */
1829 grayscales = gray_init(rb, buffer, buffer_size, false, LCD_WIDTH, LCD_HEIGHT,
1830 32, 2<<8, &graysize) + 1;
1831 buffer += graysize;
1832 buffer_size -= graysize;
1833 if (grayscales < 33 || buffer_size <= 0)
1834 {
1835 rb->splash(HZ, "gray buf error");
1836 return PLUGIN_ERROR;
1837 }
1838#endif
1839
1840 buffer_size &= ~(0x7ff); /* Round buffer down to nearest 2KB */
Michael Sevakis8676dc22007-04-21 19:07:15 +00001841 DEBUGF("audiosize=%ld, buffer_size=%ld\n",audiosize,buffer_size);
Dave Chapmana5675712007-03-26 01:32:31 +00001842
Michael Sevakis6689cb02007-04-10 14:18:30 +00001843 if (!init_mpabuf())
Dave Chapman4b801b22007-01-01 12:59:32 +00001844 return PLUGIN_ERROR;
1845
Michael Sevakis6689cb02007-04-10 14:18:30 +00001846 if (!init_pcmbuf())
Dave Chapman4b801b22007-01-01 12:59:32 +00001847 return PLUGIN_ERROR;
1848
1849 /* The remaining buffer is for use by libmpeg2 */
Karl Kurbjuncd73d8b2006-11-15 06:18:51 +00001850
Michael Sevakis6689cb02007-04-10 14:18:30 +00001851 /* Open the video file */
1852 in_file = rb->open((char*)parameter,O_RDONLY);
1853
1854 if (in_file < 0){
1855 //fprintf(stderr,"Could not open %s\n",argv[1]);
1856 return PLUGIN_ERROR;
1857 }
1858
Dave Chapmanc9d66562006-08-07 22:11:07 +00001859#ifdef HAVE_LCD_COLOR
Dave Chapman4b801b22007-01-01 12:59:32 +00001860 rb->lcd_set_backdrop(NULL);
Dave Chapmanc9d66562006-08-07 22:11:07 +00001861 rb->lcd_set_foreground(LCD_WHITE);
1862 rb->lcd_set_background(LCD_BLACK);
1863#endif
1864 rb->lcd_clear_display();
1865 rb->lcd_update();
1866
Peter D'Hoyecb53e3c2007-08-15 12:42:09 +00001867 /* Turn off backlight timeout */
Peter D'Hoye767c0ec2007-08-16 23:01:18 +00001868 backlight_force_on(rb); /* backlight control in lib/helper.c */
Dave Chapmanc9d66562006-08-07 22:11:07 +00001869
1870#ifdef HAVE_ADJUSTABLE_CPU_FREQ
1871 rb->cpu_boost(true);
1872#endif
1873
Michael Sevakis6689cb02007-04-10 14:18:30 +00001874 /* From this point on we've altered settings, colors, cpu_boost, etc. and
1875 cannot just return PLUGIN_ERROR - instead drop though to cleanup code
1876 */
1877
1878 init_settings();
1879
1880 /* Msg queue init - no need for queue_remove since it's not a registered
1881 queue */
1882 rb->queue_init( &msg_queue, false );
1883
Dave Chapman4b801b22007-01-01 12:59:32 +00001884 /* Initialise libmad */
1885 rb->memset(mad_frame_overlap, 0, sizeof(mad_frame_overlap));
1886 init_mad(mad_frame_overlap);
1887
Dave Chapman465820d2007-03-25 18:05:14 +00001888 file_remaining = rb->filesize(in_file);
1889 disk_buf_end = buffer + buffer_size-MPEG_GUARDBUF_SIZE;
Dave Chapman4b801b22007-01-01 12:59:32 +00001890
Michael Sevakis6689cb02007-04-10 14:18:30 +00001891 /* Read some stream data */
Dave Chapman465820d2007-03-25 18:05:14 +00001892 disk_buf_len = rb->read (in_file, buffer, MPEG_LOW_WATERMARK);
1893
1894 DEBUGF("Initial Buffering - %d bytes\n",(int)disk_buf_len);
Dave Chapman4b801b22007-01-01 12:59:32 +00001895 disk_buf = buffer;
Dave Chapman465820d2007-03-25 18:05:14 +00001896 disk_buf_tail = buffer+disk_buf_len;
1897 file_remaining -= disk_buf_len;
Dave Chapman4b801b22007-01-01 12:59:32 +00001898
Dave Chapman465820d2007-03-25 18:05:14 +00001899 video_str.guard_bytes = audio_str.guard_bytes = 0;
1900 video_str.prev_packet = disk_buf;
1901 audio_str.prev_packet = disk_buf;
1902 video_str.buffer_remaining = disk_buf_len;
1903 audio_str.buffer_remaining = disk_buf_len;
1904
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001905 rb->spinlock_init(&audio_str.msg_lock);
1906 rb->spinlock_init(&video_str.msg_lock);
1907 audio_str.status = STREAM_BUFFERING;
1908 video_str.status = STREAM_PLAYING;
Dave Chapman4b801b22007-01-01 12:59:32 +00001909
Dave Chapmana5675712007-03-26 01:32:31 +00001910#ifndef HAVE_LCD_COLOR
1911 gray_show(true);
1912#endif
1913
Michael Sevakis9bfa2372007-04-14 02:46:15 +00001914 init_stream_lock();
1915
Michael Sevakisffbbc602007-08-04 00:48:57 +00001916 flush_icache();
1917
Dave Chapman4b801b22007-01-01 12:59:32 +00001918 /* We put the video thread on the second processor for multi-core targets. */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001919 if ((video_str.thread = rb->create_thread(video_thread,
Daniel Ankers82f90562007-03-04 20:06:41 +00001920 (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK)
Dave Chapman83108482007-03-22 09:18:46 +00001921 IF_COP(, COP, true))) == NULL)
Dave Chapman4b801b22007-01-01 12:59:32 +00001922 {
Jens Arnold4d6374c2007-03-16 21:56:08 +00001923 rb->splash(HZ, "Cannot create video thread!");
Dave Chapman4b801b22007-01-01 12:59:32 +00001924 }
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001925 else if ((audio_str.thread = rb->create_thread(audio_thread,
Daniel Ankers82f90562007-03-04 20:06:41 +00001926 (uint8_t*)audio_stack,AUDIO_STACKSIZE,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK)
Dave Chapman83108482007-03-22 09:18:46 +00001927 IF_COP(, CPU, false))) == NULL)
Dave Chapman4b801b22007-01-01 12:59:32 +00001928 {
Jens Arnold4d6374c2007-03-16 21:56:08 +00001929 rb->splash(HZ, "Cannot create audio thread!");
Dave Chapman4b801b22007-01-01 12:59:32 +00001930 }
Michael Sevakis6689cb02007-04-10 14:18:30 +00001931 else
1932 {
1933 //DEBUGF("START: video = %d, audio = %d\n",audio_str.buffer_remaining,video_str.buffer_remaining);
1934 rb->lcd_setfont(FONT_SYSFIXED);
Dave Chapman4b801b22007-01-01 12:59:32 +00001935
Michael Sevakis6689cb02007-04-10 14:18:30 +00001936 /* Wait until both threads have finished their work */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001937 while ((audio_str.status >= 0) || (video_str.status >= 0))
Michael Sevakis9bfa2372007-04-14 02:46:15 +00001938 {
1939 size_t audio_remaining = audio_str.buffer_remaining;
1940 size_t video_remaining = video_str.buffer_remaining;
1941
Michael Sevakis6689cb02007-04-10 14:18:30 +00001942 if (MIN(audio_remaining,video_remaining) < MPEG_LOW_WATERMARK) {
Dave Chapman465820d2007-03-25 18:05:14 +00001943
Michael Sevakis9bfa2372007-04-14 02:46:15 +00001944 size_t bytes_to_read = buffer_size - MPEG_GUARDBUF_SIZE -
1945 MAX(audio_remaining,video_remaining);
Dave Chapman465820d2007-03-25 18:05:14 +00001946
Michael Sevakis6689cb02007-04-10 14:18:30 +00001947 bytes_to_read = MIN(bytes_to_read,(size_t)(disk_buf_end-disk_buf_tail));
Dave Chapman465820d2007-03-25 18:05:14 +00001948
Michael Sevakis6689cb02007-04-10 14:18:30 +00001949 while (( bytes_to_read > 0) && (file_remaining > 0) &&
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001950 ((audio_str.status >= 0) || (video_str.status >= 0))) {
Michael Sevakis9bfa2372007-04-14 02:46:15 +00001951 size_t n = rb->read(in_file, disk_buf_tail, MIN(32*1024,bytes_to_read));
Dave Chapman465820d2007-03-25 18:05:14 +00001952
Michael Sevakis6689cb02007-04-10 14:18:30 +00001953 bytes_to_read -= n;
1954 file_remaining -= n;
Michael Sevakis9bfa2372007-04-14 02:46:15 +00001955
1956 lock_stream();
Michael Sevakis6689cb02007-04-10 14:18:30 +00001957 audio_str.buffer_remaining += n;
1958 video_str.buffer_remaining += n;
Michael Sevakis9bfa2372007-04-14 02:46:15 +00001959 unlock_stream();
1960
Michael Sevakis6689cb02007-04-10 14:18:30 +00001961 disk_buf_tail += n;
Michael Sevakis9bfa2372007-04-14 02:46:15 +00001962
Michael Sevakis6689cb02007-04-10 14:18:30 +00001963 rb->yield();
1964 }
1965
1966 if (disk_buf_tail == disk_buf_end)
1967 disk_buf_tail = buffer;
Dave Chapman465820d2007-03-25 18:05:14 +00001968 }
Michael Sevakis9bfa2372007-04-14 02:46:15 +00001969
Michael Sevakis6689cb02007-04-10 14:18:30 +00001970 rb->sleep(HZ/10);
Dave Chapman465820d2007-03-25 18:05:14 +00001971 }
Michael Sevakis6689cb02007-04-10 14:18:30 +00001972
1973 rb->lcd_setfont(FONT_UI);
1974 status = PLUGIN_OK;
Dave Chapman4b801b22007-01-01 12:59:32 +00001975 }
1976
Michael Sevakis6689cb02007-04-10 14:18:30 +00001977 /* Stop the threads and wait for them to terminate */
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001978 if (video_str.thread != NULL)
Michael Sevakis930278b2007-07-20 03:56:59 +00001979 str_send_msg(&video_str, STREAM_QUIT, 0);
Michael Sevakis6689cb02007-04-10 14:18:30 +00001980
Michael Sevakisb8bd1ee2007-07-19 19:32:29 +00001981 if (audio_str.thread != NULL)
Michael Sevakis930278b2007-07-20 03:56:59 +00001982 str_send_msg(&audio_str, STREAM_QUIT, 0);
Michael Sevakis6689cb02007-04-10 14:18:30 +00001983
Michael Sevakisdfa9f442007-04-11 11:02:45 +00001984 rb->sleep(HZ/10);
Dave Chapman4b801b22007-01-01 12:59:32 +00001985
Michael Sevakis4bd827b2007-04-12 06:02:47 +00001986#ifndef HAVE_LCD_COLOR
1987 gray_release();
1988#endif
1989
Dave Chapman4b801b22007-01-01 12:59:32 +00001990 rb->lcd_clear_display();
1991 rb->lcd_update();
Dave Chapmanc9d66562006-08-07 22:11:07 +00001992
1993 mpeg2_close (mpeg2dec);
1994
1995 rb->close (in_file);
1996
1997#ifdef HAVE_ADJUSTABLE_CPU_FREQ
1998 rb->cpu_boost(false);
1999#endif
2000
Dave Chapmanc8e69df2006-08-20 23:12:56 +00002001 save_settings(); /* Save settings (if they have changed) */
2002
Michael Sevakis4597ebe2007-06-10 02:10:47 +00002003 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
2004
Peter D'Hoyecb53e3c2007-08-15 12:42:09 +00002005 /* Turn on backlight timeout (revert to settings) */
Peter D'Hoye767c0ec2007-08-16 23:01:18 +00002006 backlight_use_settings(rb); /* backlight control in lib/helper.c */
Dave Chapmanc9d66562006-08-07 22:11:07 +00002007
Michael Sevakis6689cb02007-04-10 14:18:30 +00002008 return status;
Dave Chapmanc9d66562006-08-07 22:11:07 +00002009}