summaryrefslogtreecommitdiff
path: root/apps/plugins/mpegplayer/mpegplayer.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mpegplayer/mpegplayer.c')
-rw-r--r--apps/plugins/mpegplayer/mpegplayer.c2583
1 files changed, 213 insertions, 2370 deletions
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c
index eb904ed3c1..03ec5ba821 100644
--- a/apps/plugins/mpegplayer/mpegplayer.c
+++ b/apps/plugins/mpegplayer/mpegplayer.c
@@ -1,110 +1,110 @@
1/* 1/***************************************************************************
2 * mpegplayer.c - based on : 2 * __________ __ ___.
3 * - mpeg2dec.c 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * - m2psd.c (http://www.brouhaha.com/~eric/software/m2psd/) 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
5 * 9 *
6 * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> 10 * mpegplayer main entrypoint and UI implementation
7 * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
8 * 11 *
9 * m2psd: MPEG 2 Program Stream Demultiplexer 12 * Copyright (c) 2007 Michael Sevakis
10 * Copyright (C) 2003 Eric Smith <eric@brouhaha.com>
11 * 13 *
12 * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. 14 * All files in this archive are subject to the GNU General Public License.
13 * See http://libmpeg2.sourceforge.net/ for updates. 15 * See the file COPYING in the source tree root for full license agreement.
14 * 16 *
15 * mpeg2dec is free software; you can redistribute it and/or modify 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * it under the terms of the GNU General Public License as published by 18 * KIND, either express or implied.
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 * 19 *
20 * mpeg2dec is distributed in the hope that it will be useful, 20 ****************************************************************************/
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22/****************************************************************************
23 * GNU General Public License for more details. 23 * NOTES:
24 * 24 *
25 * You should have received a copy of the GNU General Public License 25 * mpegplayer is structured as follows:
26 * along with this program; if not, write to the Free Software 26 *
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 27 * +-->Video Thread-->Video Output-->LCD
28 */ 28 * |
29 29 * UI-->Stream Manager-->+-->Audio Thread-->PCM buffer--Audio Device
30/* 30 * | | | | (ref. clock)
31 31 * | | +-->Buffer Thread |
32NOTES: 32 * Stream Data | | (clock intf./
33 33 * Requests | File Cache drift adj.)
34mpegplayer is structured as follows: 34 * | Disk I/O
35 35 * Stream services
361) Video thread (running on the COP for PortalPlayer targets). 36 * (timing, etc.)
372) Audio thread (running on the main CPU to maintain consistency with 37 *
38 the audio FIQ hander on PP). 38 * Thread list:
393) The main thread which takes care of buffering. 39 * 1) The main thread - Handles user input, settings, basic playback control
40 40 * and USB connect.
41Using the main thread for buffering wastes the 8KB main stack which is 41 *
42in IRAM. However, 8KB is not enough for the audio thread to run (it 42 * 2) Stream Manager thread - Handles playback state, events from streams
43needs somewhere between 8KB and 9KB), so we create a new thread in 43 * such as when a stream is finished, stream commands, PCM state. The
44order to`give it a larger stack and steal the core codec thread's 44 * layer in which this thread run also handles arbitration of data
45stack (9KB of precious IRAM). 45 * requests between the streams and the disk buffer. The actual specific
46 46 * transport layer code may get moved out to support multiple container
47The button loop (and hence pause/resume, main menu and, in the future, 47 * formats.
48seeking) is placed in the audio thread. This keeps it on the main CPU 48 *
49in PP targets and also allows buffering to continue in the background 49 * 3) Buffer thread - Buffers data in the background, generates notifications
50whilst the main thread is filling the buffer. 50 * to streams when their data has been buffered, and watches streams'
51 51 * progress to keep data available during playback. Handles synchronous
52A/V sync is not yet implemented but is planned to be achieved by 52 * random access requests when the file cache is missed.
53syncing the master clock with the audio, and then (as is currently 53 *
54implemented), syncing video with the master clock. This can happen in 54 * 4) Video thread (running on the COP for PortalPlayer targets) - Decodes
55the audio thread, along with resyncing after pause. 55 * the video stream and renders video frames to the LCD. Handles
56 56 * miscellaneous video tasks like frame and thumbnail printing.
57Seeking should probably happen in the main thread, as that's where the 57 *
58buffering happens. 58 * 5) Audio thread (running on the main CPU to maintain consistency with the
59 59 * audio FIQ hander on PP) - Decodes audio frames and places them into
60On PortalPlayer targets, the main CPU is not being fully utilised - 60 * the PCM buffer for rendering by the audio device.
61the bottleneck is the video decoding on the COP. One way to improve 61 *
62that might be to move the rendering of the frames (i.e. the 62 * Streams are neither aware of one another nor care about one another. All
63lcd_yuv_blit() call) from the COP back to the main CPU. Ideas and 63 * streams shall have their own thread (unless it is _really_ efficient to
64patches for that are welcome! 64 * have a single thread handle a couple minor streams). All coordination of
65 65 * the streams is done through the stream manager. The clocking is controlled
66Notes about MPEG files: 66 * by and exposed by the stream manager to other streams and implemented at
67 67 * the PCM level.
68MPEG System Clock is 27MHz - i.e. 27000000 ticks/second. 68 *
69 69 * Notes about MPEG files:
70FPS is represented in terms of a frame period - this is always an 70 *
71integer number of 27MHz ticks. 71 * MPEG System Clock is 27MHz - i.e. 27000000 ticks/second.
72 72 *
73e.g. 29.97fps (30000/1001) NTSC video has an exact frame period of 73 * FPS is represented in terms of a frame period - this is always an
74900900 27MHz ticks. 74 * integer number of 27MHz ticks.
75 75 *
76In libmpeg2, info->sequence->frame_period contains the frame_period. 76 * e.g. 29.97fps (30000/1001) NTSC video has an exact frame period of
77 77 * 900900 27MHz ticks.
78Working with Rockbox's 100Hz tick, the common frame rates would need 78 *
79to be as follows: 79 * In libmpeg2, info->sequence->frame_period contains the frame_period.
80 80 *
81FPS | 27Mhz | 100Hz | 44.1KHz | 48KHz 81 * Working with Rockbox's 100Hz tick, the common frame rates would need
82--------|----------------------------------------------------------- 82 * to be as follows (1):
8310* | 2700000 | 10 | 4410 | 4800 83 *
8412* | 2250000 | 8.3333 | 3675 | 4000 84 * FPS | 27Mhz | 100Hz | 44.1KHz | 48KHz
8515* | 1800000 | 6.6667 | 2940 | 3200 85 * --------|-----------------------------------------------------------
8623.9760 | 1126125 | 4.170833333 | 1839.3375 | 2002 86 * 10* | 2700000 | 10 | 4410 | 4800
8724 | 1125000 | 4.166667 | 1837.5 | 2000 87 * 12* | 2250000 | 8.3333 | 3675 | 4000
8825 | 1080000 | 4 | 1764 | 1920 88 * 15* | 1800000 | 6.6667 | 2940 | 3200
8929.9700 | 900900 | 3.336667 | 1471,47 | 1601.6 89 * 23.9760 | 1126125 | 4.170833333 | 1839.3375 | 2002
9030 | 900000 | 3.333333 | 1470 | 1600 90 * 24 | 1125000 | 4.166667 | 1837.5 | 2000
91 91 * 25 | 1080000 | 4 | 1764 | 1920
92 92 * 29.9700 | 900900 | 3.336667 | 1471,47 | 1601.6
93*Unofficial framerates 93 * 30 | 900000 | 3.333333 | 1470 | 1600
94 94 *
95*/ 95 * *Unofficial framerates
96 96 *
97 97 * (1) But we don't really care since the audio clock is used anyway and has
98#include "mpeg2dec_config.h" 98 * very fine resolution ;-)
99 99 *****************************************************************************/
100#include "plugin.h" 100#include "plugin.h"
101#include "gray.h" 101#include "mpegplayer.h"
102#include "helper.h" 102#include "helper.h"
103
104#include "mpeg2.h"
105#include "mpeg_settings.h" 103#include "mpeg_settings.h"
104#include "mpeg2.h"
106#include "video_out.h" 105#include "video_out.h"
107#include "../../codecs/libmad/mad.h" 106#include "stream_thread.h"
107#include "stream_mgr.h"
108 108
109PLUGIN_HEADER 109PLUGIN_HEADER
110PLUGIN_IRAM_DECLARE 110PLUGIN_IRAM_DECLARE
@@ -177,908 +177,43 @@ PLUGIN_IRAM_DECLARE
177struct plugin_api* rb; 177struct plugin_api* rb;
178 178
179CACHE_FUNCTION_WRAPPERS(rb); 179CACHE_FUNCTION_WRAPPERS(rb);
180ALIGN_BUFFER_WRAPPER(rb);
180 181
181extern void *mpeg_malloc(size_t size, mpeg2_alloc_t reason); 182static bool button_loop(void)
182extern size_t mpeg_alloc_init(unsigned char *buf, size_t mallocsize,
183 size_t libmpeg2size);
184
185static mpeg2dec_t * mpeg2dec NOCACHEBSS_ATTR;
186static int total_offset NOCACHEBSS_ATTR = 0;
187static int num_drawn NOCACHEBSS_ATTR = 0;
188static int count_start NOCACHEBSS_ATTR = 0;
189
190/* Streams */
191typedef struct
192{
193 struct thread_entry *thread; /* Stream's thread */
194 int status; /* Current stream status */
195 struct queue_event ev; /* Event sent to steam */
196 int have_msg; /* 1=event pending */
197 int replied; /* 1=replied to last event */
198 int reply; /* reply value */
199 struct mutex msg_lock; /* serialization for event senders */
200 uint8_t* curr_packet; /* Current stream packet beginning */
201 uint8_t* curr_packet_end; /* Current stream packet end */
202
203 uint8_t* prev_packet; /* Previous stream packet beginning */
204 size_t prev_packet_length; /* Lenth of previous packet */
205 size_t buffer_remaining; /* How much data is left in the buffer */
206 uint32_t curr_pts; /* Current presentation timestamp */
207 uint32_t curr_time; /* Current time in samples */
208 uint32_t tagged; /* curr_pts is valid */
209
210 int id;
211} Stream;
212
213static Stream audio_str IBSS_ATTR;
214static Stream video_str IBSS_ATTR;
215
216/* Messages */
217enum
218{
219 STREAM_PLAY,
220 STREAM_PAUSE,
221 STREAM_QUIT
222};
223
224/* Status */
225enum
226{
227 STREAM_ERROR = -4,
228 STREAM_STOPPED = -3,
229 STREAM_TERMINATED = -2,
230 STREAM_DONE = -1,
231 STREAM_PLAYING = 0,
232 STREAM_PAUSED,
233 STREAM_BUFFERING
234};
235
236/* Returns true if a message is waiting */
237static inline bool str_have_msg(Stream *str)
238{ 183{
239 return str->have_msg != 0; 184 bool ret = true;
240}
241 185
242/* Waits until a message is sent */ 186 rb->lcd_setfont(FONT_SYSFIXED);
243static void str_wait_msg(Stream *str) 187 rb->lcd_clear_display();
244{ 188 rb->lcd_update();
245 int spin_count = 0;
246 189
247 while (str->have_msg == 0) 190 /* Start playback at the specified starting time */
191 if (stream_seek(settings.resume_time, SEEK_SET) < STREAM_OK ||
192 (stream_show_vo(true), stream_play()) < STREAM_OK)
248 { 193 {
249 if (spin_count < 100) 194 rb->splash(HZ*2, "Playback failed");
250 {
251 rb->yield();
252 spin_count++;
253 continue;
254 }
255
256 rb->sleep(0);
257 }
258}
259
260/* Returns a message waiting or blocks until one is available - removes the
261 event */
262static void str_get_msg(Stream *str, struct queue_event *ev)
263{
264 str_wait_msg(str);
265 ev->id = str->ev.id;
266 ev->data = str->ev.data;
267 str->have_msg = 0;
268}
269
270/* Peeks at the current message without blocking, returns the data but
271 does not remove the event */
272static bool str_look_msg(Stream *str, struct queue_event *ev)
273{
274 if (!str_have_msg(str))
275 return false; 195 return false;
276
277 ev->id = str->ev.id;
278 ev->data = str->ev.data;
279 return true;
280}
281
282/* Replies to the last message pulled - has no effect if last message has not
283 been pulled or already replied */
284static void str_reply_msg(Stream *str, int reply)
285{
286 if (str->replied == 1 || str->have_msg != 0)
287 return;
288
289 str->reply = reply;
290 str->replied = 1;
291}
292
293/* Sends a message to a stream and waits for a reply */
294static intptr_t str_send_msg(Stream *str, int id, intptr_t data)
295{
296 int spin_count = 0;
297 intptr_t reply;
298
299#if 0
300 if (str->thread == rb->thread_get_current())
301 return str->dispatch_fn(str, msg);
302#endif
303
304 /* Only one thread at a time, please */
305 rb->mutex_lock(&str->msg_lock);
306
307 str->ev.id = id;
308 str->ev.data = data;
309 str->reply = 0;
310 str->replied = 0;
311 str->have_msg = 1;
312
313 while (str->replied == 0 && str->status != STREAM_TERMINATED)
314 {
315 if (spin_count < 100)
316 {
317 rb->yield();
318 spin_count++;
319 continue;
320 }
321
322 rb->sleep(0);
323 }
324
325 reply = str->reply;
326
327 rb->mutex_unlock(&str->msg_lock);
328
329 return reply;
330}
331
332/* NOTE: Putting the following variables in IRAM cause audio corruption
333 on the ipod (reason unknown)
334*/
335static uint8_t *disk_buf_start IBSS_ATTR; /* Start pointer */
336static uint8_t *disk_buf_end IBSS_ATTR; /* End of buffer pointer less
337 MPEG_GUARDBUF_SIZE. The
338 guard space is used to wrap
339 data at the buffer start to
340 pass continuous data
341 packets */
342static uint8_t *disk_buf_tail IBSS_ATTR; /* Location of last data + 1
343 filled into the buffer */
344static size_t disk_buf_size IBSS_ATTR; /* The total buffer length
345 including the guard
346 space */
347static size_t file_remaining IBSS_ATTR;
348
349#if NUM_CORES > 1
350/* Some stream variables are shared between cores */
351struct mutex stream_lock IBSS_ATTR;
352static inline void init_stream_lock(void)
353 { rb->mutex_init(&stream_lock); }
354static inline void lock_stream(void)
355 { rb->mutex_lock(&stream_lock); }
356static inline void unlock_stream(void)
357 { rb->mutex_unlock(&stream_lock); }
358#else
359/* No RMW issue here */
360static inline void init_stream_lock(void)
361 { }
362static inline void lock_stream(void)
363 { }
364static inline void unlock_stream(void)
365 { }
366#endif
367
368static int audio_sync_start IBSS_ATTR; /* If 0, the audio thread
369 yields waiting on the video
370 thread to synchronize with
371 the stream */
372static uint32_t audio_sync_time IBSS_ATTR; /* The time that the video
373 thread has reached after
374 synchronizing. The
375 audio thread now needs
376 to advance to this
377 time */
378static int video_sync_start IBSS_ATTR; /* While 0, the video thread
379 yields until the audio
380 thread has reached the
381 audio_sync_time */
382static int video_thumb_print IBSS_ATTR; /* If 1, the video thread is
383 only decoding one frame for
384 use in the menu. If 0,
385 normal operation */
386static int end_pts_time IBSS_ATTR; /* The movie end time as represented by
387 the maximum audio PTS tag in the
388 stream converted to half minutes */
389static int start_pts_time IBSS_ATTR; /* The movie start time as represented by
390 the first audio PTS tag in the
391 stream converted to half minutes */
392char *filename; /* hack for resume time storage */
393
394
395/* Various buffers */
396/* TODO: Can we reduce the PCM buffer size? */
397#define PCMBUFFER_SIZE ((512*1024)-PCMBUFFER_GUARD_SIZE)
398#define PCMBUFFER_GUARD_SIZE (1152*4 + sizeof (struct pcm_frame_header))
399#define MPA_MAX_FRAME_SIZE 1729 /* Largest frame - MPEG1, Layer II, 384kbps, 32kHz, pad */
400#define MPABUF_SIZE (64*1024 + ALIGN_UP(MPA_MAX_FRAME_SIZE + 2*MAD_BUFFER_GUARD, 4))
401#define LIBMPEG2BUFFER_SIZE (2*1024*1024)
402
403/* 65536+6 is required since each PES has a 6 byte header with a 16 bit packet length field */
404#define MPEG_GUARDBUF_SIZE (65*1024) /* Keep a bit extra - excessive for now */
405#define MPEG_LOW_WATERMARK (1024*1024)
406
407static void pcm_playback_play_pause(bool play);
408
409/* libmad related functions/definitions */
410#define INPUT_CHUNK_SIZE 8192
411
412struct mad_stream stream IBSS_ATTR;
413struct mad_frame frame IBSS_ATTR;
414struct mad_synth synth IBSS_ATTR;
415
416unsigned char mad_main_data[MAD_BUFFER_MDLEN]; /* 2567 bytes */
417
418/* There isn't enough room for this in IRAM on PortalPlayer, but there
419 is for Coldfire. */
420
421#ifdef CPU_COLDFIRE
422static mad_fixed_t mad_frame_overlap[2][32][18] IBSS_ATTR; /* 4608 bytes */
423#else
424static mad_fixed_t mad_frame_overlap[2][32][18] __attribute__((aligned(16))); /* 4608 bytes */
425#endif
426
427static void init_mad(void* mad_frame_overlap)
428{
429 rb->memset(&stream, 0, sizeof(struct mad_stream));
430 rb->memset(&frame, 0, sizeof(struct mad_frame));
431 rb->memset(&synth, 0, sizeof(struct mad_synth));
432
433 mad_stream_init(&stream);
434 mad_frame_init(&frame);
435
436 /* We do this so libmad doesn't try to call codec_calloc() */
437 frame.overlap = mad_frame_overlap;
438
439 rb->memset(mad_main_data, 0, sizeof(mad_main_data));
440 stream.main_data = &mad_main_data;
441}
442
443/* MPEG related headers */
444
445/* Macros for comparing memory bytes to a series of constant bytes in an
446 efficient manner - evaluate to true if corresponding bytes match */
447#if defined (CPU_ARM)
448/* ARM must load 32-bit values at addres % 4 == 0 offsets but this data
449 isn't aligned nescessarily, so just byte compare */
450#define CMP_3_CONST(_a, _b) \
451 ({ \
452 int _x; \
453 asm volatile ( \
454 "ldrb %[x], [%[a], #0] \r\n" \
455 "eors %[x], %[x], %[b0] \r\n" \
456 "ldreqb %[x], [%[a], #1] \r\n" \
457 "eoreqs %[x], %[x], %[b1] \r\n" \
458 "ldreqb %[x], [%[a], #2] \r\n" \
459 "eoreqs %[x], %[x], %[b2] \r\n" \
460 : [x]"=&r"(_x) \
461 : [a]"r"(_a), \
462 [b0]"i"((_b) >> 24), \
463 [b1]"i"((_b) << 8 >> 24), \
464 [b2]"i"((_b) << 16 >> 24) \
465 ); \
466 _x == 0; \
467 })
468#define CMP_4_CONST(_a, _b) \
469 ({ \
470 int _x; \
471 asm volatile ( \
472 "ldrb %[x], [%[a], #0] \r\n" \
473 "eors %[x], %[x], %[b0] \r\n" \
474 "ldreqb %[x], [%[a], #1] \r\n" \
475 "eoreqs %[x], %[x], %[b1] \r\n" \
476 "ldreqb %[x], [%[a], #2] \r\n" \
477 "eoreqs %[x], %[x], %[b2] \r\n" \
478 "ldreqb %[x], [%[a], #3] \r\n" \
479 "eoreqs %[x], %[x], %[b3] \r\n" \
480 : [x]"=&r"(_x) \
481 : [a]"r"(_a), \
482 [b0]"i"((_b) >> 24), \
483 [b1]"i"((_b) << 8 >> 24), \
484 [b2]"i"((_b) << 16 >> 24), \
485 [b3]"i"((_b) << 24 >> 24) \
486 ); \
487 _x == 0; \
488 })
489#elif defined (CPU_COLDFIRE)
490/* Coldfire can just load a 32 bit value at any offset but ASM is not the best way
491 to integrate this with the C code */
492#define CMP_3_CONST(a, b) \
493 (((*(uint32_t *)(a) >> 8) ^ ((uint32_t)(b) >> 8)) == 0)
494#define CMP_4_CONST(a, b) \
495 ((*(uint32_t *)(a) ^ (b)) == 0)
496#else
497/* Don't know what this is - use bytewise comparisons */
498#define CMP_3_CONST(a, b) \
499 (( ((a)[0] ^ (((b) >> 24) & 0xff)) | \
500 ((a)[1] ^ (((b) >> 16) & 0xff)) | \
501 ((a)[2] ^ (((b) >> 8) & 0xff)) ) == 0)
502#define CMP_4_CONST(a, b) \
503 (( ((a)[0] ^ (((b) >> 24) & 0xff)) | \
504 ((a)[1] ^ (((b) >> 16) & 0xff)) | \
505 ((a)[2] ^ (((b) >> 8) & 0xff)) | \
506 ((a)[3] ^ ((b) & 0xff)) ) == 0)
507#endif
508
509/* Codes for various header byte sequences - MSB represents lowest memory
510 address */
511#define PACKET_START_CODE_PREFIX 0x00000100ul
512#define END_CODE 0x000001b9ul
513#define PACK_START_CODE 0x000001baul
514#define SYSTEM_HEADER_START_CODE 0x000001bbul
515
516/* p = base pointer, b0 - b4 = byte offsets from p */
517/* We only care about the MS 32 bits of the 33 and so the ticks are 45kHz */
518#define TS_FROM_HEADER(p, b0, b1, b2, b3, b4) \
519 ((uint32_t)(((p)[b0] >> 1 << 29) | \
520 ((p)[b1] << 21) | \
521 ((p)[b2] >> 1 << 14) | \
522 ((p)[b3] << 6) | \
523 ((p)[b4] >> 2 )))
524
525/* This function synchronizes the mpeg stream. The function returns
526 true on error */
527bool sync_data_stream(uint8_t **p)
528{
529 for (;;)
530 {
531 while ( !CMP_4_CONST(*p, PACK_START_CODE) && (*p) < disk_buf_tail )
532 (*p)++;
533 if ( (*p) >= disk_buf_tail )
534 break;
535 uint8_t *p_save = (*p);
536 if ( ((*p)[4] & 0xc0) == 0x40 ) /* mpeg-2 */
537 (*p) += 14 + ((*p)[13] & 7);
538 else if ( ((*p)[4] & 0xf0) == 0x20 ) /* mpeg-1 */
539 (*p) += 12;
540 else
541 (*p) += 5;
542 if ( (*p) >= disk_buf_tail )
543 break;
544 if ( CMP_3_CONST(*p, PACKET_START_CODE_PREFIX) )
545 {
546 (*p) = p_save;
547 break;
548 }
549 else
550 (*p) = p_save+1;
551 } 196 }
552 197
553 if ( (*p) >= disk_buf_tail ) 198 /* Gently poll the video player for EOS and handle UI */
554 return true; 199 while (stream_status() != STREAM_STOPPED)
555 else
556 return false;
557}
558
559/* This function demuxes the streams and gives the next stream data
560 pointer. Type 0 is normal operation. Type 1 and 2 have been added
561 for rapid seeks into the data stream. Type 1 and 2 ignore the
562 video_sync_start state (a signal to yield for refilling the
563 buffer). Type 1 will append more data to the buffer tail (minumal
564 bufer size reads that are increased only as needed). */
565static int get_next_data( Stream* str, uint8_t type )
566{
567 uint8_t *p;
568 uint8_t *header;
569 int stream;
570
571 static int mpeg1_skip_table[16] =
572 { 0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
573
574 if ( (p=str->curr_packet_end) == NULL)
575 p = disk_buf_start;
576
577 while (1)
578 { 200 {
579 int length, bytes; 201 int button = rb->button_get_w_tmo(HZ/2);
580
581 /* Yield for buffer filling */
582 if ( (type == 0) && (str->buffer_remaining < 120*1024) && (file_remaining > 0) )
583 while ( (str->buffer_remaining < 512*1024) && (file_remaining > 0) )
584 rb->yield();
585
586 /* The packet start position (plus an arbitrary header length)
587 has exceeded the amount of data in the buffer */
588 if ( type == 1 && (p+50) >= disk_buf_tail )
589 {
590 DEBUGF("disk buffer overflow\n");
591 return 1;
592 }
593
594 /* are we at the end of file? */
595 {
596 size_t tmp_length;
597 if (p < str->prev_packet)
598 tmp_length = (disk_buf_end - str->prev_packet) +
599 (p - disk_buf_start);
600 else
601 tmp_length = (p - str->prev_packet);
602 if (0 == str->buffer_remaining-tmp_length-str->prev_packet_length)
603 {
604 str->curr_packet_end = str->curr_packet = NULL;
605 break;
606 }
607 }
608 202
609 /* wrap the disk buffer */ 203 switch (button)
610 if (p >= disk_buf_end)
611 p = disk_buf_start + (p - disk_buf_end);
612
613 /* wrap packet header if needed */
614 if ( (p+50) >= disk_buf_end )
615 rb->memcpy(disk_buf_end, disk_buf_start, 50);
616
617 /* Pack header, skip it */
618 if (CMP_4_CONST(p, PACK_START_CODE))
619 { 204 {
620 if ((p[4] & 0xc0) == 0x40) /* mpeg-2 */ 205 case BUTTON_NONE:
621 {
622 p += 14 + (p[13] & 7);
623 }
624 else if ((p[4] & 0xf0) == 0x20) /* mpeg-1 */
625 {
626 p += 12;
627 }
628 else
629 {
630 rb->splash( 30, "Weird Pack header!" );
631 p += 5;
632 }
633 }
634
635 /* System header, parse and skip it - four bytes */
636 if (CMP_4_CONST(p, SYSTEM_HEADER_START_CODE))
637 {
638 int header_length;
639
640 p += 4; /*skip start code*/
641 header_length = *p++ << 8;
642 header_length += *p++;
643
644 p += header_length;
645
646 if ( p >= disk_buf_end )
647 p = disk_buf_start + (p - disk_buf_end);
648 }
649
650 /* Packet header, parse it */
651 if (!CMP_3_CONST(p, PACKET_START_CODE_PREFIX))
652 {
653 /* Problem */
654 rb->splash( HZ*3, "missing packet start code prefix : %X%X at %lX",
655 *p, *(p+2), (long unsigned int)(p-disk_buf_start) );
656
657 /* not 64bit safe
658 DEBUGF("end diff: %X,%X,%X,%X,%X,%X\n",(int)str->curr_packet_end,
659 (int)audio_str.curr_packet_end,(int)video_str.curr_packet_end,
660 (int)disk_buf_start,(int)disk_buf_end,(int)disk_buf_tail);
661 */
662
663 str->curr_packet_end = str->curr_packet = NULL;
664 break;
665 }
666
667 /* We retrieve basic infos */
668 stream = p[3];
669 length = (p[4] << 8) | p[5];
670
671 if (stream != str->id)
672 {
673 /* End of stream ? */
674 if (stream == 0xB9)
675 {
676 str->curr_packet_end = str->curr_packet = NULL;
677 break;
678 }
679
680 /* It's not the packet we're looking for, skip it */
681 p += length + 6;
682 continue; 206 continue;
683 }
684
685 /* Ok, it's our packet */
686 str->curr_packet_end = p + length+6;
687 header = p;
688
689 if ((header[6] & 0xc0) == 0x80) /* mpeg2 */
690 {
691 length = 9 + header[8];
692
693 /* header points to the mpeg2 pes header */
694 if (header[7] & 0x80)
695 {
696 /* header has a pts */
697 uint32_t pts = TS_FROM_HEADER(header, 9, 10, 11, 12, 13);
698
699 if (stream >= 0xe0)
700 {
701 /* video stream - header may have a dts as well */
702 uint32_t dts = (header[7] & 0x40) == 0 ?
703 pts : TS_FROM_HEADER(header, 14, 15, 16, 17, 18);
704
705 mpeg2_tag_picture (mpeg2dec, pts, dts);
706 }
707 else
708 {
709 str->curr_pts = pts;
710 str->tagged = 1;
711 }
712 }
713 }
714 else /* mpeg1 */
715 {
716 int len_skip;
717 uint8_t * ptsbuf;
718
719 length = 7;
720
721 while (header[length - 1] == 0xff)
722 {
723 length++;
724 if (length > 23)
725 {
726 rb->splash( 30, "Too much stuffing" );
727 DEBUGF("Too much stuffing" );
728 break;
729 }
730 }
731
732 if ( (header[length - 1] & 0xc0) == 0x40 )
733 length += 2;
734
735 len_skip = length;
736 length += mpeg1_skip_table[header[length - 1] >> 4];
737
738 /* header points to the mpeg1 pes header */
739 ptsbuf = header + len_skip;
740
741 if ((ptsbuf[-1] & 0xe0) == 0x20)
742 {
743 /* header has a pts */
744 uint32_t pts = TS_FROM_HEADER(ptsbuf, -1, 0, 1, 2, 3);
745
746 if (stream >= 0xe0)
747 {
748 /* video stream - header may have a dts as well */
749 uint32_t dts = (ptsbuf[-1] & 0xf0) != 0x30 ?
750 pts : TS_FROM_HEADER(ptsbuf, 4, 5, 6, 7, 18);
751
752 mpeg2_tag_picture (mpeg2dec, pts, dts);
753 }
754 else
755 {
756 str->curr_pts = pts;
757 str->tagged = 1;
758 }
759 }
760 }
761
762 p += length;
763 bytes = 6 + (header[4] << 8) + header[5] - length;
764
765 if (bytes > 0)
766 {
767 str->curr_packet_end = p + bytes;
768
769 if (str->curr_packet != NULL)
770 {
771 lock_stream();
772
773 str->buffer_remaining -= str->prev_packet_length;
774 if (str->curr_packet < str->prev_packet)
775 str->prev_packet_length = (disk_buf_end - str->prev_packet) +
776 (str->curr_packet - disk_buf_start);
777 else
778 str->prev_packet_length = (str->curr_packet - str->prev_packet);
779
780 unlock_stream();
781
782 str->prev_packet = str->curr_packet;
783 }
784
785 str->curr_packet = p;
786
787 if (str->curr_packet_end > disk_buf_end)
788 rb->memcpy(disk_buf_end, disk_buf_start,
789 str->curr_packet_end - disk_buf_end );
790 }
791
792 break;
793 } /* end while */
794 return 0;
795}
796
797/* Our clock rate in ticks/second - this won't be a constant for long */
798#define CLOCK_RATE 44100
799
800/* For simple lowpass filtering of sync variables */
801#define AVERAGE(var, x, count) (((var) * (count-1) + (x)) / (count))
802/* Convert 45kHz PTS/DTS ticks to our clock ticks */
803#define TS_TO_TICKS(pts) ((uint64_t)CLOCK_RATE*(pts) / 45000)
804/* Convert 27MHz ticks to our clock ticks */
805#define TIME_TO_TICKS(stamp) ((uint64_t)CLOCK_RATE*(stamp) / 27000000)
806
807/** MPEG audio stream buffer */
808uint8_t* mpa_buffer NOCACHEBSS_ATTR;
809
810static bool init_mpabuf(void)
811{
812 mpa_buffer = mpeg_malloc(MPABUF_SIZE,-2);
813 return mpa_buffer != NULL;
814}
815
816#define PTS_QUEUE_LEN (1 << 5) /* 32 should be way more than sufficient -
817 if not, the case is handled */
818#define PTS_QUEUE_MASK (PTS_QUEUE_LEN-1)
819struct pts_queue_slot
820{
821 uint32_t pts; /* Time stamp for packet */
822 ssize_t size; /* Number of bytes left in packet */
823} pts_queue[PTS_QUEUE_LEN] __attribute__((aligned(16)));
824
825 /* This starts out wr == rd but will never be emptied to zero during
826 streaming again in order to support initializing the first packet's
827 pts value without a special case */
828static unsigned pts_queue_rd NOCACHEBSS_ATTR;
829static unsigned pts_queue_wr NOCACHEBSS_ATTR;
830
831/* Increments the queue head postion - should be used to preincrement */
832static bool pts_queue_add_head(void)
833{
834 if (pts_queue_wr - pts_queue_rd >= PTS_QUEUE_LEN-1)
835 return false;
836
837 pts_queue_wr++;
838 return true;
839}
840
841/* Increments the queue tail position - leaves one slot as current */
842static bool pts_queue_remove_tail(void)
843{
844 if (pts_queue_wr - pts_queue_rd <= 1u)
845 return false;
846
847 pts_queue_rd++;
848 return true;
849}
850
851/* Returns the "head" at the index just behind the write index */
852static struct pts_queue_slot * pts_queue_head(void)
853{
854 return &pts_queue[(pts_queue_wr - 1) & PTS_QUEUE_MASK];
855}
856
857/* Returns a pointer to the current tail */
858static struct pts_queue_slot * pts_queue_tail(void)
859{
860 return &pts_queue[pts_queue_rd & PTS_QUEUE_MASK];
861}
862
863/* Resets the pts queue - call when starting and seeking */
864static void pts_queue_reset(void)
865{
866 struct pts_queue_slot *pts;
867 pts_queue_rd = pts_queue_wr;
868 pts = pts_queue_tail();
869 pts->pts = 0;
870 pts->size = 0;
871}
872
873struct pcm_frame_header /* Header added to pcm data every time a decoded
874 mpa frame is sent out */
875{
876 uint32_t size; /* size of this frame - including header */
877 uint32_t time; /* timestamp for this frame - derived from PTS */
878 unsigned char data[]; /* open array of audio data */
879};
880
881#define PCMBUF_PLAY_ALL 1l /* Forces buffer to play back all data */
882#define PCMBUF_PLAY_NONE LONG_MAX /* Keeps buffer from playing any data */
883static volatile uint64_t pcmbuf_read IBSS_ATTR;
884static volatile uint64_t pcmbuf_written IBSS_ATTR;
885static volatile ssize_t pcmbuf_threshold IBSS_ATTR;
886static struct pcm_frame_header *pcm_buffer IBSS_ATTR;
887static struct pcm_frame_header *pcmbuf_end IBSS_ATTR;
888static struct pcm_frame_header * volatile pcmbuf_head IBSS_ATTR;
889static struct pcm_frame_header * volatile pcmbuf_tail IBSS_ATTR;
890
891static volatile uint32_t samplesplayed IBSS_ATTR; /* Our base clock */
892static volatile uint32_t samplestart IBSS_ATTR; /* Clock at playback start */
893static volatile int32_t sampleadjust IBSS_ATTR; /* Clock drift adjustment */
894
895static ssize_t pcmbuf_used(void)
896{
897 return (ssize_t)(pcmbuf_written - pcmbuf_read);
898}
899
900static bool init_pcmbuf(void)
901{
902 pcm_buffer = mpeg_malloc(PCMBUFFER_SIZE + PCMBUFFER_GUARD_SIZE, -2);
903
904 if (pcm_buffer == NULL)
905 return false;
906
907 pcmbuf_head = pcm_buffer;
908 pcmbuf_tail = pcm_buffer;
909 pcmbuf_end = SKIPBYTES(pcm_buffer, PCMBUFFER_SIZE);
910 pcmbuf_read = 0;
911 pcmbuf_written = 0;
912
913 return true;
914}
915
916/* Advance a PCM buffer pointer by size bytes circularly */
917static inline void pcm_advance_buffer(struct pcm_frame_header * volatile *p,
918 size_t size)
919{
920 *p = SKIPBYTES(*p, size);
921 if (*p >= pcmbuf_end)
922 *p = pcm_buffer;
923}
924
925static void get_more(unsigned char** start, size_t* size)
926{
927 /* 25ms @ 44.1kHz */
928 static unsigned char silence[4412] __attribute__((aligned (4))) = { 0 };
929 size_t sz;
930
931 if (pcmbuf_used() >= pcmbuf_threshold)
932 {
933 uint32_t time = pcmbuf_tail->time;
934 sz = pcmbuf_tail->size;
935
936 *start = (unsigned char *)pcmbuf_tail->data;
937
938 pcm_advance_buffer(&pcmbuf_tail, sz);
939
940 pcmbuf_read += sz;
941
942 sz -= sizeof (*pcmbuf_tail);
943
944 *size = sz;
945
946 /* Drift the clock towards the audio timestamp values */
947 sampleadjust = AVERAGE(sampleadjust, (int32_t)(time - samplesplayed), 8);
948
949 /* Update master clock */
950 samplesplayed += sz >> 2;
951 return;
952 }
953
954 /* Keep clock going at all times */
955 sz = sizeof (silence);
956 *start = silence;
957 *size = sz;
958
959 samplesplayed += sz >> 2;
960
961 if (pcmbuf_read > pcmbuf_written)
962 pcmbuf_read = pcmbuf_written;
963}
964
965/* Flushes the buffer - clock keeps counting */
966static void pcm_playback_flush(void)
967{
968 bool was_playing = rb->pcm_is_playing();
969
970 if (was_playing)
971 rb->pcm_play_stop();
972
973 pcmbuf_read = 0;
974 pcmbuf_written = 0;
975 pcmbuf_head = pcmbuf_tail;
976
977 if (was_playing)
978 rb->pcm_play_data(get_more, NULL, 0);
979}
980
981/* Seek the reference clock to the specified time - next audio data ready to
982 go to DMA should be on the buffer with the same time index or else the PCM
983 buffer should be empty */
984static void pcm_playback_seek_time(uint32_t time)
985{
986 bool was_playing = rb->pcm_is_playing();
987
988 if (was_playing)
989 rb->pcm_play_stop();
990
991 samplesplayed = time;
992 samplestart = time;
993 sampleadjust = 0;
994
995 if (was_playing)
996 rb->pcm_play_data(get_more, NULL, 0);
997}
998
999/* Start pcm playback with the reference clock set to the specified time */
1000static void pcm_playback_play(uint32_t time)
1001{
1002 pcm_playback_seek_time(time);
1003
1004 if (!rb->pcm_is_playing())
1005 rb->pcm_play_data(get_more, NULL, 0);
1006}
1007
1008/* Pauses playback - and the clock */
1009static void pcm_playback_play_pause(bool play)
1010{
1011 rb->pcm_play_pause(play);
1012}
1013
1014/* Stops all playback and resets the clock */
1015static void pcm_playback_stop(void)
1016{
1017 if (rb->pcm_is_playing())
1018 rb->pcm_play_stop();
1019
1020 pcm_playback_flush();
1021
1022 sampleadjust =
1023 samplestart =
1024 samplesplayed = 0;
1025}
1026
1027static uint32_t get_stream_time(void)
1028{
1029 return samplesplayed + sampleadjust - (rb->pcm_get_bytes_waiting() >> 2);
1030}
1031
1032static uint32_t get_playback_time(void)
1033{
1034 return samplesplayed + sampleadjust -
1035 samplestart - (rb->pcm_get_bytes_waiting() >> 2);
1036}
1037
1038static inline int32_t clip_sample(int32_t sample)
1039{
1040 if ((int16_t)sample != sample)
1041 sample = 0x7fff ^ (sample >> 31);
1042
1043 return sample;
1044}
1045 207
1046static int button_loop(void)
1047{
1048 int result;
1049 int vol, minvol, maxvol;
1050 int button;
1051
1052 if (video_sync_start==1) {
1053
1054 if (str_have_msg(&audio_str))
1055 {
1056 struct queue_event ev;
1057 str_get_msg(&audio_str, &ev);
1058
1059 if (ev.id == STREAM_QUIT)
1060 {
1061 audio_str.status = STREAM_STOPPED;
1062 goto quit;
1063 }
1064 else
1065 {
1066 str_reply_msg(&audio_str, 0);
1067 }
1068 }
1069
1070 button = rb->button_get(false);
1071
1072 switch (button)
1073 {
1074 case MPEG_VOLUP: 208 case MPEG_VOLUP:
1075 case MPEG_VOLUP|BUTTON_REPEAT: 209 case MPEG_VOLUP|BUTTON_REPEAT:
1076#ifdef MPEG_VOLUP2 210#ifdef MPEG_VOLUP2
1077 case MPEG_VOLUP2: 211 case MPEG_VOLUP2:
1078 case MPEG_VOLUP2|BUTTON_REPEAT: 212 case MPEG_VOLUP2|BUTTON_REPEAT:
1079#endif 213#endif
1080 vol = rb->global_settings->volume; 214 {
1081 maxvol = rb->sound_max(SOUND_VOLUME); 215 int vol = rb->global_settings->volume;
216 int maxvol = rb->sound_max(SOUND_VOLUME);
1082 217
1083 if (vol < maxvol) { 218 if (vol < maxvol) {
1084 vol++; 219 vol++;
@@ -1086,6 +221,7 @@ static int button_loop(void)
1086 rb->global_settings->volume = vol; 221 rb->global_settings->volume = vol;
1087 } 222 }
1088 break; 223 break;
224 } /* MPEG_VOLUP*: */
1089 225
1090 case MPEG_VOLDOWN: 226 case MPEG_VOLDOWN:
1091 case MPEG_VOLDOWN|BUTTON_REPEAT: 227 case MPEG_VOLDOWN|BUTTON_REPEAT:
@@ -1093,8 +229,9 @@ static int button_loop(void)
1093 case MPEG_VOLDOWN2: 229 case MPEG_VOLDOWN2:
1094 case MPEG_VOLDOWN2|BUTTON_REPEAT: 230 case MPEG_VOLDOWN2|BUTTON_REPEAT:
1095#endif 231#endif
1096 vol = rb->global_settings->volume; 232 {
1097 minvol = rb->sound_min(SOUND_VOLUME); 233 int vol = rb->global_settings->volume;
234 int minvol = rb->sound_min(SOUND_VOLUME);
1098 235
1099 if (vol > minvol) { 236 if (vol > minvol) {
1100 vol--; 237 vol--;
@@ -1102,1225 +239,108 @@ static int button_loop(void)
1102 rb->global_settings->volume = vol; 239 rb->global_settings->volume = vol;
1103 } 240 }
1104 break; 241 break;
242 } /* MPEG_VOLDOWN*: */
1105 243
1106 case MPEG_MENU: 244 case MPEG_MENU:
1107 pcm_playback_play_pause(false); 245 {
1108 audio_str.status = STREAM_PAUSED; 246 int state = stream_pause(); /* save previous state */
1109 str_send_msg(&video_str, STREAM_PAUSE, 0); 247 int result;
1110#ifndef HAVE_LCD_COLOR
1111 gray_show(false);
1112#endif
1113 result = mpeg_menu();
1114 count_start = get_playback_time();
1115 num_drawn = 0;
1116 248
1117#ifndef HAVE_LCD_COLOR 249 /* Hide video output */
1118 gray_show(true); 250 stream_show_vo(false);
1119#endif 251 backlight_use_settings(rb);
252
253 result = mpeg_menu();
1120 254
1121 /* The menu can change the font, so restore */ 255 /* The menu can change the font, so restore */
1122 rb->lcd_setfont(FONT_SYSFIXED); 256 rb->lcd_setfont(FONT_SYSFIXED);
1123 257
1124 switch (result) 258 switch (result)
1125 { 259 {
1126 case MPEG_MENU_QUIT: 260 case MPEG_MENU_QUIT:
1127 settings.resume_time = (int)(get_stream_time()/CLOCK_RATE/ 261 stream_stop();
1128 30-start_pts_time); 262 break;
1129 str_send_msg(&video_str, STREAM_QUIT, 0); 263 default:
1130 audio_str.status = STREAM_STOPPED; 264 /* If not stopped, show video again */
1131 break; 265 if (state != STREAM_STOPPED)
1132 default: 266 stream_show_vo(true);
1133 audio_str.status = STREAM_PLAYING; 267
1134 str_send_msg(&video_str, STREAM_PLAY, 0); 268 /* If stream was playing, restart it */
1135 pcm_playback_play_pause(true); 269 if (state == STREAM_PLAYING) {
1136 break; 270 backlight_force_on(rb);
271 stream_resume();
272 }
273 break;
1137 } 274 }
1138 break; 275 break;
276 } /* MPEG_MENU: */
1139 277
1140 case MPEG_STOP: 278 case MPEG_STOP:
1141 settings.resume_time = (int)(get_stream_time()/CLOCK_RATE/ 279 {
1142 30-start_pts_time); 280 stream_stop();
1143 str_send_msg(&video_str, STREAM_QUIT, 0);
1144 audio_str.status = STREAM_STOPPED;
1145 break; 281 break;
282 } /* MPEG_STOP: */
1146 283
1147 case MPEG_PAUSE: 284 case MPEG_PAUSE:
1148#ifdef MPEG_PAUSE2 285#ifdef MPEG_PAUSE2
1149 case MPEG_PAUSE2: 286 case MPEG_PAUSE2:
1150#endif 287#endif
1151 settings.resume_time = (int)(get_stream_time()/CLOCK_RATE/
1152 30-start_pts_time);
1153 save_settings();
1154 str_send_msg(&video_str, STREAM_PAUSE, 0);
1155 audio_str.status = STREAM_PAUSED;
1156 pcm_playback_play_pause(false);
1157
1158 button = BUTTON_NONE;
1159#ifdef HAVE_ADJUSTABLE_CPU_FREQ
1160 rb->cpu_boost(false);
1161#endif
1162 do {
1163 button = rb->button_get(true);
1164 if (button == MPEG_STOP) {
1165 str_send_msg(&video_str, STREAM_QUIT, 0);
1166 audio_str.status = STREAM_STOPPED;
1167 goto quit;
1168 }
1169#ifndef MPEG_PAUSE2
1170 } while (button != MPEG_PAUSE);
1171#else
1172 } while (button != MPEG_PAUSE && button != MPEG_PAUSE2);
1173#endif
1174
1175 str_send_msg(&video_str, STREAM_PLAY, 0);
1176 audio_str.status = STREAM_PLAYING;
1177 pcm_playback_play_pause(true);
1178#ifdef HAVE_ADJUSTABLE_CPU_FREQ
1179 rb->cpu_boost(true);
1180#endif
1181 break;
1182
1183 default:
1184 if(rb->default_event_handler(button) == SYS_USB_CONNECTED) {
1185 str_send_msg(&video_str, STREAM_QUIT, 0);
1186 audio_str.status = STREAM_STOPPED;
1187 }
1188 }
1189 }
1190quit:
1191 return audio_str.status;
1192}
1193
1194static void audio_thread(void)
1195{
1196 uint8_t *mpabuf = mpa_buffer;
1197 ssize_t mpabuf_used = 0;
1198 int mad_errors = 0; /* A count of the errors in each frame */
1199 struct pts_queue_slot *pts;
1200
1201 /* We need this here to init the EMAC for Coldfire targets */
1202 mad_synth_init(&synth);
1203
1204 /* Init pts queue */
1205 pts_queue_reset();
1206 pts = pts_queue_tail();
1207
1208 /* Keep buffer from playing */
1209 pcmbuf_threshold = PCMBUF_PLAY_NONE;
1210
1211 /* Start clock */
1212 pcm_playback_play(0);
1213
1214 /* Get first packet */
1215 get_next_data(&audio_str, 0 );
1216
1217 /* skip audio packets here */
1218 while (audio_sync_start==0)
1219 {
1220 audio_str.status = STREAM_PLAYING;
1221 rb->yield();
1222 }
1223
1224 if (audio_sync_time>10000)
1225 {
1226 while (TS_TO_TICKS(audio_str.curr_pts) < audio_sync_time - 10000)
1227 {
1228 get_next_data(&audio_str, 0 );
1229 rb->priority_yield();
1230 }
1231 }
1232
1233 if (audio_str.curr_packet == NULL)
1234 goto done;
1235
1236 /* This is the decoding loop. */
1237 while (1)
1238 {
1239 int mad_stat;
1240 size_t len;
1241
1242 if (button_loop() == STREAM_STOPPED)
1243 goto audio_thread_quit;
1244
1245 if (pts->size <= 0)
1246 { 288 {
1247 /* Carry any overshoot to the next size since we're technically 289 if (stream_status() == STREAM_PLAYING) {
1248 -pts->size bytes into it already. If size is negative an audio 290 /* Playing => Paused */
1249 frame was split accross packets. Old has to be saved before 291 stream_pause();
1250 moving the tail. */ 292 backlight_use_settings(rb);
1251 if (pts_queue_remove_tail())
1252 {
1253 struct pts_queue_slot *old = pts;
1254 pts = pts_queue_tail();
1255 pts->size += old->size;
1256 old->size = 0;
1257 } 293 }
1258 } 294 else if (stream_status() == STREAM_PAUSED) {
1259 295 /* Paused => Playing */
1260 /** Buffering **/ 296 backlight_force_on(rb);
1261 if (mpabuf_used >= MPA_MAX_FRAME_SIZE + MAD_BUFFER_GUARD) 297 stream_resume();
1262 {
1263 /* Above low watermark - do nothing */
1264 }
1265 else if (audio_str.curr_packet != NULL)
1266 {
1267 do
1268 {
1269 /* Get data from next audio packet */
1270 len = audio_str.curr_packet_end - audio_str.curr_packet;
1271
1272 if (audio_str.tagged)
1273 {
1274 struct pts_queue_slot *stamp = pts;
1275
1276 if (pts_queue_add_head())
1277 {
1278 stamp = pts_queue_head();
1279 stamp->pts = TS_TO_TICKS(audio_str.curr_pts);
1280 /* pts->size should have been zeroed when slot was
1281 freed */
1282 }
1283 /* else queue full - just count up from the last to make
1284 it look like more data in the same packet */
1285 stamp->size += len;
1286 audio_str.tagged = 0;
1287 }
1288 else
1289 {
1290 /* Add to the one just behind the head - this may be the
1291 tail or the previouly added head - whether or not we'll
1292 ever reach this is quite in question since audio always
1293 seems to have every packet timestamped */
1294 pts_queue_head()->size += len;
1295 }
1296
1297 /* Slide any remainder over to beginning - avoid function
1298 call overhead if no data remaining as well */
1299 if (mpabuf > mpa_buffer && mpabuf_used > 0)
1300 rb->memmove(mpa_buffer, mpabuf, mpabuf_used);
1301
1302 /* Splice this packet onto any remainder */
1303 rb->memcpy(mpa_buffer + mpabuf_used, audio_str.curr_packet,
1304 len);
1305
1306 mpabuf_used += len;
1307 mpabuf = mpa_buffer;
1308
1309 /* Get data from next audio packet */
1310 get_next_data(&audio_str, 0 );
1311 }
1312 while (audio_str.curr_packet != NULL &&
1313 mpabuf_used < MPA_MAX_FRAME_SIZE + MAD_BUFFER_GUARD);
1314 }
1315 else if (mpabuf_used <= 0)
1316 {
1317 /* Used up remainder of mpa buffer so quit */
1318 break;
1319 }
1320
1321 /** Decoding **/
1322 mad_stream_buffer(&stream, mpabuf, mpabuf_used);
1323
1324 mad_stat = mad_frame_decode(&frame, &stream);
1325
1326 if (stream.next_frame == NULL)
1327 {
1328 /* What to do here? (This really is fatal) */
1329 DEBUGF("/* What to do here? */\n");
1330 break;
1331 }
1332
1333 /* Next mad stream buffer is the next frame postion */
1334 mpabuf = (uint8_t *)stream.next_frame;
1335
1336 /* Adjust sizes by the frame size */
1337 len = stream.next_frame - stream.this_frame;
1338 mpabuf_used -= len;
1339 pts->size -= len;
1340
1341 if (mad_stat != 0)
1342 {
1343 if (stream.error == MAD_FLAG_INCOMPLETE
1344 || stream.error == MAD_ERROR_BUFLEN)
1345 {
1346 /* This makes the codec support partially corrupted files */
1347 if (++mad_errors > 30)
1348 break;
1349
1350 stream.error = 0;
1351 rb->priority_yield();
1352 continue;
1353 }
1354 else if (MAD_RECOVERABLE(stream.error))
1355 {
1356 stream.error = 0;
1357 rb->priority_yield();
1358 continue;
1359 }
1360 else
1361 {
1362 /* Some other unrecoverable error */
1363 DEBUGF("Unrecoverable error\n");
1364 }
1365
1366 break;
1367 }
1368
1369 mad_errors = 0; /* Clear errors */
1370
1371 /* Generate the pcm samples */
1372 mad_synth_frame(&synth, &frame);
1373
1374 /** Output **/
1375
1376 /* TODO: Output through core dsp. We'll still use our own PCM buffer
1377 since the core pcm buffer has no timestamping or clock facilities */
1378
1379 /* Add a frame of audio to the pcm buffer. Maximum is 1152 samples. */
1380 if (synth.pcm.length > 0)
1381 {
1382 int16_t *audio_data = (int16_t *)pcmbuf_head->data;
1383 size_t size = sizeof (*pcmbuf_head) + synth.pcm.length*4;
1384 size_t wait_for = size + 32*1024;
1385
1386 /* Leave at least 32KB free (this will be the currently
1387 playing chunk) */
1388 while (pcmbuf_used() + wait_for > PCMBUFFER_SIZE)
1389 {
1390 if (str_have_msg(&audio_str))
1391 {
1392 struct queue_event ev;
1393 str_look_msg(&audio_str, &ev);
1394
1395 if (ev.id == STREAM_QUIT)
1396 goto audio_thread_quit;
1397 }
1398
1399 rb->priority_yield();
1400 }
1401
1402 if (video_sync_start == 0 &&
1403 pts->pts+(uint32_t)synth.pcm.length<audio_sync_time) {
1404 synth.pcm.length = 0;
1405 size = 0;
1406 rb->yield();
1407 }
1408
1409 /* TODO: This part will be replaced with dsp calls soon */
1410 if (MAD_NCHANNELS(&frame.header) == 2)
1411 {
1412 int32_t *left = &synth.pcm.samples[0][0];
1413 int32_t *right = &synth.pcm.samples[1][0];
1414 int i = synth.pcm.length;
1415
1416 do
1417 {
1418 /* libmad outputs s3.28 */
1419 *audio_data++ = clip_sample(*left++ >> 13);
1420 *audio_data++ = clip_sample(*right++ >> 13);
1421 }
1422 while (--i > 0);
1423 }
1424 else /* mono */
1425 {
1426 int32_t *mono = &synth.pcm.samples[0][0];
1427 int i = synth.pcm.length;
1428
1429 do
1430 {
1431 int32_t s = clip_sample(*mono++ >> 13);
1432 *audio_data++ = s;
1433 *audio_data++ = s;
1434 }
1435 while (--i > 0);
1436 }
1437 /**/
1438
1439 pcmbuf_head->time = pts->pts;
1440 pcmbuf_head->size = size;
1441
1442 /* As long as we're on this timestamp, the time is just incremented
1443 by the number of samples */
1444 pts->pts += synth.pcm.length;
1445
1446 pcm_advance_buffer(&pcmbuf_head, size);
1447
1448 if (pcmbuf_threshold != PCMBUF_PLAY_ALL && pcmbuf_used() >= 64*1024)
1449 {
1450 /* We've reached our size treshold so start playing back the
1451 audio in the buffer and set the buffer to play all data */
1452 audio_str.status = STREAM_PLAYING;
1453 pcmbuf_threshold = PCMBUF_PLAY_ALL;
1454 pcm_playback_seek_time(pcmbuf_tail->time);
1455 video_sync_start = 1;
1456 }
1457
1458 /* Make this data available to DMA */
1459 pcmbuf_written += size;
1460 }
1461
1462 rb->yield();
1463 } /* end decoding loop */
1464
1465done:
1466 if (audio_str.status == STREAM_STOPPED)
1467 goto audio_thread_quit;
1468
1469 /* Force any residue to play if audio ended before reaching the
1470 threshold */
1471 if (pcmbuf_threshold != PCMBUF_PLAY_ALL && pcmbuf_used() > 0)
1472 {
1473 pcm_playback_play(pcmbuf_tail->time);
1474 pcmbuf_threshold = PCMBUF_PLAY_ALL;
1475 }
1476
1477 if (rb->pcm_is_playing() && !rb->pcm_is_paused())
1478 {
1479 /* Wait for audio to finish */
1480 while (pcmbuf_used() > 0)
1481 {
1482 if (button_loop() == STREAM_STOPPED)
1483 goto audio_thread_quit;
1484 rb->sleep(HZ/10);
1485 }
1486 }
1487
1488 audio_str.status = STREAM_DONE;
1489
1490 /* Process events until finished */
1491 while (button_loop() != STREAM_STOPPED)
1492 rb->sleep(HZ/4);
1493
1494audio_thread_quit:
1495 pcm_playback_stop();
1496
1497 audio_str.status = STREAM_TERMINATED;
1498}
1499
1500/* End of libmad stuff */
1501
1502/* The audio stack is stolen from the core codec thread (but not in uisim) */
1503#define AUDIO_STACKSIZE (9*1024)
1504uint32_t* audio_stack;
1505
1506#ifndef SIMULATOR
1507static uint32_t codec_stack_copy[AUDIO_STACKSIZE / sizeof(uint32_t)];
1508#endif
1509
1510/* TODO: Check if 4KB is appropriate - it works for my test streams,
1511 so maybe we can reduce it. */
1512#define VIDEO_STACKSIZE (4*1024)
1513static uint32_t video_stack[VIDEO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR;
1514
1515static void video_thread(void)
1516{
1517 struct queue_event ev;
1518 const mpeg2_info_t * info;
1519 mpeg2_state_t state;
1520 char str[80];
1521 uint32_t curr_time = 0;
1522 uint32_t period = 0; /* Frame period in clock ticks */
1523 uint32_t eta_audio = UINT_MAX, eta_video = 0;
1524 int32_t eta_early = 0, eta_late = 0;
1525 int frame_drop_level = 0;
1526 int skip_level = 0;
1527 int num_skipped = 0;
1528 /* Used to decide when to display FPS */
1529 unsigned long last_showfps = *rb->current_tick - HZ;
1530 /* Used to decide whether or not to force a frame update */
1531 unsigned long last_render = last_showfps;
1532
1533 mpeg2dec = mpeg2_init();
1534 if (mpeg2dec == NULL)
1535 {
1536 rb->splash(0, "mpeg2_init failed");
1537 /* Commit suicide */
1538 video_str.status = STREAM_TERMINATED;
1539 return;
1540 }
1541
1542 /* Clear the display - this is mainly just to indicate that the
1543 video thread has started successfully. */
1544 if (!video_thumb_print)
1545 {
1546 rb->lcd_clear_display();
1547 rb->lcd_update();
1548 }
1549
1550 /* Request the first packet data */
1551 get_next_data( &video_str, 0 );
1552
1553 if (video_str.curr_packet == NULL)
1554 goto video_thread_quit;
1555
1556 mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end);
1557 total_offset += video_str.curr_packet_end - video_str.curr_packet;
1558
1559 info = mpeg2_info (mpeg2dec);
1560
1561 while (1)
1562 {
1563 /* quickly check mailbox first */
1564 if (video_thumb_print)
1565 {
1566 if (video_str.status == STREAM_STOPPED)
1567 break;
1568 }
1569 else if (str_have_msg(&video_str))
1570 {
1571 while (1)
1572 {
1573 str_get_msg(&video_str, &ev);
1574
1575 switch (ev.id)
1576 {
1577 case STREAM_QUIT:
1578 video_str.status = STREAM_STOPPED;
1579 goto video_thread_quit;
1580 case STREAM_PAUSE:
1581 #if NUM_CORES > 1
1582 flush_icache();
1583 #endif
1584 video_str.status = STREAM_PAUSED;
1585 str_reply_msg(&video_str, 1);
1586 continue;
1587 }
1588
1589 break;
1590 } 298 }
1591 299
1592 video_str.status = STREAM_PLAYING;
1593 str_reply_msg(&video_str, 1);
1594 }
1595
1596 state = mpeg2_parse (mpeg2dec);
1597 rb->yield();
1598
1599 /* Prevent idle poweroff */
1600 rb->reset_poweroff_timer();
1601
1602 switch (state)
1603 {
1604 case STATE_BUFFER:
1605 /* Request next packet data */
1606 get_next_data( &video_str, 0 );
1607
1608 mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end);
1609 total_offset += video_str.curr_packet_end - video_str.curr_packet;
1610 info = mpeg2_info (mpeg2dec);
1611
1612 if (video_str.curr_packet == NULL)
1613 {
1614 /* No more data. */
1615 goto video_thread_quit;
1616 }
1617 continue;
1618
1619 case STATE_SEQUENCE:
1620 /* New GOP, inform output of any changes */
1621 vo_setup(info->sequence);
1622 break; 300 break;
1623 301 } /* MPEG_PAUSE*: */
1624 case STATE_PICTURE: 302
1625 { 303 case SYS_POWEROFF:
1626 int skip = 0; /* Assume no skip */ 304 case SYS_USB_CONNECTED:
1627 305 /* Stop and get the resume time before closing the file early */
1628 if (frame_drop_level >= 1 || skip_level > 0) 306 stream_stop();
1629 { 307 settings.resume_time = stream_get_resume_time();
1630 /* A frame will be dropped in the decoder */ 308 stream_close();
1631 309 ret = false;
1632 /* Frame type: I/P/B/D */ 310 /* Fall-through */
1633 int type = info->current_picture->flags & PIC_MASK_CODING_TYPE;
1634
1635 switch (type)
1636 {
1637 case PIC_FLAG_CODING_TYPE_I:
1638 case PIC_FLAG_CODING_TYPE_D:
1639 /* Level 5: Things are extremely late and all frames will be
1640 dropped until the next key frame */
1641 if (frame_drop_level >= 1)
1642 frame_drop_level = 0; /* Key frame - reset drop level */
1643 if (skip_level >= 5)
1644 {
1645 frame_drop_level = 1;
1646 skip_level = 0; /* reset */
1647 }
1648 break;
1649 case PIC_FLAG_CODING_TYPE_P:
1650 /* Level 4: Things are very late and all frames will be
1651 dropped until the next key frame */
1652 if (skip_level >= 4)
1653 {
1654 frame_drop_level = 1;
1655 skip_level = 0; /* reset */
1656 }
1657 break;
1658 case PIC_FLAG_CODING_TYPE_B:
1659 /* We want to drop something, so this B frame won't even
1660 be decoded. Drawing can happen on the next frame if so
1661 desired. Bring the level down as skips are done. */
1662 skip = 1;
1663 if (skip_level > 0)
1664 skip_level--;
1665 }
1666
1667 skip |= frame_drop_level;
1668 }
1669
1670 mpeg2_skip(mpeg2dec, skip);
1671 break;
1672 }
1673
1674 case STATE_SLICE:
1675 case STATE_END:
1676 case STATE_INVALID_END:
1677 {
1678 int32_t offset; /* Tick adjustment to keep sync */
1679
1680 /* draw current picture */
1681 if (!info->display_fbuf)
1682 break;
1683
1684 /* No limiting => no dropping - draw this frame */
1685 if (!settings.limitfps && (video_thumb_print == 0))
1686 {
1687 audio_sync_start = 1;
1688 video_sync_start = 1;
1689 goto picture_draw;
1690 }
1691
1692 /* Get presentation times in audio samples - quite accurate
1693 enough - add previous frame duration if not stamped */
1694 curr_time = (info->display_picture->flags & PIC_FLAG_TAGS) ?
1695 TS_TO_TICKS(info->display_picture->tag) : (curr_time + period);
1696
1697 period = TIME_TO_TICKS(info->sequence->frame_period);
1698
1699 if ( (video_thumb_print == 1 || video_sync_start == 0) &&
1700 ((int)(info->current_picture->flags & PIC_MASK_CODING_TYPE)
1701 == PIC_FLAG_CODING_TYPE_B))
1702 break;
1703
1704 eta_video = curr_time;
1705
1706 audio_sync_time = eta_video;
1707 audio_sync_start = 1;
1708
1709 while (video_sync_start == 0)
1710 rb->yield();
1711
1712 eta_audio = get_stream_time();
1713
1714 /* How early/late are we? > 0 = late, < 0 early */
1715 offset = eta_audio - eta_video;
1716
1717 if (!settings.skipframes)
1718 {
1719 /* Make no effort to determine whether this frame should be
1720 drawn or not since no action can be taken to correct the
1721 situation. We'll just wait if we're early and correct for
1722 lateness as much as possible. */
1723 if (offset < 0)
1724 offset = 0;
1725
1726 eta_late = AVERAGE(eta_late, offset, 4);
1727 offset = eta_late;
1728
1729 if ((uint32_t)offset > eta_video)
1730 offset = eta_video;
1731
1732 eta_video -= offset;
1733 goto picture_wait;
1734 }
1735
1736 /** Possibly skip this frame **/
1737
1738 /* Frameskipping has the following order of preference:
1739 *
1740 * Frame Type Who Notes/Rationale
1741 * B decoder arbitrarily drop - no decode or draw
1742 * Any renderer arbitrarily drop - will be I/D/P
1743 * P decoder must wait for I/D-frame - choppy
1744 * I/D decoder must wait for I/D-frame - choppy
1745 *
1746 * If a frame can be drawn and it has been at least 1/2 second,
1747 * the image will be updated no matter how late it is just to
1748 * avoid looking stuck.
1749 */
1750
1751 /* If we're late, set the eta to play the frame early so
1752 we may catch up. If early, especially because of a drop,
1753 mitigate a "snap" by moving back gradually. */
1754 if (offset >= 0) /* late or on time */
1755 {
1756 eta_early = 0; /* Not early now :( */
1757
1758 eta_late = AVERAGE(eta_late, offset, 4);
1759 offset = eta_late;
1760
1761 if ((uint32_t)offset > eta_video)
1762 offset = eta_video;
1763
1764 eta_video -= offset;
1765 }
1766 else
1767 {
1768 eta_late = 0; /* Not late now :) */
1769
1770 if (offset > eta_early)
1771 {
1772 /* Just dropped a frame and we're now early or we're
1773 coming back from being early */
1774 eta_early = offset;
1775 if ((uint32_t)-offset > eta_video)
1776 offset = -eta_video;
1777
1778 eta_video += offset;
1779 }
1780 else
1781 {
1782 /* Just early with an offset, do exponential drift back */
1783 if (eta_early != 0)
1784 {
1785 eta_early = AVERAGE(eta_early, 0, 8);
1786 eta_video = ((uint32_t)-eta_early > eta_video) ?
1787 0 : (eta_video + eta_early);
1788 }
1789
1790 offset = eta_early;
1791 }
1792 }
1793
1794 if (info->display_picture->flags & PIC_FLAG_SKIP)
1795 {
1796 /* This frame was set to skip so skip it after having updated
1797 timing information */
1798 num_skipped++;
1799 eta_early = INT32_MIN;
1800 goto picture_skip;
1801 }
1802
1803 if (skip_level == 3 && TIME_BEFORE(*rb->current_tick, last_render + HZ/2))
1804 {
1805 /* Render drop was set previously but nothing was dropped in the
1806 decoder or it's been to long since drawing the last frame. */
1807 skip_level = 0;
1808 num_skipped++;
1809 eta_early = INT32_MIN;
1810 goto picture_skip;
1811 }
1812
1813 /* At this point a frame _will_ be drawn - a skip may happen on
1814 the next however */
1815 skip_level = 0;
1816
1817 if (offset > CLOCK_RATE*110/1000)
1818 {
1819 /* Decide which skip level is needed in order to catch up */
1820
1821 /* TODO: Calculate this rather than if...else - this is rather
1822 exponential though */
1823 if (offset > CLOCK_RATE*367/1000)
1824 skip_level = 5; /* Decoder skip: I/D */
1825 if (offset > CLOCK_RATE*233/1000)
1826 skip_level = 4; /* Decoder skip: P */
1827 else if (offset > CLOCK_RATE*167/1000)
1828 skip_level = 3; /* Render skip */
1829 else if (offset > CLOCK_RATE*133/1000)
1830 skip_level = 2; /* Decoder skip: B */
1831 else
1832 skip_level = 1; /* Decoder skip: B */
1833 }
1834
1835 picture_wait:
1836 /* Wait until audio catches up */
1837 if (video_thumb_print)
1838 video_str.status = STREAM_STOPPED;
1839 else
1840 while (eta_video > eta_audio)
1841 {
1842 rb->priority_yield();
1843
1844 /* Make sure not to get stuck waiting here forever */
1845 if (str_have_msg(&video_str))
1846 {
1847 str_look_msg(&video_str, &ev);
1848
1849 /* If not to play, process up top */
1850 if (ev.id != STREAM_PLAY)
1851 goto rendering_finished;
1852
1853 /* Told to play but already playing */
1854 str_get_msg(&video_str, &ev);
1855 str_reply_msg(&video_str, 1);
1856 }
1857
1858 eta_audio = get_stream_time();
1859 }
1860
1861 picture_draw:
1862 /* Record last frame time */
1863 last_render = *rb->current_tick;
1864
1865 if (video_thumb_print)
1866 vo_draw_frame_thumb(info->display_fbuf->buf);
1867 else
1868 vo_draw_frame(info->display_fbuf->buf);
1869
1870 num_drawn++;
1871
1872 picture_skip:
1873 if (!settings.showfps)
1874 break;
1875
1876 /* Calculate and display fps */
1877 if (TIME_AFTER(*rb->current_tick, last_showfps + HZ))
1878 {
1879 uint32_t clock_ticks = get_playback_time() - count_start;
1880 int fps = 0;
1881
1882 if (clock_ticks != 0)
1883 fps = num_drawn*CLOCK_RATE*10ll / clock_ticks;
1884
1885 rb->snprintf(str, sizeof(str), "%d.%d %d %d ",
1886 fps / 10, fps % 10, num_skipped,
1887 info->display_picture->temporal_reference);
1888 rb->lcd_putsxy(0, 0, str);
1889 rb->lcd_update_rect(0, 0, LCD_WIDTH, 8);
1890
1891 last_showfps = *rb->current_tick;
1892 }
1893 break;
1894 }
1895
1896 default: 311 default:
312 rb->default_event_handler(button);
1897 break; 313 break;
1898 } 314 }
1899 rendering_finished:
1900 315
1901 rb->yield(); 316 rb->yield();
1902 } 317 } /* end while */
1903
1904 video_thread_quit:
1905 /* if video ends before time sync'd,
1906 besure the audio thread is closed */
1907 if (video_sync_start == 0)
1908 {
1909 audio_str.status = STREAM_STOPPED;
1910 audio_sync_start = 1;
1911 }
1912
1913 #if NUM_CORES > 1
1914 flush_icache();
1915 #endif
1916
1917 mpeg2_close (mpeg2dec);
1918
1919 /* Commit suicide */
1920 video_str.status = STREAM_TERMINATED;
1921}
1922
1923void initialize_stream( Stream *str, uint8_t *buffer_start, size_t disk_buf_len, int id )
1924{
1925 str->curr_packet_end = str->curr_packet = NULL;
1926 str->prev_packet_length = 0;
1927 str->prev_packet = str->curr_packet_end = buffer_start;
1928 str->buffer_remaining = disk_buf_len;
1929 str->id = id;
1930}
1931
1932void display_thumb(int in_file)
1933{
1934 size_t disk_buf_len;
1935
1936 video_thumb_print = 1;
1937 audio_sync_start = 1;
1938 video_sync_start = 1;
1939
1940 disk_buf_len = rb->read (in_file, disk_buf_start, disk_buf_size - MPEG_GUARDBUF_SIZE);
1941 disk_buf_tail = disk_buf_start + disk_buf_len;
1942 file_remaining = 0;
1943 initialize_stream(&video_str,disk_buf_start,disk_buf_len,0xe0);
1944
1945 video_str.status = STREAM_PLAYING;
1946
1947 if ((video_str.thread = rb->create_thread(video_thread,
1948 (uint8_t*)video_stack,VIDEO_STACKSIZE, 0,"mpgvideo"
1949 IF_PRIO(,PRIORITY_PLAYBACK) IF_COP(, COP))) == NULL)
1950 {
1951 rb->splash(HZ, "Cannot create video thread!");
1952 }
1953 else
1954 {
1955 rb->thread_wait(video_str.thread);
1956 }
1957 318
1958 if ( video_str.curr_packet_end == video_str.curr_packet) 319 rb->lcd_setfont(FONT_UI);
1959 rb->splash(0, "frame not available");
1960}
1961 320
1962int find_start_pts( int in_file ) 321 return ret;
1963{
1964 uint8_t *p;
1965 size_t read_length = 60*1024;
1966 size_t disk_buf_len;
1967
1968 start_pts_time = 0;
1969
1970 /* temporary read buffer size cannot exceed buffer size */
1971 if ( read_length > disk_buf_size )
1972 read_length = disk_buf_size;
1973
1974 /* read tail of file */
1975 rb->lseek( in_file, 0, SEEK_SET );
1976 disk_buf_len = rb->read( in_file, disk_buf_start, read_length );
1977 disk_buf_tail = disk_buf_start + disk_buf_len;
1978
1979 /* sync reader to this segment of the stream */
1980 p=disk_buf_start;
1981 if (sync_data_stream(&p))
1982 {
1983 DEBUGF("Could not sync stream\n");
1984 return PLUGIN_ERROR;
1985 }
1986
1987 /* find first PTS in audio stream. if the PTS can not be determined,
1988 set start_pts_time to 0 */
1989 audio_sync_start = 0;
1990 audio_sync_time = 0;
1991 video_sync_start = 0;
1992 {
1993 Stream tmp;
1994 initialize_stream(&tmp,p,disk_buf_len-(disk_buf_start-p),0xc0);
1995 int count=0;
1996 do
1997 {
1998 count++;
1999 get_next_data(&tmp, 2);
2000 }
2001 while (tmp.tagged != 1 && count < 30);
2002 if (tmp.tagged == 1)
2003 start_pts_time = (int)((tmp.curr_pts/45000)/30);
2004 }
2005 return 0;
2006} 322}
2007 323
2008int find_end_pts( int in_file )
2009{
2010 uint8_t *p;
2011 size_t read_length = 60*1024;
2012 size_t disk_buf_len;
2013
2014 end_pts_time = 0;
2015
2016 /* temporary read buffer size cannot exceed buffer size */
2017 if ( read_length > disk_buf_size )
2018 read_length = disk_buf_size;
2019
2020 /* read tail of file */
2021 rb->lseek( in_file, -1*read_length, SEEK_END );
2022 disk_buf_len = rb->read( in_file, disk_buf_start, read_length );
2023 disk_buf_tail = disk_buf_start + disk_buf_len;
2024
2025 /* sync reader to this segment of the stream */
2026 p=disk_buf_start;
2027 if (sync_data_stream(&p))
2028 {
2029 DEBUGF("Could not sync stream\n");
2030 return PLUGIN_ERROR;
2031 }
2032
2033 /* find last PTS in audio stream; will movie always have audio? if
2034 the play time can not be determined, set end_pts_time to 0 */
2035 audio_sync_start = 0;
2036 audio_sync_time = 0;
2037 video_sync_start = 0;
2038 {
2039 Stream tmp;
2040 initialize_stream(&tmp,p,disk_buf_len-(disk_buf_start-p),0xc0);
2041
2042 do
2043 {
2044 get_next_data(&tmp, 2);
2045 if (tmp.tagged == 1)
2046 /* 10 sec less to insure the video frame exist */
2047 end_pts_time = (int)((tmp.curr_pts/45000-10)/30);
2048 }
2049 while (tmp.curr_packet_end != NULL);
2050 }
2051 return 0;
2052}
2053
2054ssize_t seek_PTS( int in_file, int start_time, int accept_button )
2055{
2056 static ssize_t last_seek_pos = 0;
2057 static int last_start_time = 0;
2058 ssize_t seek_pos;
2059 size_t disk_buf_len;
2060 uint8_t *p;
2061 size_t read_length = 60*1024;
2062
2063 /* temporary read buffer size cannot exceed buffer size */
2064 if ( read_length > disk_buf_size )
2065 read_length = disk_buf_size;
2066
2067 if ( start_time == last_start_time )
2068 {
2069 seek_pos = last_seek_pos;
2070 rb->lseek(in_file,seek_pos,SEEK_SET);
2071 }
2072 else if ( start_time != 0 )
2073 {
2074 seek_pos = rb->filesize(in_file)*start_time/
2075 (end_pts_time-start_pts_time);
2076 int seek_pos_sec_inc = rb->filesize(in_file)/
2077 (end_pts_time-start_pts_time)/30;
2078
2079 if (seek_pos<0)
2080 seek_pos=0;
2081 if ((size_t)seek_pos > rb->filesize(in_file) - read_length)
2082 seek_pos = rb->filesize(in_file) - read_length;
2083 rb->lseek( in_file, seek_pos, SEEK_SET );
2084 disk_buf_len = rb->read( in_file, disk_buf_start, read_length );
2085 disk_buf_tail = disk_buf_start + disk_buf_len;
2086
2087 /* sync reader to this segment of the stream */
2088 p=disk_buf_start;
2089 if (sync_data_stream(&p))
2090 {
2091 DEBUGF("Could not sync stream\n");
2092 return PLUGIN_ERROR;
2093 }
2094
2095 /* find PTS >= start_time */
2096 audio_sync_start = 0;
2097 audio_sync_time = 0;
2098 video_sync_start = 0;
2099 {
2100 Stream tmp;
2101 initialize_stream(&tmp,p,disk_buf_len-(disk_buf_start-p),0xc0);
2102 int cont_seek_loop = 1;
2103 int coarse_seek = 1;
2104 do
2105 {
2106 if ( accept_button )
2107 {
2108 rb->yield();
2109 if (rb->button_queue_count())
2110 return -101;
2111 }
2112
2113 while ( get_next_data(&tmp, 1) == 1 )
2114 {
2115 if ( tmp.curr_packet_end == disk_buf_start )
2116 seek_pos += disk_buf_tail - disk_buf_start;
2117 else
2118 seek_pos += tmp.curr_packet_end - disk_buf_start;
2119 if ((size_t)seek_pos > rb->filesize(in_file) - read_length)
2120 seek_pos = rb->filesize(in_file) - read_length;
2121 rb->lseek( in_file, seek_pos, SEEK_SET );
2122 disk_buf_len = rb->read ( in_file, disk_buf_start, read_length );
2123 disk_buf_tail = disk_buf_start + disk_buf_len;
2124
2125 /* sync reader to this segment of the stream */
2126 p=disk_buf_start;
2127 initialize_stream(&tmp,p,disk_buf_len,0xc0);
2128 }
2129
2130 /* are we after start_time in the stream? */
2131 if ( coarse_seek && (int)(tmp.curr_pts/45000) >=
2132 (start_time+start_pts_time)*30 )
2133 {
2134 int time_to_backup = (int)(tmp.curr_pts/45000) -
2135 (start_time+start_pts_time)*30;
2136 if (time_to_backup == 0)
2137 time_to_backup++;
2138 seek_pos -= seek_pos_sec_inc * time_to_backup;
2139 seek_pos_sec_inc -= seek_pos_sec_inc/20; /* for stability */
2140 if (seek_pos<0)
2141 seek_pos=0;
2142 if ((size_t)seek_pos > rb->filesize(in_file) - read_length)
2143 seek_pos = rb->filesize(in_file) - read_length;
2144 rb->lseek( in_file, seek_pos, SEEK_SET );
2145 disk_buf_len = rb->read( in_file, disk_buf_start, read_length );
2146 disk_buf_tail = disk_buf_start + disk_buf_len;
2147
2148 /* sync reader to this segment of the stream */
2149 p=disk_buf_start;
2150 if (sync_data_stream(&p))
2151 {
2152 DEBUGF("Could not sync stream\n");
2153 return PLUGIN_ERROR;
2154 }
2155 initialize_stream(&tmp,p,disk_buf_len-(disk_buf_start-p),0xc0);
2156 continue;
2157 }
2158
2159 /* are we well before start_time in the stream? */
2160 if ( coarse_seek && (start_time+start_pts_time)*30 -
2161 (int)(tmp.curr_pts/45000) > 2 )
2162 {
2163 int time_to_advance = (start_time+start_pts_time)*30 -
2164 (int)(tmp.curr_pts/45000) - 2;
2165 if (time_to_advance <= 0)
2166 time_to_advance = 1;
2167 seek_pos += seek_pos_sec_inc * time_to_advance;
2168 if (seek_pos<0)
2169 seek_pos=0;
2170 if ((size_t)seek_pos > rb->filesize(in_file) - read_length)
2171 seek_pos = rb->filesize(in_file) - read_length;
2172 rb->lseek( in_file, seek_pos, SEEK_SET );
2173 disk_buf_len = rb->read ( in_file, disk_buf_start, read_length );
2174 disk_buf_tail = disk_buf_start + disk_buf_len;
2175
2176 /* sync reader to this segment of the stream */
2177 p=disk_buf_start;
2178 if (sync_data_stream(&p))
2179 {
2180 DEBUGF("Could not sync stream\n");
2181 return PLUGIN_ERROR;
2182 }
2183 initialize_stream(&tmp,p,disk_buf_len-(disk_buf_start-p),0xc0);
2184 continue;
2185 }
2186
2187 coarse_seek = 0;
2188
2189 /* are we at start_time in the stream? */
2190 if ( (int)(tmp.curr_pts/45000) >= (start_time+start_pts_time)*
2191 30 )
2192 cont_seek_loop = 0;
2193
2194 }
2195 while ( cont_seek_loop );
2196
2197
2198 DEBUGF("start diff: %u %u\n",(unsigned int)(tmp.curr_pts/45000),
2199 (start_time+start_pts_time)*30);
2200 seek_pos+=tmp.curr_packet_end-disk_buf_start;
2201
2202 last_seek_pos = seek_pos;
2203 last_start_time = start_time;
2204
2205 rb->lseek(in_file,seek_pos,SEEK_SET);
2206 }
2207 }
2208 else
2209 {
2210 seek_pos = 0;
2211 rb->lseek(in_file,0,SEEK_SET);
2212 last_seek_pos = seek_pos;
2213 last_start_time = start_time;
2214 }
2215 return seek_pos;
2216}
2217
2218enum plugin_status plugin_start(struct plugin_api* api, void* parameter) 324enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
2219{ 325{
2220 int status = PLUGIN_ERROR; /* assume failure */ 326 int status = PLUGIN_ERROR; /* assume failure */
2221 int result; 327 int result;
2222 int start_time = -1; 328 int err;
2223 void* audiobuf; 329 const char *errstring;
2224 ssize_t audiosize;
2225 int in_file;
2226 size_t disk_buf_len;
2227 ssize_t seek_pos;
2228 size_t audio_stack_size = 0; /* Keep gcc happy and init */
2229 int i;
2230#ifndef HAVE_LCD_COLOR
2231 long graysize;
2232 int grayscales;
2233#endif
2234
2235 audio_sync_start = 0;
2236 audio_sync_time = 0;
2237 video_sync_start = 0;
2238 330
2239 if (parameter == NULL) 331 if (parameter == NULL) {
2240 { 332 /* No file = GTFO */
2241 api->splash(HZ*2, "No File"); 333 api->splash(HZ*2, "No File");
2242 return PLUGIN_ERROR; 334 return PLUGIN_ERROR;
2243 } 335 }
336
337 /* Disable all talking before initializing IRAM */
2244 api->talk_disable(true); 338 api->talk_disable(true);
2245 339
2246 /* Initialize IRAM - stops audio and voice as well */ 340 /* Initialize IRAM - stops audio and voice as well */
2247 PLUGIN_IRAM_INIT(api) 341 PLUGIN_IRAM_INIT(api)
2248 342
2249 rb = api; 343 rb = api;
2250 rb->splash(0, "Loading...");
2251
2252 /* sets audiosize and returns buffer pointer */
2253 audiobuf = rb->plugin_get_audio_buffer(&audiosize);
2254
2255#if INPUT_SRC_CAPS != 0
2256 /* Select playback */
2257 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2258 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
2259#endif
2260
2261 rb->pcm_set_frequency(SAMPR_44);
2262
2263#ifndef HAVE_LCD_COLOR
2264 /* initialize the grayscale buffer: 32 bitplanes for 33 shades of gray. */
2265 grayscales = gray_init(rb, audiobuf, audiosize, false, LCD_WIDTH, LCD_HEIGHT,
2266 32, 2<<8, &graysize) + 1;
2267 audiobuf += graysize;
2268 audiosize -= graysize;
2269 if (grayscales < 33 || audiosize <= 0)
2270 {
2271 rb->talk_disable(false);
2272 rb->splash(HZ, "gray buf error");
2273 return PLUGIN_ERROR;
2274 }
2275#endif
2276
2277 /* Initialise our malloc buffer */
2278 audiosize = mpeg_alloc_init(audiobuf,audiosize, LIBMPEG2BUFFER_SIZE);
2279 if (audiosize == 0)
2280 {
2281 rb->talk_disable(false);
2282 return PLUGIN_ERROR;
2283 }
2284
2285 /* Set disk pointers to NULL */
2286 disk_buf_end = disk_buf_start = NULL;
2287
2288 /* Grab most of the buffer for the compressed video - leave some for
2289 PCM audio data and some for libmpeg2 malloc use. */
2290 disk_buf_size = audiosize - (PCMBUFFER_SIZE+PCMBUFFER_GUARD_SIZE+
2291 MPABUF_SIZE);
2292
2293 DEBUGF("audiosize=%ld, disk_buf_size=%ld\n",audiosize,disk_buf_size);
2294 disk_buf_start = mpeg_malloc(disk_buf_size,-1);
2295
2296 if (disk_buf_start == NULL)
2297 {
2298 rb->talk_disable(false);
2299 return PLUGIN_ERROR;
2300 }
2301
2302 if (!init_mpabuf())
2303 {
2304 rb->talk_disable(false);
2305 return PLUGIN_ERROR;
2306 }
2307 if (!init_pcmbuf())
2308 {
2309 rb->talk_disable(false);
2310 return PLUGIN_ERROR;
2311 }
2312
2313 /* The remaining buffer is for use by libmpeg2 */
2314
2315 /* Open the video file */
2316 in_file = rb->open((char*)parameter,O_RDONLY);
2317
2318 if (in_file < 0){
2319 DEBUGF("Could not open %s\n",(char*)parameter);
2320 rb->talk_disable(false);
2321 return PLUGIN_ERROR;
2322 }
2323 filename = (char*)parameter;
2324 344
2325#ifdef HAVE_LCD_COLOR 345#ifdef HAVE_LCD_COLOR
2326 rb->lcd_set_backdrop(NULL); 346 rb->lcd_set_backdrop(NULL);
@@ -2328,239 +348,62 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
2328 rb->lcd_set_background(LCD_BLACK); 348 rb->lcd_set_background(LCD_BLACK);
2329#endif 349#endif
2330 350
2331 init_settings((char*)parameter);
2332
2333 /* Initialise libmad */
2334 rb->memset(mad_frame_overlap, 0, sizeof(mad_frame_overlap));
2335 init_mad(mad_frame_overlap);
2336
2337 disk_buf_end = disk_buf_start + disk_buf_size-MPEG_GUARDBUF_SIZE;
2338
2339 /* initalize start_pts_time and end_pts_time with the length (in half
2340 minutes) of the movie. zero if the time could not be determined */
2341 find_start_pts( in_file );
2342 find_end_pts( in_file );
2343
2344
2345 /* start menu */
2346 rb->lcd_clear_display(); 351 rb->lcd_clear_display();
2347 rb->lcd_update(); 352 rb->lcd_update();
2348 result = mpeg_start_menu(end_pts_time-start_pts_time, in_file);
2349
2350 switch (result)
2351 {
2352 case MPEG_START_QUIT:
2353 rb->talk_disable(false);
2354 return 0;
2355 default:
2356 start_time = settings.resume_time;
2357 break;
2358 }
2359
2360 /* basic time checks */
2361 if ( start_time < 0 )
2362 start_time = 0;
2363 else if ( start_time > (end_pts_time-start_pts_time) )
2364 start_time = (end_pts_time-start_pts_time);
2365
2366 /* Turn off backlight timeout */
2367 backlight_force_on(rb); /* backlight control in lib/helper.c */
2368
2369#ifdef HAVE_ADJUSTABLE_CPU_FREQ
2370 rb->cpu_boost(true);
2371#endif
2372
2373 /* From this point on we've altered settings, colors, cpu_boost, etc. and
2374 cannot just return PLUGIN_ERROR - instead drop though to cleanup code
2375 */
2376
2377#ifdef SIMULATOR
2378 /* The simulator thread implementation doesn't have stack buffers, and
2379 these parameters are ignored. */
2380 (void)i; /* Keep gcc happy */
2381 audio_stack = NULL;
2382 audio_stack_size = 0;
2383#else
2384 /* Borrow the codec thread's stack (in IRAM on most targets) */
2385 audio_stack = NULL;
2386 for (i = 0; i < MAXTHREADS; i++)
2387 {
2388 if (rb->strcmp(rb->threads[i].name,"codec")==0)
2389 {
2390 /* Wait to ensure the codec thread has blocked */
2391 while (rb->threads[i].state!=STATE_BLOCKED)
2392 rb->yield();
2393
2394 /* Now we can steal the stack */
2395 audio_stack = rb->threads[i].stack;
2396 audio_stack_size = rb->threads[i].stack_size;
2397
2398 /* Backup the codec thread's stack */
2399 rb->memcpy(codec_stack_copy,audio_stack,audio_stack_size);
2400
2401 break;
2402 }
2403 }
2404
2405 if (audio_stack == NULL)
2406 {
2407 /* This shouldn't happen, but deal with it anyway by using
2408 the copy instead */
2409 audio_stack = codec_stack_copy;
2410 audio_stack_size = AUDIO_STACKSIZE;
2411 }
2412#endif
2413
2414 rb->splash(0, "Loading...");
2415
2416 /* seek start time */
2417 seek_pos = seek_PTS( in_file, start_time, 0 );
2418
2419 video_thumb_print = 0;
2420 audio_sync_start = 0;
2421 audio_sync_time = 0;
2422 video_sync_start = 0;
2423 353
2424 /* Read some stream data */ 354 if (stream_init() < STREAM_OK) {
2425 disk_buf_len = rb->read (in_file, disk_buf_start, disk_buf_size - MPEG_GUARDBUF_SIZE); 355 DEBUGF("Could not initialize streams\n");
356 } else {
357 rb->splash(0, "Loading...");
2426 358
2427 disk_buf_tail = disk_buf_start + disk_buf_len; 359 init_settings((char*)parameter);
2428 file_remaining = rb->filesize(in_file);
2429 file_remaining -= disk_buf_len + seek_pos;
2430 360
2431 initialize_stream( &video_str, disk_buf_start, disk_buf_len, 0xe0 ); 361 err = stream_open((char *)parameter);
2432 initialize_stream( &audio_str, disk_buf_start, disk_buf_len, 0xc0 );
2433 362
2434 rb->mutex_init(&audio_str.msg_lock); 363 if (err >= STREAM_OK) {
2435 rb->mutex_init(&video_str.msg_lock); 364 /* start menu */
365 rb->lcd_clear_display();
366 rb->lcd_update();
367 result = mpeg_start_menu(stream_get_duration());
2436 368
2437 audio_str.status = STREAM_BUFFERING; 369 if (result != MPEG_START_QUIT) {
2438 video_str.status = STREAM_PLAYING; 370 /* Turn off backlight timeout */
371 /* backlight control in lib/helper.c */
372 backlight_force_on(rb);
2439 373
2440#ifndef HAVE_LCD_COLOR 374 /* Enter button loop and process UI */
2441 gray_show(true); 375 if (button_loop()) {
2442#endif 376 settings.resume_time = stream_get_resume_time();
377 }
2443 378
2444 init_stream_lock(); 379 /* Turn on backlight timeout (revert to settings) */
380 backlight_use_settings(rb);
381 }
2445 382
2446#if NUM_CORES > 1 383 stream_close();
2447 flush_icache();
2448#endif
2449 384
2450 /* We put the video thread on the second processor for multi-core targets. */ 385 rb->lcd_clear_display();
2451 if ((video_str.thread = rb->create_thread(video_thread, 386 rb->lcd_update();
2452 (uint8_t*)video_stack, VIDEO_STACKSIZE, 0,
2453 "mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK) IF_COP(, COP))) == NULL)
2454 {
2455 rb->splash(HZ, "Cannot create video thread!");
2456 }
2457 else if ((audio_str.thread = rb->create_thread(audio_thread,
2458 (uint8_t*)audio_stack,audio_stack_size, 0,"mpgaudio"
2459 IF_PRIO(,PRIORITY_PLAYBACK) IF_COP(, CPU))) == NULL)
2460 {
2461 rb->splash(HZ, "Cannot create audio thread!");
2462 }
2463 else
2464 {
2465 rb->lcd_setfont(FONT_SYSFIXED);
2466
2467 /* Wait until both threads have finished their work */
2468 while ((audio_str.status >= 0) || (video_str.status >= 0))
2469 {
2470 size_t audio_remaining = audio_str.buffer_remaining;
2471 size_t video_remaining = video_str.buffer_remaining;
2472 387
2473 if (MIN(audio_remaining,video_remaining) < MPEG_LOW_WATERMARK) 388 save_settings(); /* Save settings (if they have changed) */
389 status = PLUGIN_OK;
390 } else {
391 DEBUGF("Could not open %s\n", (char*)parameter);
392 switch (err)
2474 { 393 {
2475 394 case STREAM_UNSUPPORTED:
2476 size_t bytes_to_read = disk_buf_size - MPEG_GUARDBUF_SIZE - 395 errstring = "Unsupported format";
2477 MAX(audio_remaining,video_remaining); 396 break;
2478 397 default:
2479 bytes_to_read = MIN(bytes_to_read,(size_t)(disk_buf_end-disk_buf_tail)); 398 errstring = "Error opening file: %d";
2480
2481 while (( bytes_to_read > 0) && (file_remaining > 0) &&
2482 ((audio_str.status != STREAM_DONE) || (video_str.status != STREAM_DONE)))
2483 {
2484
2485 size_t n;
2486 if ( video_sync_start != 0 )
2487 n = rb->read(in_file, disk_buf_tail, MIN(32*1024,bytes_to_read));
2488 else
2489 {
2490 n = rb->read(in_file, disk_buf_tail,bytes_to_read);
2491 if (n==0)
2492 rb->splash(30,"buffer fill error");
2493 }
2494
2495 bytes_to_read -= n;
2496 file_remaining -= n;
2497
2498 lock_stream();
2499 audio_str.buffer_remaining += n;
2500 video_str.buffer_remaining += n;
2501 unlock_stream();
2502
2503 disk_buf_tail += n;
2504
2505 rb->yield();
2506 }
2507
2508 if (disk_buf_tail == disk_buf_end)
2509 disk_buf_tail = disk_buf_start;
2510 } 399 }
2511 400
2512 rb->sleep(HZ/10); 401 rb->splash(HZ*2, errstring, err);
2513 } 402 }
2514
2515 rb->lcd_setfont(FONT_UI);
2516 status = PLUGIN_OK;
2517 }
2518
2519 /* Stop the threads and wait for them to terminate */
2520 if (video_str.thread != NULL)
2521 {
2522 str_send_msg(&video_str, STREAM_QUIT, 0);
2523 rb->thread_wait(video_str.thread);
2524 } 403 }
2525 404
2526 if (audio_str.thread != NULL) 405 stream_exit();
2527 {
2528 str_send_msg(&audio_str, STREAM_QUIT, 0);
2529 rb->thread_wait(audio_str.thread);
2530 }
2531
2532#if NUM_CORES > 1
2533 invalidate_icache();
2534#endif
2535
2536 vo_cleanup();
2537
2538#ifndef HAVE_LCD_COLOR
2539 gray_release();
2540#endif
2541
2542 rb->lcd_clear_display();
2543 rb->lcd_update();
2544
2545 mpeg2_close (mpeg2dec);
2546
2547 rb->close (in_file);
2548
2549#ifndef SIMULATOR
2550 /* Restore the codec thread's stack */
2551 rb->memcpy(audio_stack, codec_stack_copy, audio_stack_size);
2552#endif
2553
2554#ifdef HAVE_ADJUSTABLE_CPU_FREQ
2555 rb->cpu_boost(false);
2556#endif
2557
2558 save_settings(); /* Save settings (if they have changed) */
2559
2560 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
2561 406
2562 /* Turn on backlight timeout (revert to settings) */
2563 backlight_use_settings(rb); /* backlight control in lib/helper.c */
2564 rb->talk_disable(false); 407 rb->talk_disable(false);
2565 return status; 408 return status;
2566} 409}