summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/video.c39
1 files changed, 32 insertions, 7 deletions
diff --git a/apps/plugins/video.c b/apps/plugins/video.c
index ce7611d389..3e40f9af9c 100644
--- a/apps/plugins/video.c
+++ b/apps/plugins/video.c
@@ -43,8 +43,8 @@
43#define FF_TICKS 3000; // experimentally found nice 43#define FF_TICKS 3000; // experimentally found nice
44 44
45// trigger levels, we need about 80 kB/sec 45// trigger levels, we need about 80 kB/sec
46#define PRECHARGE (1024 * 64) // the initial filling before starting to play 46#define SPINUP_INIT 5000 // from what level on to refill, in milliseconds
47#define SPINUP 3300 // from what level on to refill, in milliseconds 47#define SPINUP_SAFETY 700 // how much on top of the measured spinup time
48#define CHUNK (1024*32) // read size 48#define CHUNK (1024*32) // read size
49 49
50 50
@@ -148,6 +148,7 @@ static struct
148 bool bSeeking; 148 bool bSeeking;
149 int nSeekAcc; // accelleration value for seek 149 int nSeekAcc; // accelleration value for seek
150 int nSeekPos; // current file position for seek 150 int nSeekPos; // current file position for seek
151 bool bDiskSleep; // disk is suspended
151} gPlay; 152} gPlay;
152 153
153// buffer information 154// buffer information
@@ -166,6 +167,7 @@ static struct
166 bool bEOF; // flag for end of file 167 bool bEOF; // flag for end of file
167 int low_water; // reload threshold 168 int low_water; // reload threshold
168 int high_water; // end of reload threshold 169 int high_water; // end of reload threshold
170 int spinup_safety; // safety margin when recalculating low_water
169 int nReadChunk; // how much data for normal buffer fill 171 int nReadChunk; // how much data for normal buffer fill
170 int nSeekChunk; // how much data while seeking 172 int nSeekChunk; // how much data while seeking
171} gBuf; 173} gBuf;
@@ -177,6 +179,8 @@ static struct
177 int minVideoAvail; 179 int minVideoAvail;
178 int nAudioUnderruns; 180 int nAudioUnderruns;
179 int nVideoUnderruns; 181 int nVideoUnderruns;
182 long minSpinup;
183 long maxSpinup;
180} gStats; 184} gStats;
181 185
182tFileHeader gFileHdr; // file header 186tFileHeader gFileHdr; // file header
@@ -485,8 +489,8 @@ int SeekTo(int fd, int nPos)
485 gBuf.pBufFill = gBuf.pBufStart; // all empty 489 gBuf.pBufFill = gBuf.pBufStart; // all empty
486 gBuf.pReadVideo = gBuf.pReadAudio = gBuf.pBufStart; 490 gBuf.pReadVideo = gBuf.pReadAudio = gBuf.pBufStart;
487 491
488 read_now = (PRECHARGE + gBuf.granularity - 1); // round up 492 read_now = gBuf.low_water - 1; // less than low water, so loading will continue
489 read_now -= read_now % gBuf.granularity; // to granularity 493 read_now -= read_now % gBuf.granularity; // round down to granularity
490 got_now = rb->read(fd, gBuf.pBufFill, read_now); 494 got_now = rb->read(fd, gBuf.pBufFill, read_now);
491 gBuf.bEOF = (read_now != got_now); 495 gBuf.bEOF = (read_now != got_now);
492 gBuf.pBufFill += got_now; 496 gBuf.pBufFill += got_now;
@@ -574,6 +578,7 @@ int PlayTick(int fd)
574 { // refill buffer 578 { // refill buffer
575 int read_now, got_now; 579 int read_now, got_now;
576 int buf_free; 580 int buf_free;
581 long spinup; // measure the spinup time
577 582
578 // how much can we reload, don't fill completely, would appear empty 583 // how much can we reload, don't fill completely, would appear empty
579 buf_free = gBuf.bufsize - MAX(avail_audio, avail_video) - gBuf.high_water; 584 buf_free = gBuf.bufsize - MAX(avail_audio, avail_video) - gBuf.high_water;
@@ -590,6 +595,8 @@ int PlayTick(int fd)
590 if (read_now == buf_free) 595 if (read_now == buf_free)
591 gPlay.bRefilling = false; // last piece requested 596 gPlay.bRefilling = false; // last piece requested
592 597
598 spinup = *rb->current_tick; // in case this is interesting below
599
593 got_now = rb->read(fd, gBuf.pBufFill, read_now); 600 got_now = rb->read(fd, gBuf.pBufFill, read_now);
594 if (got_now != read_now || read_now == 0) 601 if (got_now != read_now || read_now == 0)
595 { 602 {
@@ -597,10 +604,25 @@ int PlayTick(int fd)
597 gPlay.bRefilling = false; 604 gPlay.bRefilling = false;
598 } 605 }
599 606
607 if (gPlay.bDiskSleep) // statistics about the spinup time
608 {
609 spinup = *rb->current_tick - spinup;
610 gPlay.bDiskSleep = false;
611 if (spinup > gStats.maxSpinup)
612 gStats.maxSpinup = spinup;
613 if (spinup < gStats.minSpinup)
614 gStats.minSpinup = spinup;
615
616 // recalculate the low water mark from real measurements
617 gBuf.low_water = (gStats.maxSpinup + gBuf.spinup_safety)
618 * gFileHdr.bps_peak / 8 / HZ;
619 }
620
600 if (!gPlay.bRefilling 621 if (!gPlay.bRefilling
601 && rb->global_settings->disk_spindown < 20) // condition for test only 622 && rb->global_settings->disk_spindown < 20) // condition for test only
602 { 623 {
603 rb->ata_sleep(); // no point in leaving the disk run til timeout 624 rb->ata_sleep(); // no point in leaving the disk run til timeout
625 gPlay.bDiskSleep = true;
604 } 626 }
605 627
606 gBuf.pBufFill += got_now; 628 gBuf.pBufFill += got_now;
@@ -749,6 +771,7 @@ int PlayTick(int fd)
749 771
750 if ((gPlay.bAudioUnderrun || gPlay.bVideoUnderrun) && !gBuf.bEOF) 772 if ((gPlay.bAudioUnderrun || gPlay.bVideoUnderrun) && !gBuf.bEOF)
751 { 773 {
774 gBuf.spinup_safety += HZ/2; // add extra spinup time for the future
752 filepos = rb->lseek(fd, 0, SEEK_CUR); 775 filepos = rb->lseek(fd, 0, SEEK_CUR);
753 776
754 if (gPlay.bHasVideo && gPlay.bVideoUnderrun) 777 if (gPlay.bHasVideo && gPlay.bVideoUnderrun)
@@ -786,6 +809,7 @@ int main(char* filename)
786 // init statistics 809 // init statistics
787 rb->memset(&gStats, 0, sizeof(gStats)); 810 rb->memset(&gStats, 0, sizeof(gStats));
788 gStats.minAudioAvail = gStats.minVideoAvail = INT_MAX; 811 gStats.minAudioAvail = gStats.minVideoAvail = INT_MAX;
812 gStats.minSpinup = INT_MAX;
789 813
790 // init playback state 814 // init playback state
791 rb->memset(&gPlay, 0, sizeof(gPlay)); 815 rb->memset(&gPlay, 0, sizeof(gPlay));
@@ -827,7 +851,8 @@ int main(char* filename)
827 gBuf.granularity *= 2; 851 gBuf.granularity *= 2;
828 gBuf.bufsize -= gBuf.bufsize % gBuf.granularity; // round down 852 gBuf.bufsize -= gBuf.bufsize % gBuf.granularity; // round down
829 gBuf.pBufEnd = gBuf.pBufStart + gBuf.bufsize; 853 gBuf.pBufEnd = gBuf.pBufStart + gBuf.bufsize;
830 gBuf.low_water = SPINUP * gFileHdr.bps_peak / 8000; 854 gBuf.low_water = SPINUP_INIT * gFileHdr.bps_peak / 8000;
855 gBuf.spinup_safety = SPINUP_SAFETY * HZ / 1000; // in time ticks
831 if (gFileHdr.audio_min_associated < 0) 856 if (gFileHdr.audio_min_associated < 0)
832 gBuf.high_water = 0 - gFileHdr.audio_min_associated; 857 gBuf.high_water = 0 - gFileHdr.audio_min_associated;
833 else 858 else
@@ -897,9 +922,9 @@ int main(char* filename)
897 rb->lcd_puts(0, 2, gPrint); 922 rb->lcd_puts(0, 2, gPrint);
898 rb->snprintf(gPrint, sizeof(gPrint), "%d MinVideo bytes", gStats.minVideoAvail); 923 rb->snprintf(gPrint, sizeof(gPrint), "%d MinVideo bytes", gStats.minVideoAvail);
899 rb->lcd_puts(0, 3, gPrint); 924 rb->lcd_puts(0, 3, gPrint);
900 rb->snprintf(gPrint, sizeof(gPrint), "ReadChunk: %d", gBuf.nReadChunk); 925 rb->snprintf(gPrint, sizeof(gPrint), "MinSpinup %d.%02d", gStats.minSpinup/HZ, gStats.minSpinup%HZ);
901 rb->lcd_puts(0, 4, gPrint); 926 rb->lcd_puts(0, 4, gPrint);
902 rb->snprintf(gPrint, sizeof(gPrint), "SeekChunk: %d", gBuf.nSeekChunk); 927 rb->snprintf(gPrint, sizeof(gPrint), "MaxSpinup %d.%02d", gStats.maxSpinup/HZ, gStats.maxSpinup%HZ);
903 rb->lcd_puts(0, 5, gPrint); 928 rb->lcd_puts(0, 5, gPrint);
904 rb->snprintf(gPrint, sizeof(gPrint), "LowWater: %d", gBuf.low_water); 929 rb->snprintf(gPrint, sizeof(gPrint), "LowWater: %d", gBuf.low_water);
905 rb->lcd_puts(0, 6, gPrint); 930 rb->lcd_puts(0, 6, gPrint);