summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/plugins/video.c112
1 files changed, 59 insertions, 53 deletions
diff --git a/apps/plugins/video.c b/apps/plugins/video.c
index eab4da5c70..6650631c58 100644
--- a/apps/plugins/video.c
+++ b/apps/plugins/video.c
@@ -84,7 +84,8 @@ typedef struct // contains whatever might be useful to the player
84 unsigned long blocksize; // how many bytes per block (=video frame) 84 unsigned long blocksize; // how many bytes per block (=video frame)
85 unsigned long bps_average; // bits per second of the whole stream 85 unsigned long bps_average; // bits per second of the whole stream
86 unsigned long bps_peak; // max. of above (audio may be VBR) 86 unsigned long bps_peak; // max. of above (audio may be VBR)
87 unsigned long reserved[10]; // reserved, should be zero 87 unsigned long resume_pos; // file position to resume to
88 unsigned long reserved[9]; // reserved, should be zero
88 89
89 // video info (16 entries = 64 byte) 90 // video info (16 entries = 64 byte)
90 unsigned long video_format; // one of VIDEOFORMAT_xxx 91 unsigned long video_format; // one of VIDEOFORMAT_xxx
@@ -138,8 +139,8 @@ static struct
138{ 139{
139 enum 140 enum
140 { 141 {
141 playing,
142 paused, 142 paused,
143 playing,
143 } state; 144 } state;
144 bool bAudioUnderrun; 145 bool bAudioUnderrun;
145 bool bVideoUnderrun; 146 bool bVideoUnderrun;
@@ -198,41 +199,24 @@ int Available(unsigned char* pSnapshot)
198// debug function to draw buffer indicators 199// debug function to draw buffer indicators
199void DrawBuf(void) 200void DrawBuf(void)
200{ 201{
201 static int old_fill = -1; // indicate not initialized
202 static int old_video;
203 static int old_audio;
204 int fill, video, audio; 202 int fill, video, audio;
205 203
206 // first call? 204 rb->memset(gBuf.pOSD, 0x10, LCD_WIDTH); // draw line
207 if (old_fill == -1) 205 gBuf.pOSD[0] = gBuf.pOSD[LCD_WIDTH-1] = 0xFE; // ends
208 {
209 rb->memset(gBuf.pOSD, 0x10, LCD_WIDTH); // draw line
210 gBuf.pOSD[0] = gBuf.pOSD[LCD_WIDTH-1] = 0xFE; // ends
211 old_fill = 1; // do no harm below
212 }
213 206
214 // calculate new tick positions 207 // calculate new tick positions
215 fill = 1 + ((gBuf.pBufFill - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize; 208 fill = 1 + ((gBuf.pBufFill - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize;
216 video = 1 + ((gBuf.pReadVideo - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize; 209 video = 1 + ((gBuf.pReadVideo - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize;
217 audio = 1 + ((gBuf.pReadAudio - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize; 210 audio = 1 + ((gBuf.pReadAudio - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize;
218 211
219 if (fill != old_fill || video != old_video || audio != old_audio) 212 gBuf.pOSD[fill] |= 0x20; // below the line, two pixels
220 { 213 gBuf.pOSD[video] |= 0x08; // one above
221 // erase old ticks 214 gBuf.pOSD[audio] |= 0x04; // two above
222 gBuf.pOSD[old_fill] = 0x10;
223 gBuf.pOSD[old_video] = 0x10;
224 gBuf.pOSD[old_audio] = 0x10;
225
226 gBuf.pOSD[fill] |= 0x20; // below the line, two pixels
227 gBuf.pOSD[video] |= 0x08; // one above
228 gBuf.pOSD[audio] |= 0x04; // two above
229
230 old_fill = fill;
231 old_video = video;
232 old_audio = audio;
233 215
216 if (gPlay.state == paused) // we have to draw ourselves
217 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);
218 else
234 gPlay.bDirtyOSD = true; // redraw it with next timer IRQ 219 gPlay.bDirtyOSD = true; // redraw it with next timer IRQ
235 }
236} 220}
237 221
238 222
@@ -469,6 +453,23 @@ int WaitForButton(void)
469} 453}
470 454
471 455
456bool WantResume(int fd)
457{
458 int button;
459
460 rb->lcd_puts(0, 0, "Resume to this");
461 rb->lcd_puts(0, 1, "last position?");
462 rb->lcd_puts(0, 2, "PLAY = yes");
463 rb->lcd_puts(0, 3, "Any Other = no");
464 rb->lcd_puts(0, 4, " (plays from start)");
465 DrawPosition(gFileHdr.resume_pos, rb->filesize(fd));
466 rb->lcd_update();
467
468 button = WaitForButton();
469 return (button == BUTTON_PLAY);
470}
471
472
472int SeekTo(int fd, int nPos) 473int SeekTo(int fd, int nPos)
473{ 474{
474 int read_now, got_now; 475 int read_now, got_now;
@@ -505,18 +506,18 @@ int SeekTo(int fd, int nPos)
505 while (((tAudioFrameHeader*)(gBuf.pReadAudio))->magic != AUDIO_MAGIC) 506 while (((tAudioFrameHeader*)(gBuf.pReadAudio))->magic != AUDIO_MAGIC)
506 gBuf.pReadAudio += gFileHdr.blocksize; 507 gBuf.pReadAudio += gFileHdr.blocksize;
507 508
508 rb->mp3_play_data(gBuf.pReadAudio + gFileHdr.audio_headersize,
509 gFileHdr.blocksize - gFileHdr.audio_headersize, GetMoreMp3);
510
511 if (gPlay.bHasVideo) 509 if (gPlay.bHasVideo)
512 SyncVideo(); // pick the right video for that 510 SyncVideo(); // pick the right video for that
513 } 511 }
514 } 512 }
515 513
516 // synchronous start 514 // synchronous start
515 gPlay.state = playing;
517 if (gPlay.bHasAudio) 516 if (gPlay.bHasAudio)
518 { 517 {
519 gPlay.bAudioUnderrun = false; 518 gPlay.bAudioUnderrun = false;
519 rb->mp3_play_data(gBuf.pReadAudio + gFileHdr.audio_headersize,
520 gFileHdr.blocksize - gFileHdr.audio_headersize, GetMoreMp3);
520 rb->mp3_play_pause(true); // kickoff audio 521 rb->mp3_play_pause(true); // kickoff audio
521 } 522 }
522 if (gPlay.bHasVideo) 523 if (gPlay.bHasVideo)
@@ -553,7 +554,15 @@ int PlayTick(int fd)
553 if ((!gPlay.bHasAudio || gPlay.bAudioUnderrun) 554 if ((!gPlay.bHasAudio || gPlay.bAudioUnderrun)
554 && (!gPlay.bHasVideo || gPlay.bVideoUnderrun) 555 && (!gPlay.bHasVideo || gPlay.bVideoUnderrun)
555 && gBuf.bEOF) 556 && gBuf.bEOF)
557 {
558 if (gFileHdr.resume_pos)
559 { // we played til the end, clear resume position
560 gFileHdr.resume_pos = 0;
561 rb->lseek(fd, 0, SEEK_SET); // save resume position
562 rb->write(fd, &gFileHdr, sizeof(gFileHdr));
563 }
556 return 0; // all expired 564 return 0; // all expired
565 }
557 566
558 if (!gPlay.bRefilling || gBuf.bEOF) 567 if (!gPlay.bRefilling || gBuf.bEOF)
559 { // nothing to do 568 { // nothing to do
@@ -611,6 +620,13 @@ int PlayTick(int fd)
611 switch (button) 620 switch (button)
612 { // set exit conditions 621 { // set exit conditions
613 case BUTTON_OFF: 622 case BUTTON_OFF:
623 if (gFileHdr.magic == HEADER_MAGIC // only if file has header
624 && !(gFileHdr.flags & FLAG_LOOP)) // not for stills
625 {
626 gFileHdr.resume_pos = filepos;
627 rb->lseek(fd, 0, SEEK_SET); // save resume position
628 rb->write(fd, &gFileHdr, sizeof(gFileHdr));
629 }
614 retval = 0; // signal "stop" to caller 630 retval = 0; // signal "stop" to caller
615 break; 631 break;
616 case SYS_USB_CONNECTED: 632 case SYS_USB_CONNECTED:
@@ -680,6 +696,12 @@ int PlayTick(int fd)
680 else 696 else
681 gPlay.nSeekAcc++; 697 gPlay.nSeekAcc++;
682 break; 698 break;
699 case BUTTON_F1: // debug key
700 case BUTTON_F1 | BUTTON_REPEAT:
701 DrawBuf(); // show buffer status
702 gPlay.nTimeOSD = 30;
703 gPlay.bDirtyOSD = true;
704 break;
683 } 705 }
684 } /* if (button != BUTTON_NONE) */ 706 } /* if (button != BUTTON_NONE) */
685 707
@@ -738,7 +760,7 @@ int main(char* filename)
738 int retval; 760 int retval;
739 761
740 // try to open the file 762 // try to open the file
741 fd = rb->open(filename, O_RDONLY); 763 fd = rb->open(filename, O_RDWR);
742 if (fd < 0) 764 if (fd < 0)
743 return PLUGIN_ERROR; 765 return PLUGIN_ERROR;
744 file_size = rb->filesize(fd); 766 file_size = rb->filesize(fd);
@@ -749,15 +771,13 @@ int main(char* filename)
749 771
750 // init playback state 772 // init playback state
751 rb->memset(&gPlay, 0, sizeof(gPlay)); 773 rb->memset(&gPlay, 0, sizeof(gPlay));
752 gPlay.state = playing;
753 774
754 // init buffer 775 // init buffer
755 rb->memset(&gBuf, 0, sizeof(gBuf)); 776 rb->memset(&gBuf, 0, sizeof(gBuf));
756 gBuf.pOSD = rb->lcd_framebuffer + LCD_WIDTH*7; // last screen line 777 gBuf.pOSD = rb->lcd_framebuffer + LCD_WIDTH*7; // last screen line
757 gBuf.pBufStart = rb->plugin_get_mp3_buffer(&gBuf.bufsize); 778 gBuf.pBufStart = rb->plugin_get_mp3_buffer(&gBuf.bufsize);
758 //gBuf.bufsize = 1700*1024; // test!!!! 779 //gBuf.bufsize = 1700*1024; // test, like 2MB version!!!!
759 gBuf.pBufFill = gBuf.pBufStart; // all empty 780 gBuf.pBufFill = gBuf.pBufStart; // all empty
760 gBuf.pReadVideo = gBuf.pReadAudio = gBuf.pBufStart;
761 781
762 // load file header 782 // load file header
763 read_now = sizeof(gFileHdr); 783 read_now = sizeof(gFileHdr);
@@ -800,19 +820,10 @@ int main(char* filename)
800 gBuf.nSeekChunk += gBuf.granularity - 1; // round up 820 gBuf.nSeekChunk += gBuf.granularity - 1; // round up
801 gBuf.nSeekChunk -= gBuf.nSeekChunk % gBuf.granularity; // and align 821 gBuf.nSeekChunk -= gBuf.nSeekChunk % gBuf.granularity; // and align
802 822
803 // precharge buffer with more data
804 read_now = MAX(gFileHdr.audio_1st_frame, gFileHdr.video_1st_frame);
805 read_now = (read_now + PRECHARGE + gBuf.granularity - 1);
806 read_now -= read_now % gBuf.granularity; // round up to granularity
807 got_now = rb->read(fd, gBuf.pBufFill, read_now);
808 gBuf.pBufFill += got_now;
809
810 // prepare video playback, if contained 823 // prepare video playback, if contained
811 if (gFileHdr.video_format == VIDEOFORMAT_RAW) 824 if (gFileHdr.video_format == VIDEOFORMAT_RAW)
812 { 825 {
813 gBuf.pReadVideo += gFileHdr.video_1st_frame;
814 gPlay.bHasVideo = true; 826 gPlay.bHasVideo = true;
815
816 if (rb->global_settings->backlight_timeout > 0) 827 if (rb->global_settings->backlight_timeout > 0)
817 rb->backlight_set_timeout(1); // keep the light on 828 rb->backlight_set_timeout(1); // keep the light on
818 } 829 }
@@ -820,21 +831,16 @@ int main(char* filename)
820 // prepare audio playback, if contained 831 // prepare audio playback, if contained
821 if (gFileHdr.audio_format == AUDIOFORMAT_MP3_BITSWAPPED) 832 if (gFileHdr.audio_format == AUDIOFORMAT_MP3_BITSWAPPED)
822 { 833 {
823 gBuf.pReadAudio += gFileHdr.audio_1st_frame;
824 gPlay.bHasAudio = true; 834 gPlay.bHasAudio = true;
825
826 rb->mp3_play_init(); 835 rb->mp3_play_init();
827 rb->mp3_play_data(gBuf.pReadAudio + gFileHdr.audio_headersize,
828 gFileHdr.blocksize - gFileHdr.audio_headersize, GetMoreMp3);
829 rb->mpeg_sound_set(SOUND_VOLUME, rb->global_settings->volume); 836 rb->mpeg_sound_set(SOUND_VOLUME, rb->global_settings->volume);
830 } 837 }
831 838
832 // synchronous start 839 // start playback by seeking to zero or resume position
833 gPlay.state = playing; 840 if (gFileHdr.resume_pos && WantResume(fd)) // ask the user
834 if (gPlay.bHasAudio) 841 SeekTo(fd, gFileHdr.resume_pos);
835 rb->mp3_play_pause(true); // kickoff audio 842 else
836 if (gPlay.bHasVideo) 843 SeekTo(fd, 0);
837 timer_set(gFileHdr.video_frametime); // start display interrupt
838 844
839 // all that's left to do is keep the buffer full 845 // all that's left to do is keep the buffer full
840 do // the main loop 846 do // the main loop