2 * mpegplayer.c - based on :
4 * - m2psd.c (http://www.brouhaha.com/~eric/software/m2psd/)
6 * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
7 * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
9 * m2psd: MPEG 2 Program Stream Demultiplexer
10 * Copyright (C) 2003 Eric Smith <eric@brouhaha.com>
12 * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
13 * See http://libmpeg2.sourceforge.net/ for updates.
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.
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.
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
34 mpegplayer is structured as follows:
36 1) Video thread (running on the COP for PortalPlayer targets).
37 2) Audio thread (running on the main CPU to maintain consistency with
38 the audio FIQ hander on PP).
39 3) The main thread which takes care of buffering.
41 Using the main thread for buffering wastes the 8KB main stack which is
42 in IRAM. However, 8KB is not enough for the audio thread to run (it
43 needs somewhere between 8KB and 9KB), so we create a new thread in
44 order to`give it a larger stack.
46 We use 4.5KB of the main stack for a libmad buffer (making use of
47 otherwise unused IRAM). There is also the possiblity of stealing the
48 main Rockbox codec thread's 9KB of IRAM stack and using that for
49 mpegplayer's audio thread - but we should only implement that if we
50 can put the IRAM to good use.
52 The button loop (and hence pause/resume, main menu and, in the future,
53 seeking) is placed in the audio thread. This keeps it on the main CPU
54 in PP targets and also allows buffering to continue in the background
55 whilst the main thread is filling the buffer.
57 A/V sync is not yet implemented but is planned to be achieved by
58 syncing the master clock with the audio, and then (as is currently
59 implemented), syncing video with the master clock. This can happen in
60 the audio thread, along with resyncing after pause.
62 Seeking should probably happen in the main thread, as that's where the
65 On PortalPlayer targets, the main CPU is not being fully utilised -
66 the bottleneck is the video decoding on the COP. One way to improve
67 that might be to move the rendering of the frames (i.e. the
68 lcd_yuv_blit() call) from the COP back to the main CPU. Ideas and
69 patches for that are welcome!
71 Notes about MPEG files:
73 MPEG System Clock is 27MHz - i.e. 27000000 ticks/second.
75 FPS is represented in terms of a frame period - this is always an
76 integer number of 27MHz ticks.
78 e.g. 29.97fps (30000/1001) NTSC video has an exact frame period of
81 In libmpeg2, info->sequence->frame_period contains the frame_period.
83 Working with Rockbox's 100Hz tick, the common frame rates would need
86 FPS | 27Mhz | 100Hz | 44.1KHz | 48KHz
87 --------|-----------------------------------------------------------
88 10* | 2700000 | 10 | 4410 | 4800
89 12* | 2250000 | 8.3333 | 3675 | 4000
90 15* | 1800000 | 6.6667 | 2940 | 3200
91 23.9760 | 1126125 | 4.170833333 | 1839.3375 | 2002
92 24 | 1125000 | 4.166667 | 1837.5 | 2000
93 25 | 1080000 | 4 | 1764 | 1920
94 29.9700 | 900900 | 3.336667 | 1471,47 | 1601.6
95 30 | 900000 | 3.333333 | 1470 | 1600
98 *Unofficial framerates
103 #include "mpeg2dec_config.h"
109 #include "mpeg_settings.h"
110 #include "video_out.h"
111 #include "../../codecs/libmad/mad.h"
116 /* button definitions */
117 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
118 #define MPEG_MENU BUTTON_MODE
119 #define MPEG_STOP BUTTON_OFF
120 #define MPEG_PAUSE BUTTON_ON
121 #define MPEG_VOLDOWN BUTTON_DOWN
122 #define MPEG_VOLUP BUTTON_UP
124 #elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD)
125 #define MPEG_MENU BUTTON_MENU
126 #define MPEG_PAUSE (BUTTON_PLAY | BUTTON_REL)
127 #define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT)
128 #define MPEG_VOLDOWN BUTTON_SCROLL_BACK
129 #define MPEG_VOLUP BUTTON_SCROLL_FWD
131 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
132 #define MPEG_MENU (BUTTON_REC | BUTTON_REL)
133 #define MPEG_STOP BUTTON_POWER
134 #define MPEG_PAUSE BUTTON_PLAY
135 #define MPEG_VOLDOWN BUTTON_DOWN
136 #define MPEG_VOLUP BUTTON_UP
138 #elif CONFIG_KEYPAD == GIGABEAT_PAD
139 #define MPEG_MENU BUTTON_MENU
140 #define MPEG_STOP BUTTON_A
141 #define MPEG_PAUSE BUTTON_SELECT
142 #define MPEG_VOLDOWN BUTTON_LEFT
143 #define MPEG_VOLUP BUTTON_RIGHT
144 #define MPEG_VOLDOWN2 BUTTON_VOL_DOWN
145 #define MPEG_VOLUP2 BUTTON_VOL_UP
147 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
148 #define MPEG_MENU (BUTTON_REW | BUTTON_REL)
149 #define MPEG_STOP BUTTON_POWER
150 #define MPEG_PAUSE BUTTON_PLAY
151 #define MPEG_VOLDOWN BUTTON_SCROLL_DOWN
152 #define MPEG_VOLUP BUTTON_SCROLL_UP
154 #elif CONFIG_KEYPAD == SANSA_E200_PAD
155 #define MPEG_MENU BUTTON_SELECT
156 #define MPEG_STOP BUTTON_POWER
157 #define MPEG_PAUSE BUTTON_UP
158 #define MPEG_VOLDOWN BUTTON_SCROLL_UP
159 #define MPEG_VOLUP BUTTON_SCROLL_DOWN
162 #error MPEGPLAYER: Unsupported keypad
165 struct plugin_api
* rb
;
167 static mpeg2dec_t
* mpeg2dec
;
168 static int total_offset
= 0;
173 uint8_t* curr_packet
; /* Current stream packet beginning */
174 uint8_t* curr_packet_end
; /* Current stream packet end */
176 uint8_t* prev_packet
; /* Previous stream packet beginning */
177 uint8_t* next_packet
; /* Next stream packet beginning */
179 size_t guard_bytes
; /* Number of bytes in guardbuf used */
180 size_t buffer_remaining
; /* How much data is left in the buffer */
186 static Stream audio_str IBSS_ATTR
;
187 static Stream video_str IBSS_ATTR
;
189 /* NOTE: Putting the following variables in IRAM cause audio corruption
190 on the ipod (reason unknown)
192 static uint8_t *disk_buf
, *disk_buf_end
;
193 static uint8_t *disk_buf_tail IBSS_ATTR
;
194 static size_t buffer_size IBSS_ATTR
;
197 static struct event_queue msg_queue IBSS_ATTR
;
199 #define MSG_BUFFER_NEARLY_EMPTY 1
200 #define MSG_EXIT_REQUESTED 2
203 static struct thread_entry
* audiothread_id
;
204 static struct thread_entry
* videothread_id
;
207 #define STREAM_PLAYING 0
208 #define STREAM_DONE 1
209 #define STREAM_PAUSING 2
210 #define STREAM_BUFFERING 3
211 #define STREAM_ERROR 4
212 #define PLEASE_STOP 5
213 #define PLEASE_PAUSE 6
215 int audiostatus IBSS_ATTR
;
216 int videostatus IBSS_ATTR
;
218 /* Various buffers */
219 /* TODO: Can we reduce the PCM buffer size? */
220 #define PCMBUFFER_SIZE (512*1024)
221 #define AUDIOBUFFER_SIZE (32*1024)
222 #define LIBMPEG2BUFFER_SIZE (2*1024*1024)
224 /* TODO: Is 32KB enough? */
225 #define MPEG_GUARDBUF_SIZE (32*1024)
226 #define MPEG_LOW_WATERMARK (1024*1024)
228 static void button_loop(void)
231 int vol
, minvol
, maxvol
;
232 int button
= rb
->button_get(false);
237 case MPEG_VOLUP
|BUTTON_REPEAT
:
240 case MPEG_VOLUP2
|BUTTON_REPEAT
:
242 vol
= rb
->global_settings
->volume
;
243 maxvol
= rb
->sound_max(SOUND_VOLUME
);
247 rb
->sound_set(SOUND_VOLUME
, vol
);
248 rb
->global_settings
->volume
= vol
;
253 case MPEG_VOLDOWN
|BUTTON_REPEAT
:
256 case MPEG_VOLDOWN2
|BUTTON_REPEAT
:
258 vol
= rb
->global_settings
->volume
;
259 minvol
= rb
->sound_min(SOUND_VOLUME
);
263 rb
->sound_set(SOUND_VOLUME
, vol
);
264 rb
->global_settings
->volume
= vol
;
269 rb
->pcm_play_pause(false);
270 if (videostatus
!= STREAM_DONE
) {
271 videostatus
=PLEASE_PAUSE
;
273 /* Wait for video thread to stop */
274 while (videostatus
== PLEASE_PAUSE
) { rb
->sleep(HZ
/25); }
277 #ifndef HAVE_LCD_COLOR
280 result
= mpeg_menu();
282 #ifndef HAVE_LCD_COLOR
286 /* The menu can change the font, so restore */
287 rb
->lcd_setfont(FONT_SYSFIXED
);
290 audiostatus
= PLEASE_STOP
;
291 if (videostatus
!= STREAM_DONE
) videostatus
= PLEASE_STOP
;
293 if (videostatus
!= STREAM_DONE
) videostatus
= STREAM_PLAYING
;
294 rb
->pcm_play_pause(true);
299 audiostatus
= PLEASE_STOP
;
300 if (videostatus
!= STREAM_DONE
) videostatus
= PLEASE_STOP
;
304 if (videostatus
!= STREAM_DONE
) videostatus
=PLEASE_PAUSE
;
305 rb
->pcm_play_pause(false);
307 button
= BUTTON_NONE
;
308 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
309 rb
->cpu_boost(false);
312 button
= rb
->button_get(true);
313 if (button
== MPEG_STOP
) {
314 audiostatus
= PLEASE_STOP
;
315 if (videostatus
!= STREAM_DONE
) videostatus
= PLEASE_STOP
;
318 } while (button
!= MPEG_PAUSE
);
320 if (videostatus
!= STREAM_DONE
) videostatus
= STREAM_PLAYING
;
321 rb
->pcm_play_pause(true);
322 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
328 if(rb
->default_event_handler(button
) == SYS_USB_CONNECTED
) {
329 audiostatus
= PLEASE_STOP
;
330 if (videostatus
!= STREAM_DONE
) videostatus
= PLEASE_STOP
;
335 /* libmad related functions/definitions */
336 #define INPUT_CHUNK_SIZE 8192
338 struct mad_stream stream IBSS_ATTR
;
339 struct mad_frame frame IBSS_ATTR
;
340 struct mad_synth synth IBSS_ATTR
;
342 unsigned char mad_main_data
[MAD_BUFFER_MDLEN
]; /* 2567 bytes */
344 static void init_mad(void* mad_frame_overlap
)
346 rb
->memset(&stream
, 0, sizeof(struct mad_stream
));
347 rb
->memset(&frame
, 0, sizeof(struct mad_frame
));
348 rb
->memset(&synth
, 0, sizeof(struct mad_synth
));
350 mad_stream_init(&stream
);
351 mad_frame_init(&frame
);
353 /* We do this so libmad doesn't try to call codec_calloc() */
354 frame
.overlap
= mad_frame_overlap
;
356 rb
->memset(mad_main_data
, 0, sizeof(mad_main_data
));
357 stream
.main_data
= &mad_main_data
;
360 /* MPEG related headers */
361 uint8_t packet_start_code_prefix
[3] = { 0x00, 0x00, 0x01 };
362 uint8_t end_code
[4] = { 0x00, 0x00, 0x01, 0xb9 };
363 uint8_t pack_start_code
[4] = { 0x00, 0x00, 0x01, 0xba };
364 uint8_t system_header_start_code
[4] = { 0x00, 0x00, 0x01, 0xbb };
366 /* This function demux the streams and give the next stream data pointer */
367 static void get_next_data( Stream
* str
)
373 static int mpeg1_skip_table
[16] = {
374 0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
377 if (str
->curr_packet_end
== NULL
) {
378 /* What does this do? */
379 while( (p
= disk_buf
) == NULL
)
381 rb
->lcd_putsxy(0,LCD_HEIGHT
-10,"FREEZE!");
386 p
= str
->curr_packet_end
;
393 if( p
>= disk_buf_end
)
395 p
= disk_buf
+ (p
- disk_buf_end
);
398 /* Pack header, skip it */
399 if( rb
->memcmp (p
, pack_start_code
, sizeof (pack_start_code
)) == 0 )
401 if ((p
[4] & 0xc0) == 0x40) { /* mpeg-2 */
402 p
+= 14 + (p
[13] & 7);
403 } else if ((p
[4] & 0xf0) == 0x20) { /* mpeg-1 */
406 rb
->splash( 30, "Weird Pack header!" );
409 /*rb->splash( 30, "Pack header" );*/
412 /* System header, parse and skip it */
413 if( rb
->memcmp (p
, system_header_start_code
, sizeof (system_header_start_code
)) == 0 )
417 p
+= 4; /*skip start code*/
418 header_length
= (*(p
++)) << 8;
419 header_length
+= *(p
++);
422 /*rb->splash( 30, "System header" );*/
425 /* Packet header, parse it */
426 if( rb
->memcmp (p
, packet_start_code_prefix
, sizeof (packet_start_code_prefix
)) != 0 )
429 //rb->splash( HZ*3, "missing packet start code prefix : %X%X at %X", *p, *(p+2), p-disk_buf );
430 str
->curr_packet_end
= str
->curr_packet
= NULL
;
436 /* We retrieve basic infos */
438 length
= (*(p
+4)) << 8;
441 /*rb->splash( 100, "Stream : %X", stream );*/
442 if (stream
!= str
->id
)
444 /* End of stream ? */
447 str
->curr_packet_end
= str
->curr_packet
= NULL
;
451 /* It's not the packet we're looking for, skip it */
456 /* Ok, it's our packet */
457 str
->curr_packet_end
= p
+ length
+6;
459 if ((header
[6] & 0xc0) == 0x80) { /* mpeg2 */
461 length
= 9 + header
[8];
462 /* header points to the mpeg2 pes header */
463 if (header
[7] & 0x80) {
466 pts
= (((header
[9] >> 1) << 30) |
467 (header
[10] << 22) | ((header
[11] >> 1) << 15) |
468 (header
[12] << 7) | (header
[13] >> 1));
470 if (str
->first_pts
==0)
471 str
->first_pts
= pts
;
475 dts
= (!(header
[7] & 0x40) ? pts
:
476 ((uint32_t)(((header
[14] >> 1) << 30) |
478 ((header
[16] >> 1) << 15) |
479 (header
[17] << 7) | (header
[18] >> 1))));
482 mpeg2_tag_picture (mpeg2dec
, pts
, dts
);
489 while (header
[length
- 1] == 0xff)
494 rb
->splash( 30, "Too much stuffing" );
495 DEBUGF("Too much stuffing" );
499 if ((header
[length
- 1] & 0xc0) == 0x40)
504 length
+= mpeg1_skip_table
[header
[length
- 1] >> 4];
506 /* header points to the mpeg1 pes header */
507 ptsbuf
= header
+ len_skip
;
508 if ((ptsbuf
[-1] & 0xe0) == 0x20)
512 pts
= (((ptsbuf
[-1] >> 1) << 30) |
513 (ptsbuf
[0] << 22) | ((ptsbuf
[1] >> 1) << 15) |
514 (ptsbuf
[2] << 7) | (ptsbuf
[3] >> 1));
516 if (str
->first_pts
==0)
517 str
->first_pts
= pts
;
521 dts
= (((ptsbuf
[-1] & 0xf0) != 0x30) ? pts
:
522 ((uint32_t)(((ptsbuf
[4] >> 1) << 30) |
523 (ptsbuf
[5] << 22) | ((ptsbuf
[6] >> 1) << 15) |
524 (ptsbuf
[7] << 7) | (ptsbuf
[18] >> 1))));
527 mpeg2_tag_picture (mpeg2dec
, pts
, dts
);
532 bytes
= 6 + (header
[4] << 8) + header
[5] - length
;
534 str
->curr_packet_end
= p
+bytes
;
535 //DEBUGF("prev = %d, curr = %d\n",str->prev_packet,str->curr_packet);
537 if (str
->curr_packet
!= NULL
) {
538 if (str
->curr_packet
< str
->prev_packet
) {
539 str
->buffer_remaining
-= (disk_buf_end
- str
->prev_packet
) + (str
->curr_packet
- disk_buf
);
540 str
->buffer_remaining
-= str
->guard_bytes
;
541 str
->guard_bytes
= 0;
543 str
->buffer_remaining
-= (str
->curr_packet
- str
->prev_packet
);
546 str
->prev_packet
= str
->curr_packet
;
549 str
->curr_packet
= p
;
551 if( str
->curr_packet_end
> disk_buf_end
)
553 str
->guard_bytes
= str
->curr_packet_end
-disk_buf_end
;
554 rb
->memcpy(disk_buf_end
,disk_buf
,str
->guard_bytes
);
564 size_t mpa_buffer_size
;
566 static volatile int madpcm_playing IBSS_ATTR
;
567 static volatile int16_t* pcm_buffer IBSS_ATTR
;
568 static volatile size_t pcm_buffer_size IBSS_ATTR
;
570 static volatile size_t pcmbuf_len IBSS_ATTR
;
571 static volatile int16_t* pcmbuf_end IBSS_ATTR
;
572 static volatile int16_t* pcmbuf_head IBSS_ATTR
;
573 static volatile int16_t* pcmbuf_tail IBSS_ATTR
;
575 static volatile uint32_t samplesplayed IBSS_ATTR
;
576 static volatile int delay IBSS_ATTR
;
578 static void init_pcmbuf(void)
580 pcmbuf_head
= pcm_buffer
;
582 pcmbuf_tail
= pcm_buffer
;
583 pcmbuf_end
= pcm_buffer
+ pcm_buffer_size
/ sizeof(int16_t);
587 static void get_more(unsigned char** start
, size_t* size
)
589 if (pcmbuf_len
< 32*1024) {
595 *start
= (unsigned char*)(pcmbuf_tail
);
597 pcmbuf_tail
+= (32*1024)/sizeof(int16_t);
598 pcmbuf_len
-= 32*1024;
599 if (pcmbuf_tail
>= pcmbuf_end
) { pcmbuf_tail
= pcm_buffer
; }
601 /* Update master clock */
602 samplesplayed
+= (32*1024)/4;
608 static void audio_thread(void)
616 int file_end
= 0; /* A count of the errors in each frame */
618 int found_avdelay
= 0;
619 int avdelay
= 0; /* Number of audio samples difference between first audio and video PTS values. */
620 int64_t apts_samples
;
621 uint32_t samplesdecoded
= 0;
623 /* We need this here to init the EMAC for Coldfire targets */
624 mad_synth_init(&synth
);
628 /* This is the decoding loop. */
632 if (!found_avdelay
) {
633 if ((audio_str
.first_pts
!= 0) && (video_str
.first_pts
!= 0)) {
634 avdelay
= audio_str
.first_pts
- video_str
.first_pts
;
638 DEBUGF("First Audio PTS = %u, First Video PTS=%u, A-V=%d samples\n",(unsigned int)audio_str
.first_pts
,(unsigned int)video_str
.first_pts
,avdelay
);
642 if (audiostatus
== PLEASE_STOP
) {
646 if (n
< 1500) { /* TODO: What is the maximum size of an MPEG audio frame? */
647 get_next_data( &audio_str
);
648 if (audio_str
.curr_packet
== NULL
) {
649 /* Wait for audio to finish */
650 while (pcmbuf_len
> 0) { rb
->sleep(HZ
/10); }
654 len
= audio_str
.curr_packet_end
- audio_str
.curr_packet
;
655 if (n
+ len
> mpa_buffer_size
) {
656 rb
->splash( 30, "Audio buffer overflow" );
657 DEBUGF("Audio buffer overflow" );
658 audiostatus
=STREAM_DONE
;
659 /* Wait to be killed */
660 for (;;) { rb
->sleep(HZ
); }
662 rb
->memcpy(mpa_buffer
+n
,audio_str
.curr_packet
,len
);
667 if (stream
.error
== 0) {
668 mad_stream_buffer(&stream
, mpa_buffer
, n
);
671 if (mad_frame_decode(&frame
, &stream
)) {
672 DEBUGF("Audio stream error - %d\n",stream
.error
);
673 if (stream
.error
== MAD_FLAG_INCOMPLETE
674 || stream
.error
== MAD_ERROR_BUFLEN
) {
675 /* This makes the codec support partially corrupted files */
680 /* The mpa.c version: */
681 if (stream
.next_frame
)
682 inputbuffer
= stream
.next_frame
;
690 } else if (MAD_RECOVERABLE(stream
.error
)) {
693 /* Some other unrecoverable error */
694 DEBUGF("Unrecoverable error\n");
702 mad_synth_frame(&synth
, &frame
);
704 /* TODO: Don't memmove so much... */
705 if (stream
.next_frame
) {
706 len
= stream
.next_frame
- mpa_buffer
;
707 rb
->memmove(mpa_buffer
,stream
.next_frame
,n
-len
);
710 /* What to do here? */
711 DEBUGF("/* What to do here? */\n");
715 /* The mpa.c version: */
716 if (stream
.next_frame
)
717 inputbuffer
= stream
.next_frame
;
719 inputbuffer
= inputbuffer_end
;
722 framelength
= synth
.pcm
.length
;
723 samplesdecoded
+= framelength
;
726 apts_samples
= (audio_str
.curr_pts
-audio_str
.first_pts
);
727 apts_samples
*= 44100;
728 apts_samples
/= 90000;
729 delay
= (int)(avdelay
+apts_samples
-samplesdecoded
);
730 //DEBUGF("delay=%d\n",delay);
733 if (framelength
> 0) {
734 /* Leave at least 32KB free (this will be the currently playing chunk) */
735 while (pcmbuf_len
+ framelength
*4 + 32*1024 > pcm_buffer_size
) { rb
->yield(); }
737 if (MAD_NCHANNELS(&frame
.header
) == 2) {
738 left
= &synth
.pcm
.samples
[0][0];
739 right
= &synth
.pcm
.samples
[1][0];
740 for (i
= 0 ; i
< framelength
; i
++) {
741 /* libmad outputs s3.28 */
742 sample
= *(left
++) >> 13;
745 else if (sample
< -32768)
747 *(pcmbuf_head
++) = sample
;
749 sample
= *(right
++) >> 13;
752 else if (sample
< -32768)
754 *(pcmbuf_head
++) = sample
;
756 if (pcmbuf_head
>= pcmbuf_end
) { pcmbuf_head
= pcm_buffer
; }
759 left
= &synth
.pcm
.samples
[0][0];
760 for (i
= 0 ; i
< framelength
; i
++) {
761 sample
= *(left
++) >> 13;
765 else if (sample
< -32768)
768 *(pcmbuf_head
++) = sample
;
769 *(pcmbuf_head
++) = sample
;
770 if (pcmbuf_head
>= pcmbuf_end
) { pcmbuf_head
= pcm_buffer
; }
774 /* TODO: Disable interrupts for Coldfire? */
776 /* pcmbuf_len is also modified by the FIQ handler (in
777 get_more), so we disable the FIQ TODO: Add sempahore so we
778 don't change whilst get_more is running. */
783 pcmbuf_len
+= framelength
*4;
787 if ((!madpcm_playing
) && (pcmbuf_len
> 64*1024)) {
789 rb
->pcm_play_data(get_more
,NULL
,0);
790 audiostatus
= STREAM_PLAYING
;
798 audiostatus
=STREAM_DONE
;
806 /* End of libmad stuff */
808 static int64_t eta IBSS_ATTR
;
810 /* TODO: Running in the main thread, libmad needs 8.25KB of stack.
811 The codec thread uses a 9KB stack. So we can probable reduce this a
812 little, but leave at 9KB for now to be safe. */
813 #define AUDIO_STACKSIZE (9*1024)
814 uint32_t audio_stack
[AUDIO_STACKSIZE
/ sizeof(uint32_t)] IBSS_ATTR
;
816 /* TODO: Check if 4KB is appropriate - it works for my test streams,
817 so maybe we can reduce it. */
818 #define VIDEO_STACKSIZE (4*1024)
819 static uint32_t video_stack
[VIDEO_STACKSIZE
/ sizeof(uint32_t)] IBSS_ATTR
;
821 static void video_thread(void)
823 const mpeg2_info_t
* info
;
835 mpeg2dec
= mpeg2_init ();
837 if (mpeg2dec
== NULL
) {
838 videostatus
= STREAM_ERROR
;
839 rb
->splash(0, "mpeg2_init failed");
841 rb
->remove_thread(NULL
);
844 /* Clear the display - this is mainly just to indicate that the
845 video thread has started successfully. */
846 rb
->lcd_clear_display();
849 /* Used to decide when to display FPS */
850 lasttick
= *rb
->current_tick
- HZ
;
852 /* Request the first packet data */
853 get_next_data( &video_str
);
854 mpeg2_buffer (mpeg2dec
, video_str
.curr_packet
, video_str
.curr_packet_end
);
855 total_offset
+= video_str
.curr_packet_end
- video_str
.curr_packet
;
857 info
= mpeg2_info (mpeg2dec
);
859 if (videostatus
== PLEASE_STOP
) {
861 } else if (videostatus
== PLEASE_PAUSE
) {
862 videostatus
= STREAM_PAUSING
;
863 while (videostatus
== STREAM_PAUSING
) { rb
->sleep(HZ
/10); }
865 state
= mpeg2_parse (mpeg2dec
);
870 /* Request next packet data */
871 get_next_data( &video_str
);
872 mpeg2_buffer (mpeg2dec
, video_str
.curr_packet
, video_str
.curr_packet_end
);
873 total_offset
+= video_str
.curr_packet_end
- video_str
.curr_packet
;
874 info
= mpeg2_info (mpeg2dec
);
875 if (video_str
.curr_packet
== NULL
) {
882 vo_setup(info
->sequence
);
883 mpeg2_skip (mpeg2dec
, false);
890 case STATE_INVALID_END
:
891 /* draw current picture */
892 if (info
->display_fbuf
) {
893 /* Wait if the audio thread is buffering - i.e. before
894 the first frames are decoded */
895 while (audiostatus
== STREAM_BUFFERING
) {
898 eta
+= (info
->sequence
->frame_period
);
900 /* Convert eta (in 27MHz ticks) into audio samples */
901 eta2
=(eta
* 44100) / 27000000;
905 s
= samplesplayed
- (rb
->pcm_get_bytes_waiting() >> 2);
906 if (settings
.limitfps
) {
908 rb
->sleep(4); //((eta2-s)*HZ)/44100);
912 /* If we are more than 3/20 second behind schedule (and
913 more than 3/20 second into the decoding), skip frame.
914 But don't skip more than 10 consecutive frames. */
915 if (settings
.skipframes
&& (s
> ((3*44100)/20)) &&
916 (eta2
< (s
- ((3*44100)/20))) && (skipcount
< 10)) {
920 vo_draw_frame(info
->display_fbuf
->buf
);
926 if (settings
.showfps
&& (*rb
->current_tick
-lasttick
>=HZ
)) {
930 rb
->snprintf(str
,sizeof(str
),"%d.%d %d %d",
931 (int)(fps
/10),(int)(fps
%10),skipped
,delay
);
932 rb
->lcd_putsxy(0,0,str
);
933 rb
->lcd_update_rect(0,0,LCD_WIDTH
,8);
935 lasttick
= *rb
->current_tick
;
947 videostatus
= STREAM_DONE
;
949 rb
->remove_thread(NULL
);
952 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
958 size_t audio_remaining
, video_remaining
;
959 size_t bytes_to_read
;
960 size_t file_remaining
;
963 #ifndef HAVE_LCD_COLOR
968 /* We define this here so it is on the main stack (in IRAM) */
969 mad_fixed_t mad_frame_overlap
[2][32][18]; /* 4608 bytes */
971 /* This also stops audio playback - so we do it before using IRAM */
972 audiobuf
= api
->plugin_get_audio_buffer(&audiosize
);
974 PLUGIN_IRAM_INIT(api
)
977 /* Set disk pointers to NULL */
978 disk_buf_end
= disk_buf
= NULL
;
980 /* Stream construction */
981 /* We take the first stream of each (audio and video) */
982 /* TODO : Search for these in the file first */
983 audio_str
.curr_packet_end
= audio_str
.curr_packet
= audio_str
.next_packet
= NULL
;
984 video_str
= audio_str
;
988 /* Initialise our malloc buffer */
989 mpeg2_alloc_init(audiobuf
,audiosize
);
991 /* Grab most of the buffer for the compressed video - leave some for
992 PCM audio data and some for libmpeg2 malloc use. */
993 buffer_size
= audiosize
- (PCMBUFFER_SIZE
+AUDIOBUFFER_SIZE
+LIBMPEG2BUFFER_SIZE
);
995 DEBUGF("audiosize=%d, buffer_size=%ld\n",audiosize
,buffer_size
);
996 buffer
= mpeg2_malloc(buffer_size
,-1);
1001 #ifndef HAVE_LCD_COLOR
1002 /* initialize the grayscale buffer: 32 bitplanes for 33 shades of gray. */
1003 grayscales
= gray_init(rb
, buffer
, buffer_size
, false, LCD_WIDTH
, LCD_HEIGHT
,
1004 32, 2<<8, &graysize
) + 1;
1006 buffer_size
-= graysize
;
1007 if (grayscales
< 33 || buffer_size
<= 0)
1009 rb
->splash(HZ
, "gray buf error");
1010 return PLUGIN_ERROR
;
1014 buffer_size
&= ~(0x7ff); /* Round buffer down to nearest 2KB */
1015 DEBUGF("audiosize=%d, buffer_size=%ld\n",audiosize
,buffer_size
);
1017 mpa_buffer_size
= AUDIOBUFFER_SIZE
;
1018 mpa_buffer
= mpeg2_malloc(mpa_buffer_size
,-2);
1020 if (mpa_buffer
== NULL
)
1021 return PLUGIN_ERROR
;
1023 pcm_buffer_size
= PCMBUFFER_SIZE
;
1024 pcm_buffer
= mpeg2_malloc(pcm_buffer_size
,-2);
1026 if (pcm_buffer
== NULL
)
1027 return PLUGIN_ERROR
;
1029 /* The remaining buffer is for use by libmpeg2 */
1031 #ifdef HAVE_LCD_COLOR
1032 rb
->lcd_set_backdrop(NULL
);
1033 rb
->lcd_set_foreground(LCD_WHITE
);
1034 rb
->lcd_set_background(LCD_BLACK
);
1036 rb
->lcd_clear_display();
1039 if (parameter
== NULL
) {
1040 return PLUGIN_ERROR
;
1043 /* Open the video file */
1044 in_file
= rb
->open((char*)parameter
,O_RDONLY
);
1047 //fprintf(stderr,"Could not open %s\n",argv[1]);
1048 return PLUGIN_ERROR
;
1053 rb
->queue_init( &msg_queue
, false ); /* Msg queue init */
1055 /* make sure the backlight is always on when viewing video
1056 (actually it should also set the timeout when plugged in,
1057 but the function backlight_set_timeout_plugged is not
1058 available in plugins) */
1059 #if CONFIG_BACKLIGHT
1060 if (rb
->global_settings
->backlight_timeout
> 0)
1061 rb
->backlight_set_timeout(1);
1064 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
1065 rb
->cpu_boost(true);
1068 /* Initialise libmad */
1069 rb
->memset(mad_frame_overlap
, 0, sizeof(mad_frame_overlap
));
1070 init_mad(mad_frame_overlap
);
1074 file_remaining
= rb
->filesize(in_file
);
1075 disk_buf_end
= buffer
+ buffer_size
-MPEG_GUARDBUF_SIZE
;
1077 disk_buf_len
= rb
->read (in_file
, buffer
, MPEG_LOW_WATERMARK
);
1079 DEBUGF("Initial Buffering - %d bytes\n",(int)disk_buf_len
);
1081 disk_buf_tail
= buffer
+disk_buf_len
;
1082 file_remaining
-= disk_buf_len
;
1084 video_str
.guard_bytes
= audio_str
.guard_bytes
= 0;
1085 video_str
.first_pts
= audio_str
.first_pts
= 0;
1086 video_str
.prev_packet
= disk_buf
;
1087 audio_str
.prev_packet
= disk_buf
;
1088 video_str
.buffer_remaining
= disk_buf_len
;
1089 audio_str
.buffer_remaining
= disk_buf_len
;
1091 //DEBUGF("START: video = %d, audio = %d\n",audio_str.buffer_remaining,video_str.buffer_remaining);
1092 rb
->lcd_setfont(FONT_SYSFIXED
);
1094 audiostatus
= STREAM_BUFFERING
;
1095 videostatus
= STREAM_PLAYING
;
1097 #ifndef HAVE_LCD_COLOR
1101 /* We put the video thread on the second processor for multi-core targets. */
1102 if ((videothread_id
= rb
->create_thread(video_thread
,
1103 (uint8_t*)video_stack
,VIDEO_STACKSIZE
,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK
)
1104 IF_COP(, COP
, true))) == NULL
)
1106 rb
->splash(HZ
, "Cannot create video thread!");
1107 return PLUGIN_ERROR
;
1109 if ((audiothread_id
= rb
->create_thread(audio_thread
,
1110 (uint8_t*)audio_stack
,AUDIO_STACKSIZE
,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK
)
1111 IF_COP(, CPU
, false))) == NULL
)
1113 rb
->splash(HZ
, "Cannot create audio thread!");
1114 /* To do: Handle this error correctly on dual-core targets */
1115 rb
->remove_thread(videothread_id
);
1116 return PLUGIN_ERROR
;
1119 /* Wait until both threads have finished their work */
1120 while ((audiostatus
!= STREAM_DONE
) || (videostatus
!= STREAM_DONE
)) {
1121 audio_remaining
= audio_str
.buffer_remaining
;
1122 video_remaining
= video_str
.buffer_remaining
;
1123 if (MIN(audio_remaining
,video_remaining
) < MPEG_LOW_WATERMARK
) {
1125 // TODO: Add mutex when updating the A/V buffer_remaining variables.
1126 bytes_to_read
= buffer_size
- MPEG_GUARDBUF_SIZE
- MAX(audio_remaining
,video_remaining
);
1128 bytes_to_read
= MIN(bytes_to_read
,(size_t)(disk_buf_end
-disk_buf_tail
));
1130 while (( bytes_to_read
> 0) && (file_remaining
> 0) &&
1131 ((audiostatus
!= STREAM_DONE
) || (videostatus
!= STREAM_DONE
))) {
1132 n
= rb
->read(in_file
, disk_buf_tail
, MIN(32*1024,bytes_to_read
));
1135 file_remaining
-= n
;
1136 audio_str
.buffer_remaining
+= n
;
1137 video_str
.buffer_remaining
+= n
;
1142 if (disk_buf_tail
== disk_buf_end
)
1143 disk_buf_tail
= buffer
;
1149 #ifndef HAVE_LCD_COLOR
1153 rb
->remove_thread(audiothread_id
);
1154 rb
->yield(); /* Is this needed? */
1156 rb
->lcd_clear_display();
1159 mpeg2_close (mpeg2dec
);
1161 rb
->queue_delete( &msg_queue
);
1163 rb
->close (in_file
);
1165 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
1166 rb
->cpu_boost(false);
1169 save_settings(); /* Save settings (if they have changed) */
1171 rb
->lcd_setfont(FONT_UI
);
1173 #if CONFIG_BACKLIGHT
1174 /* reset backlight settings */
1175 rb
->backlight_set_timeout(rb
->global_settings
->backlight_timeout
);