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.c770
1 files changed, 596 insertions, 174 deletions
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c
index 54fdf05355..128eb268a6 100644
--- a/apps/plugins/mpegplayer/mpegplayer.c
+++ b/apps/plugins/mpegplayer/mpegplayer.c
@@ -110,6 +110,7 @@ FPS | 27Mhz | 100Hz | 44.1KHz | 48KHz
110#include "mpeg_settings.h" 110#include "mpeg_settings.h"
111#include "video_out.h" 111#include "video_out.h"
112#include "../../codecs/libmad/mad.h" 112#include "../../codecs/libmad/mad.h"
113#include "splash.h"
113 114
114PLUGIN_HEADER 115PLUGIN_HEADER
115PLUGIN_IRAM_DECLARE 116PLUGIN_IRAM_DECLARE
@@ -198,11 +199,8 @@ typedef struct
198 uint8_t* curr_packet_end; /* Current stream packet end */ 199 uint8_t* curr_packet_end; /* Current stream packet end */
199 200
200 uint8_t* prev_packet; /* Previous stream packet beginning */ 201 uint8_t* prev_packet; /* Previous stream packet beginning */
201 uint8_t* next_packet; /* Next stream packet beginning */ 202 size_t prev_packet_length; /* Lenth of previous packet */
202 203 size_t buffer_remaining; /* How much data is left in the buffer */
203 size_t guard_bytes; /* Number of bytes in guardbuf used */
204 uint64_t buffer_tail; /* Accumulation of bytes added */
205 uint64_t buffer_head; /* Accumulation of bytes removed */
206 uint32_t curr_pts; /* Current presentation timestamp */ 204 uint32_t curr_pts; /* Current presentation timestamp */
207 uint32_t curr_time; /* Current time in samples */ 205 uint32_t curr_time; /* Current time in samples */
208 uint32_t tagged; /* curr_pts is valid */ 206 uint32_t tagged; /* curr_pts is valid */
@@ -301,8 +299,7 @@ static intptr_t str_send_msg(Stream *str, int id, intptr_t data)
301 return str->dispatch_fn(str, msg); 299 return str->dispatch_fn(str, msg);
302#endif 300#endif
303 301
304 /* Only one thread at a time, please - only one core may safely send 302 /* Only one thread at a time, please */
305 right now */
306 rb->spinlock_lock(&str->msg_lock); 303 rb->spinlock_lock(&str->msg_lock);
307 304
308 str->ev.id = id; 305 str->ev.id = id;
@@ -333,13 +330,62 @@ static intptr_t str_send_msg(Stream *str, int id, intptr_t data)
333/* NOTE: Putting the following variables in IRAM cause audio corruption 330/* NOTE: Putting the following variables in IRAM cause audio corruption
334 on the ipod (reason unknown) 331 on the ipod (reason unknown)
335*/ 332*/
336static uint8_t *disk_buf IBSS_ATTR; 333static uint8_t *disk_buf_start IBSS_ATTR; /* Start pointer */
337static uint8_t *disk_buf_end IBSS_ATTR; 334static uint8_t *disk_buf_end IBSS_ATTR; /* End of buffer pointer less
338static uint8_t *disk_buf_tail IBSS_ATTR; 335 MPEG_GUARDBUF_SIZE. The
339static size_t buffer_size IBSS_ATTR; 336 guard space is used to wrap
337 data at the buffer start to
338 pass continuous data
339 packets */
340static uint8_t *disk_buf_tail IBSS_ATTR; /* Location of last data + 1
341 filled into the buffer */
342static size_t disk_buf_size IBSS_ATTR; /* The total buffer length
343 including the guard
344 space */
345static size_t file_remaining IBSS_ATTR;
346
347#if NUM_CORES > 1
348/* Some stream variables are shared between cores */
349struct mutex stream_lock IBSS_ATTR;
350static inline void init_stream_lock(void)
351 { rb->spinlock_init(&stream_lock); }
352static inline void lock_stream(void)
353 { rb->spinlock_lock(&stream_lock); }
354static inline void unlock_stream(void)
355 { rb->spinlock_unlock(&stream_lock); }
356#else
357/* No RMW issue here */
358static inline void init_stream_lock(void)
359 { }
360static inline void lock_stream(void)
361 { }
362static inline void unlock_stream(void)
363 { }
364#endif
365
366static int audio_sync_start IBSS_ATTR; /* If 0, the audio thread
367 yields waiting on the video
368 thread to synchronize with
369 the stream */
370static uint32_t audio_sync_time IBSS_ATTR; /* The time that the video
371 thread has reached after
372 synchronizing. The
373 audio thread now needs
374 to advance to this
375 time */
376static int video_sync_start IBSS_ATTR; /* While 0, the video thread
377 yields until the audio
378 thread has reached the
379 audio_sync_time */
380static int video_thumb_print IBSS_ATTR; /* If 1, the video thread is
381 only decoding one frame for
382 use in the menu. If 0,
383 normal operation */
384static int play_time IBSS_ATTR; /* The movie time as represented by
385 the maximum audio PTS tag in the
386 stream converted to half minutes */
387char *filename; /* hack for resume time storage */
340 388
341#define MSG_BUFFER_NEARLY_EMPTY 1
342#define MSG_EXIT_REQUESTED 2
343 389
344/* Various buffers */ 390/* Various buffers */
345/* TODO: Can we reduce the PCM buffer size? */ 391/* TODO: Can we reduce the PCM buffer size? */
@@ -350,7 +396,7 @@ static size_t buffer_size IBSS_ATTR;
350#define LIBMPEG2BUFFER_SIZE (2*1024*1024) 396#define LIBMPEG2BUFFER_SIZE (2*1024*1024)
351 397
352/* 65536+6 is required since each PES has a 6 byte header with a 16 bit packet length field */ 398/* 65536+6 is required since each PES has a 6 byte header with a 16 bit packet length field */
353#define MPEG_GUARDBUF_SIZE (64*1024+1024) /* Keep a bit extra - excessive for now */ 399#define MPEG_GUARDBUF_SIZE (65*1024) /* Keep a bit extra - excessive for now */
354#define MPEG_LOW_WATERMARK (1024*1024) 400#define MPEG_LOW_WATERMARK (1024*1024)
355 401
356static void pcm_playback_play_pause(bool play); 402static void pcm_playback_play_pause(bool play);
@@ -471,8 +517,47 @@ static void init_mad(void* mad_frame_overlap)
471 ((p)[b3] << 6) | \ 517 ((p)[b3] << 6) | \
472 ((p)[b4] >> 2 ))) 518 ((p)[b4] >> 2 )))
473 519
474/* This function demuxes the streams and gives the next stream data pointer */ 520/* This function synchronizes the mpeg stream. The function returns
475static void get_next_data( Stream* str ) 521 true on error */
522bool sync_data_stream(uint8_t **p)
523{
524 for (;;)
525 {
526 while ( !CMP_4_CONST(*p, PACK_START_CODE) && (*p) < disk_buf_tail )
527 (*p)++;
528 if ( (*p) >= disk_buf_tail )
529 break;
530 uint8_t *p_save = (*p);
531 if ( ((*p)[4] & 0xc0) == 0x40 ) /* mpeg-2 */
532 (*p) += 14 + ((*p)[13] & 7);
533 else if ( ((*p)[4] & 0xf0) == 0x20 ) /* mpeg-1 */
534 (*p) += 12;
535 else
536 (*p) += 5;
537 if ( (*p) >= disk_buf_tail )
538 break;
539 if ( CMP_3_CONST(*p, PACKET_START_CODE_PREFIX) )
540 {
541 (*p) = p_save;
542 break;
543 }
544 else
545 (*p) = p_save+1;
546 }
547
548 if ( (*p) >= disk_buf_tail )
549 return true;
550 else
551 return false;
552}
553
554/* This function demuxes the streams and gives the next stream data
555 pointer. Type 0 is normal operation. Type 1 and 2 have been added
556 for rapid seeks into the data stream. Type 1 and 2 ignore the
557 video_sync_start state (a signal to yield for refilling the
558 buffer). Type 1 will append more data to the buffer tail (minumal
559 bufer size reads that are increased only as needed). */
560static int get_next_data( Stream* str, uint8_t type )
476{ 561{
477 uint8_t *p; 562 uint8_t *p;
478 uint8_t *header; 563 uint8_t *header;
@@ -481,30 +566,49 @@ static void get_next_data( Stream* str )
481 static int mpeg1_skip_table[16] = 566 static int mpeg1_skip_table[16] =
482 { 0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 567 { 0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
483 568
484 if (str->curr_packet_end == NULL) 569 if ( (p=str->curr_packet_end) == NULL)
485 { 570 p = disk_buf_start;
486 /* What does this do? */
487 while ((p = disk_buf) == NULL)
488 {
489 rb->lcd_putsxy(0,LCD_HEIGHT-10,"FREEZE!");
490 rb->lcd_update();
491 rb->sleep(HZ);
492 }
493 }
494 else
495 {
496 p = str->curr_packet_end;
497 }
498 571
499 while (1) 572 while (1)
500 { 573 {
501 int length, bytes; 574 int length, bytes;
502 575
503 if (p >= disk_buf_end) 576 /* Yield for buffer filling */
577 if ( (type == 0) && (str->buffer_remaining < 120*1024) && (file_remaining > 0) )
578 while ( (str->buffer_remaining < 512*1024) && (file_remaining > 0) )
579 rb->yield();
580
581 /* The packet start position (plus an arbitrary header length)
582 has exceeded the amount of data in the buffer */
583 if ( type == 1 && (p+50) >= disk_buf_tail )
504 { 584 {
505 p = disk_buf + (p - disk_buf_end); 585 DEBUGF("disk buffer overflow\n");
586 return 1;
506 } 587 }
507 588
589 /* are we at the end of file? */
590 {
591 size_t tmp_length;
592 if (p < str->prev_packet)
593 tmp_length = (disk_buf_end - str->prev_packet) +
594 (p - disk_buf_start);
595 else
596 tmp_length = (p - str->prev_packet);
597 if (0 == str->buffer_remaining-tmp_length-str->prev_packet_length)
598 {
599 str->curr_packet_end = str->curr_packet = NULL;
600 break;
601 }
602 }
603
604 /* wrap the disk buffer */
605 if (p >= disk_buf_end)
606 p = disk_buf_start + (p - disk_buf_end);
607
608 /* wrap packet header if needed */
609 if ( (p+50) >= disk_buf_end )
610 rb->memcpy(disk_buf_end, disk_buf_start, 50);
611
508 /* Pack header, skip it */ 612 /* Pack header, skip it */
509 if (CMP_4_CONST(p, PACK_START_CODE)) 613 if (CMP_4_CONST(p, PACK_START_CODE))
510 { 614 {
@@ -521,7 +625,6 @@ static void get_next_data( Stream* str )
521 rb->splash( 30, "Weird Pack header!" ); 625 rb->splash( 30, "Weird Pack header!" );
522 p += 5; 626 p += 5;
523 } 627 }
524 /*rb->splash( 30, "Pack header" );*/
525 } 628 }
526 629
527 /* System header, parse and skip it - four bytes */ 630 /* System header, parse and skip it - four bytes */
@@ -535,29 +638,29 @@ static void get_next_data( Stream* str )
535 638
536 p += header_length; 639 p += header_length;
537 640
538 if (p >= disk_buf_end) 641 if ( p >= disk_buf_end )
539 { 642 p = disk_buf_start + (p - disk_buf_end);
540 p = disk_buf + (p - disk_buf_end);
541 }
542 /*rb->splash( 30, "System header" );*/
543 } 643 }
544 644
545 /* Packet header, parse it */ 645 /* Packet header, parse it */
546 if (!CMP_3_CONST(p, PACKET_START_CODE_PREFIX)) 646 if (!CMP_3_CONST(p, PACKET_START_CODE_PREFIX))
547 { 647 {
548 /* Problem */ 648 /* Problem */
549 //rb->splash( HZ*3, "missing packet start code prefix : %X%X at %X", *p, *(p+2), p-disk_buf ); 649 rb->splash( HZ*3, "missing packet start code prefix : %X%X at %lX",
650 *p, *(p+2), (long unsigned int)(p-disk_buf_start) );
651
652 DEBUGF("end diff: %X,%X,%X,%X,%X,%X\n",(int)str->curr_packet_end,
653 (int)audio_str.curr_packet_end,(int)video_str.curr_packet_end,
654 (int)disk_buf_start,(int)disk_buf_end,(int)disk_buf_tail);
655
550 str->curr_packet_end = str->curr_packet = NULL; 656 str->curr_packet_end = str->curr_packet = NULL;
551 break; 657 break;
552 //++p;
553 //break;
554 } 658 }
555 659
556 /* We retrieve basic infos */ 660 /* We retrieve basic infos */
557 stream = p[3]; 661 stream = p[3];
558 length = (p[4] << 8) | p[5]; 662 length = (p[4] << 8) | p[5];
559 663
560 /*rb->splash( 100, "Stream : %X", stream );*/
561 if (stream != str->id) 664 if (stream != str->id)
562 { 665 {
563 /* End of stream ? */ 666 /* End of stream ? */
@@ -618,11 +721,9 @@ static void get_next_data( Stream* str )
618 break; 721 break;
619 } 722 }
620 } 723 }
621 724
622 if ((header[length - 1] & 0xc0) == 0x40) 725 if ( (header[length - 1] & 0xc0) == 0x40 )
623 {
624 length += 2; 726 length += 2;
625 }
626 727
627 len_skip = length; 728 len_skip = length;
628 length += mpeg1_skip_table[header[length - 1] >> 4]; 729 length += mpeg1_skip_table[header[length - 1] >> 4];
@@ -657,20 +758,19 @@ static void get_next_data( Stream* str )
657 if (bytes > 0) 758 if (bytes > 0)
658 { 759 {
659 str->curr_packet_end = p + bytes; 760 str->curr_packet_end = p + bytes;
660 //DEBUGF("prev = %d, curr = %d\n",str->prev_packet,str->curr_packet);
661 761
662 if (str->curr_packet != NULL) 762 if (str->curr_packet != NULL)
663 { 763 {
764 lock_stream();
765
766 str->buffer_remaining -= str->prev_packet_length;
664 if (str->curr_packet < str->prev_packet) 767 if (str->curr_packet < str->prev_packet)
665 { 768 str->prev_packet_length = (disk_buf_end - str->prev_packet) +
666 str->buffer_head += (disk_buf_end - str->prev_packet) + 769 (str->curr_packet - disk_buf_start);
667 (str->curr_packet - disk_buf);
668 str->guard_bytes = 0;
669 }
670 else 770 else
671 { 771 str->prev_packet_length = (str->curr_packet - str->prev_packet);
672 str->buffer_head += (str->curr_packet - str->prev_packet); 772
673 } 773 unlock_stream();
674 774
675 str->prev_packet = str->curr_packet; 775 str->prev_packet = str->curr_packet;
676 } 776 }
@@ -678,14 +778,13 @@ static void get_next_data( Stream* str )
678 str->curr_packet = p; 778 str->curr_packet = p;
679 779
680 if (str->curr_packet_end > disk_buf_end) 780 if (str->curr_packet_end > disk_buf_end)
681 { 781 rb->memcpy(disk_buf_end, disk_buf_start,
682 str->guard_bytes = str->curr_packet_end - disk_buf_end; 782 str->curr_packet_end - disk_buf_end );
683 rb->memcpy(disk_buf_end, disk_buf, str->guard_bytes);
684 }
685 } 783 }
686 784
687 break; 785 break;
688 } /* end while */ 786 } /* end while */
787 return 0;
689} 788}
690 789
691/* Our clock rate in ticks/second - this won't be a constant for long */ 790/* Our clock rate in ticks/second - this won't be a constant for long */
@@ -943,6 +1042,8 @@ static int button_loop(void)
943 int vol, minvol, maxvol; 1042 int vol, minvol, maxvol;
944 int button; 1043 int button;
945 1044
1045 if (video_sync_start==1) {
1046
946 if (str_have_msg(&audio_str)) 1047 if (str_have_msg(&audio_str))
947 { 1048 {
948 struct event ev; 1049 struct event ev;
@@ -1014,6 +1115,7 @@ static int button_loop(void)
1014 rb->lcd_setfont(FONT_SYSFIXED); 1115 rb->lcd_setfont(FONT_SYSFIXED);
1015 1116
1016 if (result) { 1117 if (result) {
1118 settings.resume_time = (int)(get_stream_time()/44100/30);
1017 str_send_msg(&video_str, STREAM_QUIT, 0); 1119 str_send_msg(&video_str, STREAM_QUIT, 0);
1018 audio_str.status = STREAM_STOPPED; 1120 audio_str.status = STREAM_STOPPED;
1019 } else { 1121 } else {
@@ -1024,6 +1126,7 @@ static int button_loop(void)
1024 break; 1126 break;
1025 1127
1026 case MPEG_STOP: 1128 case MPEG_STOP:
1129 settings.resume_time = (int)(get_stream_time()/44100/30);
1027 str_send_msg(&video_str, STREAM_QUIT, 0); 1130 str_send_msg(&video_str, STREAM_QUIT, 0);
1028 audio_str.status = STREAM_STOPPED; 1131 audio_str.status = STREAM_STOPPED;
1029 break; 1132 break;
@@ -1060,7 +1163,7 @@ static int button_loop(void)
1060 audio_str.status = STREAM_STOPPED; 1163 audio_str.status = STREAM_STOPPED;
1061 } 1164 }
1062 } 1165 }
1063 1166 }
1064quit: 1167quit:
1065 return audio_str.status; 1168 return audio_str.status;
1066} 1169}
@@ -1086,7 +1189,23 @@ static void audio_thread(void)
1086 pcm_playback_play(0); 1189 pcm_playback_play(0);
1087 1190
1088 /* Get first packet */ 1191 /* Get first packet */
1089 get_next_data(&audio_str); 1192 get_next_data(&audio_str, 0 );
1193
1194 /* skip audio packets here */
1195 while (audio_sync_start==0)
1196 {
1197 audio_str.status = STREAM_PLAYING;
1198 rb->yield();
1199 }
1200
1201 if (audio_sync_time>10000)
1202 {
1203 while (TS_TO_TICKS(audio_str.curr_pts) < audio_sync_time - 10000)
1204 {
1205 get_next_data(&audio_str, 0 );
1206 rb->priority_yield();
1207 }
1208 }
1090 1209
1091 if (audio_str.curr_packet == NULL) 1210 if (audio_str.curr_packet == NULL)
1092 goto done; 1211 goto done;
@@ -1165,7 +1284,7 @@ static void audio_thread(void)
1165 mpabuf = mpa_buffer; 1284 mpabuf = mpa_buffer;
1166 1285
1167 /* Get data from next audio packet */ 1286 /* Get data from next audio packet */
1168 get_next_data(&audio_str); 1287 get_next_data(&audio_str, 0 );
1169 } 1288 }
1170 while (audio_str.curr_packet != NULL && 1289 while (audio_str.curr_packet != NULL &&
1171 mpabuf_used < MPA_MAX_FRAME_SIZE + MAD_BUFFER_GUARD); 1290 mpabuf_used < MPA_MAX_FRAME_SIZE + MAD_BUFFER_GUARD);
@@ -1198,8 +1317,6 @@ static void audio_thread(void)
1198 1317
1199 if (mad_stat != 0) 1318 if (mad_stat != 0)
1200 { 1319 {
1201 DEBUGF("Audio stream error - %d\n", stream.error);
1202
1203 if (stream.error == MAD_FLAG_INCOMPLETE 1320 if (stream.error == MAD_FLAG_INCOMPLETE
1204 || stream.error == MAD_ERROR_BUFLEN) 1321 || stream.error == MAD_ERROR_BUFLEN)
1205 { 1322 {
@@ -1259,6 +1376,13 @@ static void audio_thread(void)
1259 rb->priority_yield(); 1376 rb->priority_yield();
1260 } 1377 }
1261 1378
1379 if (video_sync_start == 0 &&
1380 pts->pts+(uint32_t)synth.pcm.length<audio_sync_time) {
1381 synth.pcm.length = 0;
1382 size = 0;
1383 rb->yield();
1384 }
1385
1262 /* TODO: This part will be replaced with dsp calls soon */ 1386 /* TODO: This part will be replaced with dsp calls soon */
1263 if (MAD_NCHANNELS(&frame.header) == 2) 1387 if (MAD_NCHANNELS(&frame.header) == 2)
1264 { 1388 {
@@ -1305,6 +1429,7 @@ static void audio_thread(void)
1305 audio_str.status = STREAM_PLAYING; 1429 audio_str.status = STREAM_PLAYING;
1306 pcmbuf_threshold = PCMBUF_PLAY_ALL; 1430 pcmbuf_threshold = PCMBUF_PLAY_ALL;
1307 pcm_playback_seek_time(pcmbuf_tail->time); 1431 pcm_playback_seek_time(pcmbuf_tail->time);
1432 video_sync_start = 1;
1308 } 1433 }
1309 1434
1310 /* Make this data available to DMA */ 1435 /* Make this data available to DMA */
@@ -1391,29 +1516,32 @@ static void video_thread(void)
1391 1516
1392 /* Clear the display - this is mainly just to indicate that the 1517 /* Clear the display - this is mainly just to indicate that the
1393 video thread has started successfully. */ 1518 video thread has started successfully. */
1394 rb->lcd_clear_display(); 1519 if (!video_thumb_print)
1395 rb->lcd_update(); 1520 {
1521 rb->lcd_clear_display();
1522 rb->lcd_update();
1523 }
1396 1524
1397 /* Request the first packet data */ 1525 /* Request the first packet data */
1398 get_next_data( &video_str ); 1526 get_next_data( &video_str, 0 );
1399 1527
1400 if (video_str.curr_packet == NULL) 1528 if (video_str.curr_packet == NULL)
1401 goto done; 1529 goto video_thread_quit;
1402 1530
1403 mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end); 1531 mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end);
1404 total_offset += video_str.curr_packet_end - video_str.curr_packet; 1532 total_offset += video_str.curr_packet_end - video_str.curr_packet;
1405 1533
1406 info = mpeg2_info (mpeg2dec); 1534 info = mpeg2_info (mpeg2dec);
1407 1535
1408 /* Wait if the audio thread is buffering - i.e. before
1409 the first frames are decoded */
1410 while (audio_str.status == STREAM_BUFFERING)
1411 rb->priority_yield();
1412
1413 while (1) 1536 while (1)
1414 { 1537 {
1415 /* quickly check mailbox first */ 1538 /* quickly check mailbox first */
1416 if (str_have_msg(&video_str)) 1539 if (video_thumb_print)
1540 {
1541 if (video_str.status == STREAM_STOPPED)
1542 break;
1543 }
1544 else if (str_have_msg(&video_str))
1417 { 1545 {
1418 while (1) 1546 while (1)
1419 { 1547 {
@@ -1450,7 +1578,8 @@ static void video_thread(void)
1450 { 1578 {
1451 case STATE_BUFFER: 1579 case STATE_BUFFER:
1452 /* Request next packet data */ 1580 /* Request next packet data */
1453 get_next_data( &video_str ); 1581 get_next_data( &video_str, 0 );
1582
1454 mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end); 1583 mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end);
1455 total_offset += video_str.curr_packet_end - video_str.curr_packet; 1584 total_offset += video_str.curr_packet_end - video_str.curr_packet;
1456 info = mpeg2_info (mpeg2dec); 1585 info = mpeg2_info (mpeg2dec);
@@ -1458,7 +1587,7 @@ static void video_thread(void)
1458 if (video_str.curr_packet == NULL) 1587 if (video_str.curr_packet == NULL)
1459 { 1588 {
1460 /* No more data. */ 1589 /* No more data. */
1461 goto done; 1590 goto video_thread_quit;
1462 } 1591 }
1463 continue; 1592 continue;
1464 1593
@@ -1528,8 +1657,12 @@ static void video_thread(void)
1528 break; 1657 break;
1529 1658
1530 /* No limiting => no dropping - draw this frame */ 1659 /* No limiting => no dropping - draw this frame */
1531 if (!settings.limitfps) 1660 if (!settings.limitfps && (video_thumb_print == 0))
1661 {
1662 audio_sync_start = 1;
1663 video_sync_start = 1;
1532 goto picture_draw; 1664 goto picture_draw;
1665 }
1533 1666
1534 /* Get presentation times in audio samples - quite accurate 1667 /* Get presentation times in audio samples - quite accurate
1535 enough - add previous frame duration if not stamped */ 1668 enough - add previous frame duration if not stamped */
@@ -1538,7 +1671,19 @@ static void video_thread(void)
1538 1671
1539 period = TIME_TO_TICKS(info->sequence->frame_period); 1672 period = TIME_TO_TICKS(info->sequence->frame_period);
1540 1673
1674 if ( (video_thumb_print == 1 || video_sync_start == 0) &&
1675 ((int)(info->current_picture->flags & PIC_MASK_CODING_TYPE)
1676 == PIC_FLAG_CODING_TYPE_B))
1677 break;
1678
1541 eta_video = curr_time; 1679 eta_video = curr_time;
1680
1681 audio_sync_time = eta_video;
1682 audio_sync_start = 1;
1683
1684 while (video_sync_start == 0)
1685 rb->yield();
1686
1542 eta_audio = get_stream_time(); 1687 eta_audio = get_stream_time();
1543 1688
1544 /* How early/late are we? > 0 = late, < 0 early */ 1689 /* How early/late are we? > 0 = late, < 0 early */
@@ -1664,32 +1809,39 @@ static void video_thread(void)
1664 1809
1665 picture_wait: 1810 picture_wait:
1666 /* Wait until audio catches up */ 1811 /* Wait until audio catches up */
1667 while (eta_video > eta_audio) 1812 if (video_thumb_print)
1668 { 1813 video_str.status = STREAM_STOPPED;
1669 rb->priority_yield(); 1814 else
1670 1815 while (eta_video > eta_audio)
1671 /* Make sure not to get stuck waiting here forever */
1672 if (str_have_msg(&video_str))
1673 { 1816 {
1674 str_look_msg(&video_str, &ev); 1817 rb->priority_yield();
1675 1818
1676 /* If not to play, process up top */ 1819 /* Make sure not to get stuck waiting here forever */
1677 if (ev.id != STREAM_PLAY) 1820 if (str_have_msg(&video_str))
1678 goto rendering_finished; 1821 {
1822 str_look_msg(&video_str, &ev);
1823
1824 /* If not to play, process up top */
1825 if (ev.id != STREAM_PLAY)
1826 goto rendering_finished;
1827
1828 /* Told to play but already playing */
1829 str_get_msg(&video_str, &ev);
1830 str_reply_msg(&video_str, 1);
1831 }
1679 1832
1680 /* Told to play but already playing */ 1833 eta_audio = get_stream_time();
1681 str_get_msg(&video_str, &ev);
1682 str_reply_msg(&video_str, 1);
1683 } 1834 }
1684 1835
1685 eta_audio = get_stream_time();
1686 }
1687
1688 picture_draw: 1836 picture_draw:
1689 /* Record last frame time */ 1837 /* Record last frame time */
1690 last_render = *rb->current_tick; 1838 last_render = *rb->current_tick;
1691 1839
1692 vo_draw_frame(info->display_fbuf->buf); 1840 if (video_thumb_print)
1841 vo_draw_frame_thumb(info->display_fbuf->buf);
1842 else
1843 vo_draw_frame(info->display_fbuf->buf);
1844
1693 num_drawn++; 1845 num_drawn++;
1694 1846
1695 picture_skip: 1847 picture_skip:
@@ -1724,53 +1876,298 @@ static void video_thread(void)
1724 rb->yield(); 1876 rb->yield();
1725 } 1877 }
1726 1878
1727done: 1879 video_thread_quit:
1728#if NUM_CORES > 1 1880 /* if video ends before time sync'd,
1729 flush_icache(); 1881 besure the audio thread is closed */
1730#endif 1882 if (video_sync_start == 0)
1883 {
1884 audio_str.status = STREAM_STOPPED;
1885 audio_sync_start = 1;
1886 }
1731 1887
1732 video_str.status = STREAM_DONE; 1888 #if NUM_CORES > 1
1889 flush_icache();
1890 #endif
1891
1892 mpeg2_close (mpeg2dec);
1893
1894 /* Commit suicide */
1895 video_str.status = STREAM_TERMINATED;
1896}
1733 1897
1734 while (1) 1898void initialize_stream( Stream *str, uint8_t *buffer_start, size_t disk_buf_len, int id )
1735 { 1899{
1736 str_get_msg(&video_str, &ev); 1900 str->curr_packet_end = str->curr_packet = NULL;
1901 str->prev_packet_length = 0;
1902 str->prev_packet = str->curr_packet_end = buffer_start;
1903 str->buffer_remaining = disk_buf_len;
1904 str->id = id;
1905}
1906
1907void display_thumb(int in_file)
1908{
1909 size_t disk_buf_len;
1737 1910
1738 if (ev.id == STREAM_QUIT) 1911 video_thumb_print = 1;
1739 break; 1912 audio_sync_start = 1;
1913 video_sync_start = 1;
1914
1915 disk_buf_len = rb->read (in_file, disk_buf_start, disk_buf_size - MPEG_GUARDBUF_SIZE);
1916 disk_buf_tail = disk_buf_start + disk_buf_len;
1917 file_remaining = 0;
1918 initialize_stream(&video_str,disk_buf_start,disk_buf_len,0xe0);
1919
1920 video_str.status = STREAM_PLAYING;
1740 1921
1741 str_reply_msg(&video_str, 0); 1922 if ((video_str.thread = rb->create_thread(video_thread,
1923 (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo"
1924 IF_PRIO(,PRIORITY_PLAYBACK)
1925 IF_COP(, COP, true))) == NULL)
1926 {
1927 rb->splash(HZ, "Cannot create video thread!");
1928 }
1929 else
1930 {
1931 while (video_str.status != STREAM_TERMINATED)
1932 rb->yield();
1742 } 1933 }
1743 1934
1744video_thread_quit: 1935 if ( video_str.curr_packet_end == video_str.curr_packet)
1745 /* Commit suicide */ 1936 rb->splash(0, "frame not available");
1746 video_str.status = STREAM_TERMINATED;
1747} 1937}
1748 1938
1939int find_length( int in_file )
1940{
1941 uint8_t *p;
1942 size_t read_length = 60*1024;
1943 size_t disk_buf_len;
1944
1945 play_time = 0;
1946
1947 /* temporary read buffer size cannot exceed buffer size */
1948 if ( read_length > disk_buf_size )
1949 read_length = disk_buf_size;
1950
1951 /* read tail of file */
1952 rb->lseek( in_file, -1*read_length, SEEK_END );
1953 disk_buf_len = rb->read( in_file, disk_buf_start, read_length );
1954 disk_buf_tail = disk_buf_start + disk_buf_len;
1955
1956 /* sync reader to this segment of the stream */
1957 p=disk_buf_start;
1958 if (sync_data_stream(&p))
1959 {
1960 DEBUGF("Could not sync stream\n");
1961 return PLUGIN_ERROR;
1962 }
1963
1964 /* find last PTS in audio stream; will movie always have audio? if
1965 the play time can not be determined, set play_time to 0 */
1966 audio_sync_start = 0;
1967 audio_sync_time = 0;
1968 video_sync_start = 0;
1969 {
1970 Stream tmp;
1971 initialize_stream(&tmp,p,disk_buf_len-(disk_buf_start-p),0xc0);
1972
1973 do
1974 {
1975 get_next_data(&tmp, 2);
1976 if (tmp.tagged == 1)
1977 /* 10 sec less to insure the video frame exist */
1978 play_time = (int)((tmp.curr_pts/45000-10)/30);
1979 }
1980 while (tmp.curr_packet_end != NULL);
1981 }
1982 return 0;
1983}
1984
1985ssize_t seek_PTS( int in_file, int start_time, int accept_button )
1986{
1987 static ssize_t last_seek_pos = 0;
1988 static int last_start_time = 0;
1989 ssize_t seek_pos;
1990 size_t disk_buf_len;
1991 uint8_t *p;
1992 size_t read_length = 60*1024;
1993
1994 /* temporary read buffer size cannot exceed buffer size */
1995 if ( read_length > disk_buf_size )
1996 read_length = disk_buf_size;
1997
1998 if ( start_time == last_start_time )
1999 {
2000 seek_pos = last_seek_pos;
2001 rb->lseek(in_file,seek_pos,SEEK_SET);
2002 }
2003 else if ( start_time != 0 )
2004 {
2005 seek_pos = rb->filesize(in_file)*start_time/play_time;
2006 int seek_pos_sec_inc = rb->filesize(in_file)/play_time/30;
2007
2008 if (seek_pos<0)
2009 seek_pos=0;
2010 if ((size_t)seek_pos > rb->filesize(in_file) - read_length)
2011 seek_pos = rb->filesize(in_file) - read_length;
2012 rb->lseek( in_file, seek_pos, SEEK_SET );
2013 disk_buf_len = rb->read( in_file, disk_buf_start, read_length );
2014 disk_buf_tail = disk_buf_start + disk_buf_len;
2015
2016 /* sync reader to this segment of the stream */
2017 p=disk_buf_start;
2018 if (sync_data_stream(&p))
2019 {
2020 DEBUGF("Could not sync stream\n");
2021 return PLUGIN_ERROR;
2022 }
2023
2024 /* find PTS >= start_time */
2025 audio_sync_start = 0;
2026 audio_sync_time = 0;
2027 video_sync_start = 0;
2028 {
2029 Stream tmp;
2030 initialize_stream(&tmp,p,disk_buf_len-(disk_buf_start-p),0xc0);
2031 int cont_seek_loop = 1;
2032 int coarse_seek = 1;
2033 do
2034 {
2035 if ( accept_button )
2036 {
2037 rb->yield();
2038 if (rb->button_available())
2039 return -101;
2040 }
2041
2042 while ( get_next_data(&tmp, 1) == 1 )
2043 {
2044 if ( tmp.curr_packet_end == disk_buf_start )
2045 seek_pos += disk_buf_tail - disk_buf_start;
2046 else
2047 seek_pos += tmp.curr_packet_end - disk_buf_start;
2048 if ((size_t)seek_pos > rb->filesize(in_file) - read_length)
2049 seek_pos = rb->filesize(in_file) - read_length;
2050 rb->lseek( in_file, seek_pos, SEEK_SET );
2051 disk_buf_len = rb->read ( in_file, disk_buf_start, read_length );
2052 disk_buf_tail = disk_buf_start + disk_buf_len;
2053
2054 /* sync reader to this segment of the stream */
2055 p=disk_buf_start;
2056 initialize_stream(&tmp,p,disk_buf_len,0xc0);
2057 }
2058
2059 /* are we after start_time in the stream? */
2060 if ( coarse_seek && (int)(tmp.curr_pts/45000) >= start_time*30 )
2061 {
2062 int time_to_backup = (int)(tmp.curr_pts/45000) - start_time*30;
2063 if (time_to_backup == 0)
2064 time_to_backup++;
2065 seek_pos -= seek_pos_sec_inc * time_to_backup;
2066 seek_pos_sec_inc -= seek_pos_sec_inc/20; /* for stability */
2067 if (seek_pos<0)
2068 seek_pos=0;
2069 if ((size_t)seek_pos > rb->filesize(in_file) - read_length)
2070 seek_pos = rb->filesize(in_file) - read_length;
2071 rb->lseek( in_file, seek_pos, SEEK_SET );
2072 disk_buf_len = rb->read( in_file, disk_buf_start, read_length );
2073 disk_buf_tail = disk_buf_start + disk_buf_len;
2074
2075 /* sync reader to this segment of the stream */
2076 p=disk_buf_start;
2077 if (sync_data_stream(&p))
2078 {
2079 DEBUGF("Could not sync stream\n");
2080 return PLUGIN_ERROR;
2081 }
2082 initialize_stream(&tmp,p,disk_buf_len-(disk_buf_start-p),0xc0);
2083 continue;
2084 }
2085
2086 /* are we well before start_time in the stream? */
2087 if ( coarse_seek && start_time*30 - (int)(tmp.curr_pts/45000) > 2 )
2088 {
2089 int time_to_advance = start_time*30 - (int)(tmp.curr_pts/45000) - 2;
2090 if (time_to_advance <= 0)
2091 time_to_advance = 1;
2092 seek_pos += seek_pos_sec_inc * time_to_advance;
2093 if (seek_pos<0)
2094 seek_pos=0;
2095 if ((size_t)seek_pos > rb->filesize(in_file) - read_length)
2096 seek_pos = rb->filesize(in_file) - read_length;
2097 rb->lseek( in_file, seek_pos, SEEK_SET );
2098 disk_buf_len = rb->read ( in_file, disk_buf_start, read_length );
2099 disk_buf_tail = disk_buf_start + disk_buf_len;
2100
2101 /* sync reader to this segment of the stream */
2102 p=disk_buf_start;
2103 if (sync_data_stream(&p))
2104 {
2105 DEBUGF("Could not sync stream\n");
2106 return PLUGIN_ERROR;
2107 }
2108 initialize_stream(&tmp,p,disk_buf_len-(disk_buf_start-p),0xc0);
2109 continue;
2110 }
2111
2112 coarse_seek = 0;
2113
2114 /* are we at start_time in the stream? */
2115 if ( (int)(tmp.curr_pts/45000) >= start_time*30 )
2116 cont_seek_loop = 0;
2117
2118 }
2119 while ( cont_seek_loop );
2120
2121
2122 DEBUGF("start diff: %u %u\n",(unsigned int)(tmp.curr_pts/45000),start_time*30);
2123 seek_pos+=tmp.curr_packet_end-disk_buf_start;
2124
2125 last_seek_pos = seek_pos;
2126 last_start_time = start_time;
2127
2128 rb->lseek(in_file,seek_pos,SEEK_SET);
2129 }
2130 }
2131 else
2132 {
2133 seek_pos = 0;
2134 rb->lseek(in_file,0,SEEK_SET);
2135 last_seek_pos = seek_pos;
2136 last_start_time = start_time;
2137 }
2138 return seek_pos;
2139}
2140
1749enum plugin_status plugin_start(struct plugin_api* api, void* parameter) 2141enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1750{ 2142{
1751 int status = PLUGIN_ERROR; /* assume failure */ 2143 int status = PLUGIN_ERROR; /* assume failure */
2144 int start_time=-1;
1752 void* audiobuf; 2145 void* audiobuf;
1753 ssize_t audiosize; 2146 ssize_t audiosize;
1754 int in_file; 2147 int in_file;
1755 uint8_t* buffer;
1756 size_t file_remaining;
1757 size_t disk_buf_len; 2148 size_t disk_buf_len;
2149 ssize_t seek_pos;
1758#ifndef HAVE_LCD_COLOR 2150#ifndef HAVE_LCD_COLOR
1759 long graysize; 2151 long graysize;
1760 int grayscales; 2152 int grayscales;
1761#endif 2153#endif
1762 2154
2155 audio_sync_start = 0;
2156 audio_sync_time = 0;
2157 video_sync_start = 0;
2158
1763 if (parameter == NULL) 2159 if (parameter == NULL)
1764 { 2160 {
1765 api->splash(HZ*2, "No File"); 2161 api->splash(HZ*2, "No File");
1766 return PLUGIN_ERROR;
1767 } 2162 }
1768 2163
1769 /* Initialize IRAM - stops audio and voice as well */ 2164 /* Initialize IRAM - stops audio and voice as well */
1770 PLUGIN_IRAM_INIT(api) 2165 PLUGIN_IRAM_INIT(api)
1771 2166
1772 rb = api; 2167 rb = api;
2168 rb->splash(0, "loading ...");
1773 2169
2170 /* sets audiosize and returns buffer pointer */
1774 audiobuf = rb->plugin_get_audio_buffer(&audiosize); 2171 audiobuf = rb->plugin_get_audio_buffer(&audiosize);
1775 2172
1776#if INPUT_SRC_CAPS != 0 2173#if INPUT_SRC_CAPS != 0
@@ -1781,49 +2178,38 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1781 2178
1782 rb->pcm_set_frequency(SAMPR_44); 2179 rb->pcm_set_frequency(SAMPR_44);
1783 2180
1784 /* Set disk pointers to NULL */ 2181#ifndef HAVE_LCD_COLOR
1785 disk_buf_end = disk_buf = NULL; 2182 /* initialize the grayscale buffer: 32 bitplanes for 33 shades of gray. */
1786 2183 grayscales = gray_init(rb, audiobuf, audiosize, false, LCD_WIDTH, LCD_HEIGHT,
1787 /* Stream construction */ 2184 32, 2<<8, &graysize) + 1;
1788 /* We take the first stream of each (audio and video) */ 2185 audiobuf += graysize;
1789 /* TODO : Search for these in the file first */ 2186 audiosize -= graysize;
1790 audio_str.curr_packet_end = audio_str.curr_packet = audio_str.next_packet = NULL; 2187 if (grayscales < 33 || audiosize <= 0)
1791 video_str = audio_str; 2188 {
1792 video_str.id = 0xe0; 2189 rb->splash(HZ, "gray buf error");
1793 audio_str.id = 0xc0; 2190 return PLUGIN_ERROR;
2191 }
2192#endif
1794 2193
1795 /* Initialise our malloc buffer */ 2194 /* Initialise our malloc buffer */
1796 audiosize = mpeg_alloc_init(audiobuf, audiosize, LIBMPEG2BUFFER_SIZE); 2195 audiosize = mpeg_alloc_init(audiobuf,audiosize, LIBMPEG2BUFFER_SIZE);
1797 if (audiosize == 0) 2196 if (audiosize == 0)
1798 return PLUGIN_ERROR; 2197 return PLUGIN_ERROR;
1799 2198
2199 /* Set disk pointers to NULL */
2200 disk_buf_end = disk_buf_start = NULL;
2201
1800 /* Grab most of the buffer for the compressed video - leave some for 2202 /* Grab most of the buffer for the compressed video - leave some for
1801 PCM audio data and some for libmpeg2 malloc use. */ 2203 PCM audio data and some for libmpeg2 malloc use. */
1802 buffer_size = audiosize - (PCMBUFFER_SIZE+PCMBUFFER_GUARD_SIZE+ 2204 disk_buf_size = audiosize - (PCMBUFFER_SIZE+PCMBUFFER_GUARD_SIZE+
1803 MPABUF_SIZE); 2205 MPABUF_SIZE);
1804 2206
1805 DEBUGF("audiosize=%ld, buffer_size=%ld\n",audiosize,buffer_size); 2207 DEBUGF("audiosize=%ld, disk_buf_size=%ld\n",audiosize,disk_buf_size);
1806 buffer = mpeg_malloc(buffer_size,-1); 2208 disk_buf_start = mpeg_malloc(disk_buf_size,-1);
1807 2209
1808 if (buffer == NULL) 2210 if (disk_buf_start == NULL)
1809 return PLUGIN_ERROR; 2211 return PLUGIN_ERROR;
1810 2212
1811#ifndef HAVE_LCD_COLOR
1812 /* initialize the grayscale buffer: 32 bitplanes for 33 shades of gray. */
1813 grayscales = gray_init(rb, buffer, buffer_size, false, LCD_WIDTH, LCD_HEIGHT,
1814 32, 2<<8, &graysize) + 1;
1815 buffer += graysize;
1816 buffer_size -= graysize;
1817 if (grayscales < 33 || buffer_size <= 0)
1818 {
1819 rb->splash(HZ, "gray buf error");
1820 return PLUGIN_ERROR;
1821 }
1822#endif
1823
1824 buffer_size &= ~(0x7ff); /* Round buffer down to nearest 2KB */
1825 DEBUGF("audiosize=%ld, buffer_size=%ld\n",audiosize,buffer_size);
1826
1827 if (!init_mpabuf()) 2213 if (!init_mpabuf())
1828 return PLUGIN_ERROR; 2214 return PLUGIN_ERROR;
1829 2215
@@ -1836,9 +2222,10 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1836 in_file = rb->open((char*)parameter,O_RDONLY); 2222 in_file = rb->open((char*)parameter,O_RDONLY);
1837 2223
1838 if (in_file < 0){ 2224 if (in_file < 0){
1839 //fprintf(stderr,"Could not open %s\n",argv[1]); 2225 DEBUGF("Could not open %s\n",(char*)parameter);
1840 return PLUGIN_ERROR; 2226 return PLUGIN_ERROR;
1841 } 2227 }
2228 filename = (char*)parameter;
1842 2229
1843#ifdef HAVE_LCD_COLOR 2230#ifdef HAVE_LCD_COLOR
1844 rb->lcd_set_backdrop(NULL); 2231 rb->lcd_set_backdrop(NULL);
@@ -1860,34 +2247,51 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1860 cannot just return PLUGIN_ERROR - instead drop though to cleanup code 2247 cannot just return PLUGIN_ERROR - instead drop though to cleanup code
1861 */ 2248 */
1862 2249
1863 init_settings(); 2250 init_settings((char*)parameter);
1864 2251
1865 /* Initialise libmad */ 2252 /* Initialise libmad */
1866 rb->memset(mad_frame_overlap, 0, sizeof(mad_frame_overlap)); 2253 rb->memset(mad_frame_overlap, 0, sizeof(mad_frame_overlap));
1867 init_mad(mad_frame_overlap); 2254 init_mad(mad_frame_overlap);
1868 2255
1869 file_remaining = rb->filesize(in_file); 2256 disk_buf_end = disk_buf_start + disk_buf_size-MPEG_GUARDBUF_SIZE;
1870 disk_buf_end = buffer + buffer_size-MPEG_GUARDBUF_SIZE; 2257
2258 /* initalize play_time with the length (in half minutes) of the movie
2259 zero if the time could not be determined */
2260 find_length( in_file );
2261
2262 /* start menu */
2263 start_time = mpeg_start_menu(play_time, in_file);
2264 if ( start_time == -1 )
2265 return 0;
2266 else if ( start_time < 0 )
2267 start_time = 0;
2268 else if ( start_time > play_time )
2269 start_time = play_time;
2270
2271 rb->splash(0, "loading ...");
2272
2273 /* seek start time */
2274 seek_pos = seek_PTS( in_file, start_time, 0 );
2275
2276 rb->lseek(in_file,seek_pos,SEEK_SET);
2277 video_thumb_print = 0;
2278 audio_sync_start = 0;
2279 audio_sync_time = 0;
2280 video_sync_start = 0;
1871 2281
1872 /* Read some stream data */ 2282 /* Read some stream data */
1873 disk_buf_len = rb->read (in_file, buffer, MPEG_LOW_WATERMARK); 2283 disk_buf_len = rb->read (in_file, disk_buf_start, disk_buf_size - MPEG_GUARDBUF_SIZE);
1874 2284
1875 DEBUGF("Initial Buffering - %d bytes\n",(int)disk_buf_len); 2285 disk_buf_tail = disk_buf_start + disk_buf_len;
1876 disk_buf = buffer; 2286 file_remaining = rb->filesize(in_file);
1877 disk_buf_tail = buffer+disk_buf_len; 2287 file_remaining -= disk_buf_len + seek_pos;
1878 file_remaining -= disk_buf_len; 2288
1879 2289 initialize_stream( &video_str, disk_buf_start, disk_buf_len, 0xe0 );
1880 audio_str.guard_bytes = 0; 2290 initialize_stream( &audio_str, disk_buf_start, disk_buf_len, 0xc0 );
1881 audio_str.prev_packet = disk_buf;
1882 audio_str.buffer_head = 0;
1883 audio_str.buffer_tail = disk_buf_len;
1884 video_str.guard_bytes = 0;
1885 video_str.prev_packet = disk_buf;
1886 video_str.buffer_head = 0;
1887 video_str.buffer_tail = disk_buf_len;
1888 2291
1889 rb->spinlock_init(&audio_str.msg_lock); 2292 rb->spinlock_init(&audio_str.msg_lock);
1890 rb->spinlock_init(&video_str.msg_lock); 2293 rb->spinlock_init(&video_str.msg_lock);
2294
1891 audio_str.status = STREAM_BUFFERING; 2295 audio_str.status = STREAM_BUFFERING;
1892 video_str.status = STREAM_PLAYING; 2296 video_str.status = STREAM_PLAYING;
1893 2297
@@ -1895,6 +2299,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1895 gray_show(true); 2299 gray_show(true);
1896#endif 2300#endif
1897 2301
2302 init_stream_lock();
2303
1898#if NUM_CORES > 1 2304#if NUM_CORES > 1
1899 flush_icache(); 2305 flush_icache();
1900#endif 2306#endif
@@ -1914,38 +2320,52 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1914 } 2320 }
1915 else 2321 else
1916 { 2322 {
1917 //DEBUGF("START: video = %d, audio = %d\n",audio_str.buffer_remaining,video_str.buffer_remaining);
1918 rb->lcd_setfont(FONT_SYSFIXED); 2323 rb->lcd_setfont(FONT_SYSFIXED);
1919 2324
1920 /* Wait until both threads have finished their work */ 2325 /* Wait until both threads have finished their work */
1921 while ((audio_str.status >= 0) || (video_str.status >= 0)) 2326 while ((audio_str.status >= 0) || (video_str.status >= 0))
1922 { 2327 {
1923 size_t audio_remaining = audio_str.buffer_tail - audio_str.buffer_head; 2328 size_t audio_remaining = audio_str.buffer_remaining;
1924 size_t video_remaining = video_str.buffer_tail - video_str.buffer_head; 2329 size_t video_remaining = video_str.buffer_remaining;
1925 2330
1926 if (MIN(audio_remaining,video_remaining) < MPEG_LOW_WATERMARK) { 2331 if (MIN(audio_remaining,video_remaining) < MPEG_LOW_WATERMARK)
2332 {
1927 2333
1928 size_t bytes_to_read = buffer_size - MPEG_GUARDBUF_SIZE - 2334 size_t bytes_to_read = disk_buf_size - MPEG_GUARDBUF_SIZE -
1929 MAX(audio_remaining,video_remaining); 2335 MAX(audio_remaining,video_remaining);
1930 2336
1931 bytes_to_read = MIN(bytes_to_read,(size_t)(disk_buf_end-disk_buf_tail)); 2337 bytes_to_read = MIN(bytes_to_read,(size_t)(disk_buf_end-disk_buf_tail));
1932 2338
1933 while (( bytes_to_read > 0) && (file_remaining > 0) && 2339 while (( bytes_to_read > 0) && (file_remaining > 0) &&
1934 ((audio_str.status >= 0) || (video_str.status >= 0))) { 2340 ((audio_str.status != STREAM_DONE) || (video_str.status != STREAM_DONE)))
1935 size_t n = rb->read(in_file, disk_buf_tail, MIN(32*1024,bytes_to_read)); 2341 {
2342
2343 size_t n;
2344 if ( video_sync_start != 0 )
2345 n = rb->read(in_file, disk_buf_tail, MIN(32*1024,bytes_to_read));
2346 else
2347 {
2348 n = rb->read(in_file, disk_buf_tail,bytes_to_read);
2349 if (n==0)
2350 rb->splash(30,"buffer fill error");
2351 }
2352
1936 2353
1937 bytes_to_read -= n; 2354 bytes_to_read -= n;
1938 file_remaining -= n; 2355 file_remaining -= n;
1939 2356
1940 audio_str.buffer_tail += n; 2357 lock_stream();
1941 video_str.buffer_tail += n; 2358 audio_str.buffer_remaining += n;
2359 video_str.buffer_remaining += n;
2360 unlock_stream();
2361
1942 disk_buf_tail += n; 2362 disk_buf_tail += n;
1943 2363
1944 rb->yield(); 2364 rb->yield();
1945 } 2365 }
1946 2366
1947 if (disk_buf_tail == disk_buf_end) 2367 if (disk_buf_tail == disk_buf_end)
1948 disk_buf_tail = buffer; 2368 disk_buf_tail = disk_buf_start;
1949 } 2369 }
1950 2370
1951 rb->sleep(HZ/10); 2371 rb->sleep(HZ/10);
@@ -1968,6 +2388,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1968 invalidate_icache(); 2388 invalidate_icache();
1969#endif 2389#endif
1970 2390
2391 vo_cleanup();
2392
1971#ifndef HAVE_LCD_COLOR 2393#ifndef HAVE_LCD_COLOR
1972 gray_release(); 2394 gray_release();
1973#endif 2395#endif