summaryrefslogtreecommitdiff
path: root/apps/plugins/video.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/video.c')
-rw-r--r--apps/plugins/video.c495
1 files changed, 247 insertions, 248 deletions
diff --git a/apps/plugins/video.c b/apps/plugins/video.c
index 53535597c9..e82ec1a84f 100644
--- a/apps/plugins/video.c
+++ b/apps/plugins/video.c
@@ -27,10 +27,10 @@
27#include "plugin.h" 27#include "plugin.h"
28#include "sh7034.h" 28#include "sh7034.h"
29#include "system.h" 29#include "system.h"
30#include "../apps/recorder/widgets.h" // not in search path, booh 30#include "../apps/recorder/widgets.h" /* not in search path, booh */
31 31
32#ifndef SIMULATOR // not for simulator by now 32#ifndef SIMULATOR /* not for simulator by now */
33#ifdef HAVE_LCD_BITMAP // and definitely not for the Player, haha 33#ifdef HAVE_LCD_BITMAP /* and definitely not for the Player, haha */
34 34
35PLUGIN_HEADER 35PLUGIN_HEADER
36 36
@@ -52,89 +52,89 @@ PLUGIN_HEADER
52#endif 52#endif
53/****************** constants ******************/ 53/****************** constants ******************/
54 54
55#define SCREENSIZE (LCD_WIDTH*LCD_HEIGHT/8) // in bytes 55#define SCREENSIZE (LCD_WIDTH*LCD_HEIGHT/8) /* in bytes */
56#define FPS 68 // default fps for headerless (old video-only) file 56#define FPS 68 /* default fps for headerless (old video-only) file */
57#define MAX_ACC 20 // maximum FF/FR speedup 57#define MAX_ACC 20 /* maximum FF/FR speedup */
58#define FF_TICKS 3000; // experimentally found nice 58#define FF_TICKS 3000; /* experimentally found nice */
59 59
60// trigger levels, we need about 80 kB/sec 60/* trigger levels, we need about 80 kB/sec */
61#define SPINUP_INIT 5000 // from what level on to refill, in milliseconds 61#define SPINUP_INIT 5000 /* from what level on to refill, in milliseconds */
62#define SPINUP_SAFETY 700 // how much on top of the measured spinup time 62#define SPINUP_SAFETY 700 /* how much on top of the measured spinup time */
63#define CHUNK (1024*32) // read size 63#define CHUNK (1024*32) /* read size */
64 64
65 65
66/****************** prototypes ******************/ 66/****************** prototypes ******************/
67void timer4_isr(void); // IMIA4 ISR 67void timer4_isr(void); /* IMIA4 ISR */
68int check_button(void); // determine next relative frame 68int check_button(void); /* determine next relative frame */
69 69
70 70
71/****************** data types ******************/ 71/****************** data types ******************/
72 72
73// plugins don't introduce headers, so structs are repeated from rvf_format.h 73/* plugins don't introduce headers, so structs are repeated from rvf_format.h */
74 74
75#define HEADER_MAGIC 0x52564668 // "RVFh" at file start 75#define HEADER_MAGIC 0x52564668 /* "RVFh" at file start */
76#define AUDIO_MAGIC 0x41756446 // "AudF" for each audio block 76#define AUDIO_MAGIC 0x41756446 /* "AudF" for each audio block */
77#define FILEVERSION 100 // 1.00 77#define FILEVERSION 100 /* 1.00 */
78 78
79// format type definitions 79/* format type definitions */
80#define VIDEOFORMAT_NO_VIDEO 0 80#define VIDEOFORMAT_NO_VIDEO 0
81#define VIDEOFORMAT_RAW 1 81#define VIDEOFORMAT_RAW 1
82#define AUDIOFORMAT_NO_AUDIO 0 82#define AUDIOFORMAT_NO_AUDIO 0
83#define AUDIOFORMAT_MP3 1 83#define AUDIOFORMAT_MP3 1
84#define AUDIOFORMAT_MP3_BITSWAPPED 2 84#define AUDIOFORMAT_MP3_BITSWAPPED 2
85 85
86// bit flags 86/* bit flags */
87#define FLAG_LOOP 0x00000001 // loop the playback, e.g. for stills 87#define FLAG_LOOP 0x00000001 /* loop the playback, e.g. for stills */
88 88
89typedef struct // contains whatever might be useful to the player 89typedef struct /* contains whatever might be useful to the player */
90{ 90{
91 // general info (16 entries = 64 byte) 91 /* general info (16 entries = 64 byte) */
92 unsigned long magic; // HEADER_MAGIC 92 unsigned long magic; /* HEADER_MAGIC */
93 unsigned long version; // file version 93 unsigned long version; /* file version */
94 unsigned long flags; // combination of FLAG_xx 94 unsigned long flags; /* combination of FLAG_xx */
95 unsigned long blocksize; // how many bytes per block (=video frame) 95 unsigned long blocksize; /* how many bytes per block (=video frame) */
96 unsigned long bps_average; // bits per second of the whole stream 96 unsigned long bps_average; /* bits per second of the whole stream */
97 unsigned long bps_peak; // max. of above (audio may be VBR) 97 unsigned long bps_peak; /* max. of above (audio may be VBR) */
98 unsigned long resume_pos; // file position to resume to 98 unsigned long resume_pos; /* file position to resume to */
99 unsigned long reserved[9]; // reserved, should be zero 99 unsigned long reserved[9]; /* reserved, should be zero */
100 100
101 // video info (16 entries = 64 byte) 101 /* video info (16 entries = 64 byte) */
102 unsigned long video_format; // one of VIDEOFORMAT_xxx 102 unsigned long video_format; /* one of VIDEOFORMAT_xxx */
103 unsigned long video_1st_frame; // byte position of first video frame 103 unsigned long video_1st_frame; /* byte position of first video frame */
104 unsigned long video_duration; // total length of video part, in ms 104 unsigned long video_duration; /* total length of video part, in ms */
105 unsigned long video_payload_size; // total amount of video data, in bytes 105 unsigned long video_payload_size; /* total amount of video data, in bytes */
106 unsigned long video_bitrate; // derived from resolution and frame time, in bps 106 unsigned long video_bitrate; /* derived from resolution and frame time, in bps */
107 unsigned long video_frametime; // frame interval in 11.0592 MHz clocks 107 unsigned long video_frametime; /* frame interval in 11.0592 MHz clocks */
108 long video_preroll; // video is how much ahead, in 11.0592 MHz clocks 108 long video_preroll; /* video is how much ahead, in 11.0592 MHz clocks */
109 unsigned long video_width; // in pixels 109 unsigned long video_width; /* in pixels */
110 unsigned long video_height; // in pixels 110 unsigned long video_height; /* in pixels */
111 unsigned long video_reserved[7]; // reserved, should be zero 111 unsigned long video_reserved[7]; /* reserved, should be zero */
112 112
113 // audio info (16 entries = 64 byte) 113 /* audio info (16 entries = 64 byte) */
114 unsigned long audio_format; // one of AUDIOFORMAT_xxx 114 unsigned long audio_format; /* one of AUDIOFORMAT_xxx */
115 unsigned long audio_1st_frame; // byte position of first video frame 115 unsigned long audio_1st_frame; /* byte position of first video frame */
116 unsigned long audio_duration; // total length of audio part, in ms 116 unsigned long audio_duration; /* total length of audio part, in ms */
117 unsigned long audio_payload_size; // total amount of audio data, in bytes 117 unsigned long audio_payload_size; /* total amount of audio data, in bytes */
118 unsigned long audio_avg_bitrate; // average audio bitrate, in bits per second 118 unsigned long audio_avg_bitrate; /* average audio bitrate, in bits per second */
119 unsigned long audio_peak_bitrate; // maximum bitrate 119 unsigned long audio_peak_bitrate; /* maximum bitrate */
120 unsigned long audio_headersize; // offset to payload in audio frames 120 unsigned long audio_headersize; /* offset to payload in audio frames */
121 long audio_min_associated; // minimum offset to video frame, in bytes 121 long audio_min_associated; /* minimum offset to video frame, in bytes */
122 long audio_max_associated; // maximum offset to video frame, in bytes 122 long audio_max_associated; /* maximum offset to video frame, in bytes */
123 unsigned long audio_reserved[7]; // reserved, should be zero 123 unsigned long audio_reserved[7]; /* reserved, should be zero */
124 124
125 // more to come... ? 125 /* more to come... ? */
126 126
127 // Note: padding up to 'blocksize' with zero following this header 127 /* Note: padding up to 'blocksize' with zero following this header */
128} tFileHeader; 128} tFileHeader;
129 129
130typedef struct // the little header for all audio blocks 130typedef struct /* the little header for all audio blocks */
131{ 131{
132 unsigned long magic; // AUDIO_MAGIC indicates an audio block 132 unsigned long magic; /* AUDIO_MAGIC indicates an audio block */
133 unsigned char previous_block; // previous how many blocks backwards 133 unsigned char previous_block; /* previous how many blocks backwards */
134 unsigned char next_block; // next how many blocks forward 134 unsigned char next_block; /* next how many blocks forward */
135 short associated_video; // offset to block with corresponding video 135 short associated_video; /* offset to block with corresponding video */
136 unsigned short frame_start; // offset to first frame starting in this block 136 unsigned short frame_start; /* offset to first frame starting in this block */
137 unsigned short frame_end; // offset to behind last frame ending in this block 137 unsigned short frame_end; /* offset to behind last frame ending in this block */
138} tAudioFrameHeader; 138} tAudioFrameHeader;
139 139
140 140
@@ -145,7 +145,7 @@ static struct plugin_api* rb; /* here is a global api struct pointer */
145static char gPrint[32]; /* a global printf buffer, saves stack */ 145static char gPrint[32]; /* a global printf buffer, saves stack */
146 146
147 147
148// playstate 148/* playstate */
149static struct 149static struct
150{ 150{
151 enum 151 enum
@@ -157,40 +157,40 @@ static struct
157 bool bVideoUnderrun; 157 bool bVideoUnderrun;
158 bool bHasAudio; 158 bool bHasAudio;
159 bool bHasVideo; 159 bool bHasVideo;
160 int nTimeOSD; // OSD should stay for this many frames 160 int nTimeOSD; /* OSD should stay for this many frames */
161 bool bDirtyOSD; // OSD needs redraw 161 bool bDirtyOSD; /* OSD needs redraw */
162 bool bRefilling; // set if refilling buffer 162 bool bRefilling; /* set if refilling buffer */
163 bool bSeeking; 163 bool bSeeking;
164 int nSeekAcc; // accelleration value for seek 164 int nSeekAcc; /* accelleration value for seek */
165 int nSeekPos; // current file position for seek 165 int nSeekPos; /* current file position for seek */
166 bool bDiskSleep; // disk is suspended 166 bool bDiskSleep; /* disk is suspended */
167#if FREQ == 12000000 /* Ondio speed kludge */ 167#if FREQ == 12000000 /* Ondio speed kludge */
168 int nFrameTimeAdjusted; 168 int nFrameTimeAdjusted;
169#endif 169#endif
170} gPlay; 170} gPlay;
171 171
172// buffer information 172/* buffer information */
173static struct 173static struct
174{ 174{
175 int bufsize; 175 int bufsize;
176 int granularity; // common multiple of block and sector size 176 int granularity; /* common multiple of block and sector size */
177 unsigned char* pBufStart; // start of ring buffer 177 unsigned char* pBufStart; /* start of ring buffer */
178 unsigned char* pBufEnd; // end of ring buffer 178 unsigned char* pBufEnd; /* end of ring buffer */
179 unsigned char* pOSD; // OSD memory (112 bytes for 112*8 pixels) 179 unsigned char* pOSD; /* OSD memory (112 bytes for 112*8 pixels) */
180 180
181 int vidcount; // how many video blocks are known in a row 181 int vidcount; /* how many video blocks are known in a row */
182 unsigned char* pBufFill; // write pointer for disk, owned by main task 182 unsigned char* pBufFill; /* write pointer for disk, owned by main task */
183 unsigned char* pReadVideo; // video readout, maintained by timer ISR 183 unsigned char* pReadVideo; /* video readout, maintained by timer ISR */
184 unsigned char* pReadAudio; // audio readout, maintained by demand ISR 184 unsigned char* pReadAudio; /* audio readout, maintained by demand ISR */
185 bool bEOF; // flag for end of file 185 bool bEOF; /* flag for end of file */
186 int low_water; // reload threshold 186 int low_water; /* reload threshold */
187 int high_water; // end of reload threshold 187 int high_water; /* end of reload threshold */
188 int spinup_safety; // safety margin when recalculating low_water 188 int spinup_safety; /* safety margin when recalculating low_water */
189 int nReadChunk; // how much data for normal buffer fill 189 int nReadChunk; /* how much data for normal buffer fill */
190 int nSeekChunk; // how much data while seeking 190 int nSeekChunk; /* how much data while seeking */
191} gBuf; 191} gBuf;
192 192
193// statistics 193/* statistics */
194static struct 194static struct
195{ 195{
196 int minAudioAvail; 196 int minAudioAvail;
@@ -201,11 +201,11 @@ static struct
201 long maxSpinup; 201 long maxSpinup;
202} gStats; 202} gStats;
203 203
204tFileHeader gFileHdr; // file header 204tFileHeader gFileHdr; /* file header */
205 205
206/****************** implementation ******************/ 206/****************** implementation ******************/
207 207
208// tool function: return how much playable audio/video is left 208/* tool function: return how much playable audio/video is left */
209int Available(unsigned char* pSnapshot) 209int Available(unsigned char* pSnapshot)
210{ 210{
211 if (pSnapshot <= gBuf.pBufFill) 211 if (pSnapshot <= gBuf.pBufFill)
@@ -214,35 +214,35 @@ int Available(unsigned char* pSnapshot)
214 return gBuf.bufsize - (pSnapshot - gBuf.pBufFill); 214 return gBuf.bufsize - (pSnapshot - gBuf.pBufFill);
215} 215}
216 216
217// debug function to draw buffer indicators 217/* debug function to draw buffer indicators */
218void DrawBuf(void) 218void DrawBuf(void)
219{ 219{
220 int fill, video, audio; 220 int fill, video, audio;
221 221
222 rb->memset(gBuf.pOSD, 0x10, LCD_WIDTH); // draw line 222 rb->memset(gBuf.pOSD, 0x10, LCD_WIDTH); /* draw line */
223 gBuf.pOSD[0] = gBuf.pOSD[LCD_WIDTH-1] = 0xFE; // ends 223 gBuf.pOSD[0] = gBuf.pOSD[LCD_WIDTH-1] = 0xFE; /* ends */
224 224
225 // calculate new tick positions 225 /* calculate new tick positions */
226 fill = 1 + ((gBuf.pBufFill - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize; 226 fill = 1 + ((gBuf.pBufFill - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize;
227 video = 1 + ((gBuf.pReadVideo - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize; 227 video = 1 + ((gBuf.pReadVideo - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize;
228 audio = 1 + ((gBuf.pReadAudio - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize; 228 audio = 1 + ((gBuf.pReadAudio - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize;
229 229
230 gBuf.pOSD[fill] |= 0x20; // below the line, two pixels 230 gBuf.pOSD[fill] |= 0x20; /* below the line, two pixels */
231 gBuf.pOSD[video] |= 0x08; // one above 231 gBuf.pOSD[video] |= 0x08; /* one above */
232 gBuf.pOSD[audio] |= 0x04; // two above 232 gBuf.pOSD[audio] |= 0x04; /* two above */
233 233
234 if (gPlay.state == paused) // we have to draw ourselves 234 if (gPlay.state == paused) /* we have to draw ourselves */
235 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8); 235 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);
236 else 236 else
237 gPlay.bDirtyOSD = true; // redraw it with next timer IRQ 237 gPlay.bDirtyOSD = true; /* redraw it with next timer IRQ */
238} 238}
239 239
240 240
241// helper function to draw a position indicator 241/* helper function to draw a position indicator */
242void DrawPosition(int pos, int total) 242void DrawPosition(int pos, int total)
243{ 243{
244 int w,h; 244 int w,h;
245 int sec; // estimated seconds 245 int sec; /* estimated seconds */
246 246
247 247
248 /* print the estimated position */ 248 /* print the estimated position */
@@ -258,17 +258,17 @@ void DrawPosition(int pos, int total)
258 w++; 258 w++;
259 rb->scrollbar(w, LCD_HEIGHT-7, LCD_WIDTH-w, 7, total, 0, pos, HORIZONTAL); 259 rb->scrollbar(w, LCD_HEIGHT-7, LCD_WIDTH-w, 7, total, 0, pos, HORIZONTAL);
260 260
261 if (gPlay.state == paused) // we have to draw ourselves 261 if (gPlay.state == paused) /* we have to draw ourselves */
262 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8); 262 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);
263 else // let the display time do it 263 else /* let the display time do it */
264 { 264 {
265 gPlay.nTimeOSD = 70; 265 gPlay.nTimeOSD = 70;
266 gPlay.bDirtyOSD = true; // redraw it with next timer IRQ 266 gPlay.bDirtyOSD = true; /* redraw it with next timer IRQ */
267 } 267 }
268} 268}
269 269
270 270
271// helper function to change the volume by a certain amount, +/- 271/* helper function to change the volume by a certain amount, +/- */
272void ChangeVolume(int delta) 272void ChangeVolume(int delta)
273{ 273{
274 int minvol = rb->sound_min(SOUND_VOLUME); 274 int minvol = rb->sound_min(SOUND_VOLUME);
@@ -283,18 +283,18 @@ void ChangeVolume(int delta)
283 rb->global_settings->volume = vol; 283 rb->global_settings->volume = vol;
284 rb->snprintf(gPrint, sizeof(gPrint), "Vol: %d dB", vol); 284 rb->snprintf(gPrint, sizeof(gPrint), "Vol: %d dB", vol);
285 rb->lcd_puts(0, 7, gPrint); 285 rb->lcd_puts(0, 7, gPrint);
286 if (gPlay.state == paused) // we have to draw ourselves 286 if (gPlay.state == paused) /* we have to draw ourselves */
287 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8); 287 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);
288 else // let the display time do it 288 else /* let the display time do it */
289 { 289 {
290 gPlay.nTimeOSD = 50; // display it for 50 frames 290 gPlay.nTimeOSD = 50; /* display it for 50 frames */
291 gPlay.bDirtyOSD = true; // let the refresh copy it to LCD 291 gPlay.bDirtyOSD = true; /* let the refresh copy it to LCD */
292 } 292 }
293 } 293 }
294} 294}
295 295
296 296
297// helper function to change the LCD contrast by a certain amount, +/- 297/* helper function to change the LCD contrast by a certain amount, +/- */
298void ChangeContrast(int delta) 298void ChangeContrast(int delta)
299{ 299{
300 static int mycontrast = -1; /* the "permanent" value while running */ 300 static int mycontrast = -1; /* the "permanent" value while running */
@@ -312,18 +312,18 @@ void ChangeContrast(int delta)
312 mycontrast = contrast; 312 mycontrast = contrast;
313 rb->snprintf(gPrint, sizeof(gPrint), "Contrast: %d", contrast); 313 rb->snprintf(gPrint, sizeof(gPrint), "Contrast: %d", contrast);
314 rb->lcd_puts(0, 7, gPrint); 314 rb->lcd_puts(0, 7, gPrint);
315 if (gPlay.state == paused) // we have to draw ourselves 315 if (gPlay.state == paused) /* we have to draw ourselves */
316 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8); 316 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);
317 else // let the display time do it 317 else /* let the display time do it */
318 { 318 {
319 gPlay.nTimeOSD = 50; // display it for 50 frames 319 gPlay.nTimeOSD = 50; /* display it for 50 frames */
320 gPlay.bDirtyOSD = true; // let the refresh copy it to LCD 320 gPlay.bDirtyOSD = true; /* let the refresh copy it to LCD */
321 } 321 }
322 } 322 }
323} 323}
324 324
325 325
326// sync the video to the current audio 326/* sync the video to the current audio */
327void SyncVideo(void) 327void SyncVideo(void)
328{ 328{
329 tAudioFrameHeader* pAudioBuf; 329 tAudioFrameHeader* pAudioBuf;
@@ -331,12 +331,12 @@ void SyncVideo(void)
331 pAudioBuf = (tAudioFrameHeader*)(gBuf.pReadAudio); 331 pAudioBuf = (tAudioFrameHeader*)(gBuf.pReadAudio);
332 if (pAudioBuf->magic == AUDIO_MAGIC) 332 if (pAudioBuf->magic == AUDIO_MAGIC)
333 { 333 {
334 gBuf.vidcount = 0; // nothing known 334 gBuf.vidcount = 0; /* nothing known */
335 // sync the video position 335 /* sync the video position */
336 gBuf.pReadVideo = gBuf.pReadAudio + 336 gBuf.pReadVideo = gBuf.pReadAudio +
337 (long)pAudioBuf->associated_video * (long)gFileHdr.blocksize; 337 (long)pAudioBuf->associated_video * (long)gFileHdr.blocksize;
338 338
339 // handle possible wrap 339 /* handle possible wrap */
340 if (gBuf.pReadVideo >= gBuf.pBufEnd) 340 if (gBuf.pReadVideo >= gBuf.pBufEnd)
341 gBuf.pReadVideo -= gBuf.bufsize; 341 gBuf.pReadVideo -= gBuf.bufsize;
342 else if (gBuf.pReadVideo < gBuf.pBufStart) 342 else if (gBuf.pReadVideo < gBuf.pBufStart)
@@ -345,21 +345,21 @@ void SyncVideo(void)
345} 345}
346 346
347 347
348// timer interrupt handler to display a frame 348/* timer interrupt handler to display a frame */
349void timer4_isr(void) 349void timer4_isr(void)
350{ 350{
351 int available; 351 int available;
352 tAudioFrameHeader* pAudioBuf; 352 tAudioFrameHeader* pAudioBuf;
353 int height; // height to display 353 int height; /* height to display */
354 354
355 // reduce height if we have OSD on 355 /* reduce height if we have OSD on */
356 height = gFileHdr.video_height/8; 356 height = gFileHdr.video_height/8;
357 if (gPlay.nTimeOSD > 0) 357 if (gPlay.nTimeOSD > 0)
358 { 358 {
359 gPlay.nTimeOSD--; 359 gPlay.nTimeOSD--;
360 height = MIN(LCD_HEIGHT/8-1, height); // reserve bottom line 360 height = MIN(LCD_HEIGHT/8-1, height); /* reserve bottom line */
361 if (gPlay.bDirtyOSD) 361 if (gPlay.bDirtyOSD)
362 { // OSD to bottom line 362 { /* OSD to bottom line */
363 rb->lcd_blit(gBuf.pOSD, 0, LCD_HEIGHT/8-1, 363 rb->lcd_blit(gBuf.pOSD, 0, LCD_HEIGHT/8-1,
364 LCD_WIDTH, 1, LCD_WIDTH); 364 LCD_WIDTH, 1, LCD_WIDTH);
365 gPlay.bDirtyOSD = false; 365 gPlay.bDirtyOSD = false;
@@ -371,58 +371,58 @@ void timer4_isr(void)
371 371
372 available = Available(gBuf.pReadVideo); 372 available = Available(gBuf.pReadVideo);
373 373
374 // loop to skip audio frame(s) 374 /* loop to skip audio frame(s) */
375 while(1) 375 while(1)
376 { 376 {
377 // just for the statistics 377 /* just for the statistics */
378 if (!gBuf.bEOF && available < gStats.minVideoAvail) 378 if (!gBuf.bEOF && available < gStats.minVideoAvail)
379 gStats.minVideoAvail = available; 379 gStats.minVideoAvail = available;
380 380
381 if (available <= (int)gFileHdr.blocksize) 381 if (available <= (int)gFileHdr.blocksize)
382 { // no data for next frame 382 { /* no data for next frame */
383 383
384 if (gBuf.bEOF && (gFileHdr.flags & FLAG_LOOP)) 384 if (gBuf.bEOF && (gFileHdr.flags & FLAG_LOOP))
385 { // loop now, assuming the looped clip fits in memory 385 { /* loop now, assuming the looped clip fits in memory */
386 gBuf.pReadVideo = gBuf.pBufStart + gFileHdr.video_1st_frame; 386 gBuf.pReadVideo = gBuf.pBufStart + gFileHdr.video_1st_frame;
387 // FixMe: pReadVideo is incremented below 387 /* FixMe: pReadVideo is incremented below */
388 } 388 }
389 else 389 else
390 { 390 {
391 gPlay.bVideoUnderrun = true; 391 gPlay.bVideoUnderrun = true;
392 rb->timer_unregister(); // disable ourselves 392 rb->timer_unregister(); /* disable ourselves */
393 return; // no data available 393 return; /* no data available */
394 } 394 }
395 } 395 }
396 else // normal advance for next time 396 else /* normal advance for next time */
397 { 397 {
398 gBuf.pReadVideo += gFileHdr.blocksize; 398 gBuf.pReadVideo += gFileHdr.blocksize;
399 if (gBuf.pReadVideo >= gBuf.pBufEnd) 399 if (gBuf.pReadVideo >= gBuf.pBufEnd)
400 gBuf.pReadVideo -= gBuf.bufsize; // wraparound 400 gBuf.pReadVideo -= gBuf.bufsize; /* wraparound */
401 available -= gFileHdr.blocksize; 401 available -= gFileHdr.blocksize;
402 } 402 }
403 403
404 if (!gPlay.bHasAudio) 404 if (!gPlay.bHasAudio)
405 break; // no need to skip any audio 405 break; /* no need to skip any audio */
406 406
407 if (gBuf.vidcount) 407 if (gBuf.vidcount)
408 { 408 {
409 // we know the next is a video frame 409 /* we know the next is a video frame */
410 gBuf.vidcount--; 410 gBuf.vidcount--;
411 break; // exit the loop 411 break; /* exit the loop */
412 } 412 }
413 413
414 pAudioBuf = (tAudioFrameHeader*)(gBuf.pReadVideo); 414 pAudioBuf = (tAudioFrameHeader*)(gBuf.pReadVideo);
415 if (pAudioBuf->magic == AUDIO_MAGIC) 415 if (pAudioBuf->magic == AUDIO_MAGIC)
416 { // we ran into audio, can happen after seek 416 { /* we ran into audio, can happen after seek */
417 gBuf.vidcount = pAudioBuf->next_block; 417 gBuf.vidcount = pAudioBuf->next_block;
418 if (gBuf.vidcount) 418 if (gBuf.vidcount)
419 gBuf.vidcount--; // minus the audio block 419 gBuf.vidcount--; /* minus the audio block */
420 } 420 }
421 } // while 421 } /* while */
422} 422}
423 423
424 424
425// ISR function to get more mp3 data 425/* ISR function to get more mp3 data */
426void GetMoreMp3(unsigned char** start, int* size) 426void GetMoreMp3(unsigned char** start, int* size)
427{ 427{
428 int available; 428 int available;
@@ -434,19 +434,19 @@ void GetMoreMp3(unsigned char** start, int* size)
434 434
435 available = Available(gBuf.pReadAudio); 435 available = Available(gBuf.pReadAudio);
436 436
437 // just for the statistics 437 /* just for the statistics */
438 if (!gBuf.bEOF && available < gStats.minAudioAvail) 438 if (!gBuf.bEOF && available < gStats.minAudioAvail)
439 gStats.minAudioAvail = available; 439 gStats.minAudioAvail = available;
440 440
441 if (available < advance + (int)gFileHdr.blocksize || advance == 0) 441 if (available < advance + (int)gFileHdr.blocksize || advance == 0)
442 { 442 {
443 gPlay.bAudioUnderrun = true; 443 gPlay.bAudioUnderrun = true;
444 return; // no data available 444 return; /* no data available */
445 } 445 }
446 446
447 gBuf.pReadAudio += advance; 447 gBuf.pReadAudio += advance;
448 if (gBuf.pReadAudio >= gBuf.pBufEnd) 448 if (gBuf.pReadAudio >= gBuf.pBufEnd)
449 gBuf.pReadAudio -= gBuf.bufsize; // wraparound 449 gBuf.pReadAudio -= gBuf.bufsize; /* wraparound */
450 450
451 *start = gBuf.pReadAudio + gFileHdr.audio_headersize; 451 *start = gBuf.pReadAudio + gFileHdr.audio_headersize;
452 *size = gFileHdr.blocksize - gFileHdr.audio_headersize; 452 *size = gFileHdr.blocksize - gFileHdr.audio_headersize;
@@ -489,23 +489,23 @@ int SeekTo(int fd, int nPos)
489 int read_now, got_now; 489 int read_now, got_now;
490 490
491 if (gPlay.bHasAudio) 491 if (gPlay.bHasAudio)
492 rb->mp3_play_stop(); // stop audio ISR 492 rb->mp3_play_stop(); /* stop audio ISR */
493 if (gPlay.bHasVideo) 493 if (gPlay.bHasVideo)
494 rb->timer_unregister(); // stop the timer 494 rb->timer_unregister(); /* stop the timer */
495 495
496 rb->lseek(fd, nPos, SEEK_SET); 496 rb->lseek(fd, nPos, SEEK_SET);
497 497
498 gBuf.pBufFill = gBuf.pBufStart; // all empty 498 gBuf.pBufFill = gBuf.pBufStart; /* all empty */
499 gBuf.pReadVideo = gBuf.pReadAudio = gBuf.pBufStart; 499 gBuf.pReadVideo = gBuf.pReadAudio = gBuf.pBufStart;
500 500
501 read_now = gBuf.low_water - 1; // less than low water, so loading will continue 501 read_now = gBuf.low_water - 1; /* less than low water, so loading will continue */
502 read_now -= read_now % gBuf.granularity; // round down to granularity 502 read_now -= read_now % gBuf.granularity; /* round down to granularity */
503 got_now = rb->read(fd, gBuf.pBufFill, read_now); 503 got_now = rb->read(fd, gBuf.pBufFill, read_now);
504 gBuf.bEOF = (read_now != got_now); 504 gBuf.bEOF = (read_now != got_now);
505 gBuf.pBufFill += got_now; 505 gBuf.pBufFill += got_now;
506 506
507 if (nPos == 0) 507 if (nPos == 0)
508 { // we seeked to the start 508 { /* we seeked to the start */
509 if (gPlay.bHasVideo) 509 if (gPlay.bHasVideo)
510 gBuf.pReadVideo += gFileHdr.video_1st_frame; 510 gBuf.pReadVideo += gFileHdr.video_1st_frame;
511 511
@@ -513,31 +513,31 @@ int SeekTo(int fd, int nPos)
513 gBuf.pReadAudio += gFileHdr.audio_1st_frame; 513 gBuf.pReadAudio += gFileHdr.audio_1st_frame;
514 } 514 }
515 else 515 else
516 { // we have to search for the positions 516 { /* we have to search for the positions */
517 if (gPlay.bHasAudio) // prepare audio playback, if contained 517 if (gPlay.bHasAudio) /* prepare audio playback, if contained */
518 { 518 {
519 // search for audio frame 519 /* search for audio frame */
520 while (((tAudioFrameHeader*)(gBuf.pReadAudio))->magic != AUDIO_MAGIC) 520 while (((tAudioFrameHeader*)(gBuf.pReadAudio))->magic != AUDIO_MAGIC)
521 gBuf.pReadAudio += gFileHdr.blocksize; 521 gBuf.pReadAudio += gFileHdr.blocksize;
522 522
523 if (gPlay.bHasVideo) 523 if (gPlay.bHasVideo)
524 SyncVideo(); // pick the right video for that 524 SyncVideo(); /* pick the right video for that */
525 } 525 }
526 } 526 }
527 527
528 // synchronous start 528 /* synchronous start */
529 gPlay.state = playing; 529 gPlay.state = playing;
530 if (gPlay.bHasAudio) 530 if (gPlay.bHasAudio)
531 { 531 {
532 gPlay.bAudioUnderrun = false; 532 gPlay.bAudioUnderrun = false;
533 rb->mp3_play_data(gBuf.pReadAudio + gFileHdr.audio_headersize, 533 rb->mp3_play_data(gBuf.pReadAudio + gFileHdr.audio_headersize,
534 gFileHdr.blocksize - gFileHdr.audio_headersize, GetMoreMp3); 534 gFileHdr.blocksize - gFileHdr.audio_headersize, GetMoreMp3);
535 rb->mp3_play_pause(true); // kickoff audio 535 rb->mp3_play_pause(true); /* kickoff audio */
536 } 536 }
537 if (gPlay.bHasVideo) 537 if (gPlay.bHasVideo)
538 { 538 {
539 gPlay.bVideoUnderrun = false; 539 gPlay.bVideoUnderrun = false;
540 // start display interrupt 540 /* start display interrupt */
541#if FREQ == 12000000 /* Ondio speed kludge */ 541#if FREQ == 12000000 /* Ondio speed kludge */
542 rb->timer_register(1, NULL, gPlay.nFrameTimeAdjusted, 1, timer4_isr); 542 rb->timer_register(1, NULL, gPlay.nFrameTimeAdjusted, 1, timer4_isr);
543#else 543#else
@@ -548,25 +548,25 @@ int SeekTo(int fd, int nPos)
548 return 0; 548 return 0;
549} 549}
550 550
551// called from default_event_handler_ex() or at end of playback 551/* called from default_event_handler_ex() or at end of playback */
552void Cleanup(void *fd) 552void Cleanup(void *fd)
553{ 553{
554 rb->close(*(int*)fd); // close the file 554 rb->close(*(int*)fd); /* close the file */
555 555
556 if (gPlay.bHasVideo) 556 if (gPlay.bHasVideo)
557 rb->timer_unregister(); // stop video ISR, now I can use the display again 557 rb->timer_unregister(); /* stop video ISR, now I can use the display again */
558 558
559 if (gPlay.bHasAudio) 559 if (gPlay.bHasAudio)
560 rb->mp3_play_stop(); // stop audio ISR 560 rb->mp3_play_stop(); /* stop audio ISR */
561 561
562 // restore normal backlight setting 562 /* restore normal backlight setting */
563 rb->backlight_set_timeout(rb->global_settings->backlight_timeout); 563 rb->backlight_set_timeout(rb->global_settings->backlight_timeout);
564 564
565 // restore normal contrast 565 /* restore normal contrast */
566 rb->lcd_set_contrast(rb->global_settings->contrast); 566 rb->lcd_set_contrast(rb->global_settings->contrast);
567} 567}
568 568
569// returns >0 if continue, =0 to stop, <0 to abort (USB) 569/* returns >0 if continue, =0 to stop, <0 to abort (USB) */
570int PlayTick(int fd) 570int PlayTick(int fd)
571{ 571{
572 int button; 572 int button;
@@ -575,7 +575,7 @@ int PlayTick(int fd)
575 int retval = 1; 575 int retval = 1;
576 int filepos; 576 int filepos;
577 577
578 // check buffer level 578 /* check buffer level */
579 579
580 if (gPlay.bHasAudio) 580 if (gPlay.bHasAudio)
581 avail_audio = Available(gBuf.pReadAudio); 581 avail_audio = Available(gBuf.pReadAudio);
@@ -593,41 +593,41 @@ int PlayTick(int fd)
593 && gBuf.bEOF) 593 && gBuf.bEOF)
594 { 594 {
595 if (gFileHdr.resume_pos) 595 if (gFileHdr.resume_pos)
596 { // we played til the end, clear resume position 596 { /* we played til the end, clear resume position */
597 gFileHdr.resume_pos = 0; 597 gFileHdr.resume_pos = 0;
598 rb->lseek(fd, 0, SEEK_SET); // save resume position 598 rb->lseek(fd, 0, SEEK_SET); /* save resume position */
599 rb->write(fd, &gFileHdr, sizeof(gFileHdr)); 599 rb->write(fd, &gFileHdr, sizeof(gFileHdr));
600 } 600 }
601 Cleanup(&fd); 601 Cleanup(&fd);
602 return 0; // all expired 602 return 0; /* all expired */
603 } 603 }
604 604
605 if (!gPlay.bRefilling || gBuf.bEOF) 605 if (!gPlay.bRefilling || gBuf.bEOF)
606 { // nothing to do 606 { /* nothing to do */
607 button = rb->button_get_w_tmo(HZ/10); 607 button = rb->button_get_w_tmo(HZ/10);
608 } 608 }
609 else 609 else
610 { // refill buffer 610 { /* refill buffer */
611 int read_now, got_now; 611 int read_now, got_now;
612 int buf_free; 612 int buf_free;
613 long spinup; // measure the spinup time 613 long spinup; /* measure the spinup time */
614 614
615 // how much can we reload, don't fill completely, would appear empty 615 /* how much can we reload, don't fill completely, would appear empty */
616 buf_free = gBuf.bufsize - MAX(avail_audio, avail_video) - gBuf.high_water; 616 buf_free = gBuf.bufsize - MAX(avail_audio, avail_video) - gBuf.high_water;
617 if (buf_free < 0) 617 if (buf_free < 0)
618 buf_free = 0; // just for safety 618 buf_free = 0; /* just for safety */
619 buf_free -= buf_free % gBuf.granularity; // round down to granularity 619 buf_free -= buf_free % gBuf.granularity; /* round down to granularity */
620 620
621 // in one piece max. up to buffer end (wrap after that) 621 /* in one piece max. up to buffer end (wrap after that) */
622 read_now = MIN(buf_free, gBuf.pBufEnd - gBuf.pBufFill); 622 read_now = MIN(buf_free, gBuf.pBufEnd - gBuf.pBufFill);
623 623
624 // load piecewise, to stay responsive 624 /* load piecewise, to stay responsive */
625 read_now = MIN(read_now, gBuf.nReadChunk); 625 read_now = MIN(read_now, gBuf.nReadChunk);
626 626
627 if (read_now == buf_free) 627 if (read_now == buf_free)
628 gPlay.bRefilling = false; // last piece requested 628 gPlay.bRefilling = false; /* last piece requested */
629 629
630 spinup = *rb->current_tick; // in case this is interesting below 630 spinup = *rb->current_tick; /* in case this is interesting below */
631 631
632 got_now = rb->read(fd, gBuf.pBufFill, read_now); 632 got_now = rb->read(fd, gBuf.pBufFill, read_now);
633 if (got_now != read_now || read_now == 0) 633 if (got_now != read_now || read_now == 0)
@@ -636,7 +636,7 @@ int PlayTick(int fd)
636 gPlay.bRefilling = false; 636 gPlay.bRefilling = false;
637 } 637 }
638 638
639 if (gPlay.bDiskSleep) // statistics about the spinup time 639 if (gPlay.bDiskSleep) /* statistics about the spinup time */
640 { 640 {
641 spinup = *rb->current_tick - spinup; 641 spinup = *rb->current_tick - spinup;
642 gPlay.bDiskSleep = false; 642 gPlay.bDiskSleep = false;
@@ -645,49 +645,48 @@ int PlayTick(int fd)
645 if (spinup < gStats.minSpinup) 645 if (spinup < gStats.minSpinup)
646 gStats.minSpinup = spinup; 646 gStats.minSpinup = spinup;
647 647
648 // recalculate the low water mark from real measurements 648 /* recalculate the low water mark from real measurements */
649 gBuf.low_water = (gStats.maxSpinup + gBuf.spinup_safety) 649 gBuf.low_water = (gStats.maxSpinup + gBuf.spinup_safety)
650 * gFileHdr.bps_peak / 8 / HZ; 650 * gFileHdr.bps_peak / 8 / HZ;
651 } 651 }
652 652
653 if (!gPlay.bRefilling 653 if (!gPlay.bRefilling
654 && rb->global_settings->disk_spindown < 20) // condition for test only 654 && rb->global_settings->disk_spindown < 20) /* condition for test only */
655 { 655 {
656 rb->ata_sleep(); // no point in leaving the disk run til timeout 656 rb->ata_sleep(); /* no point in leaving the disk run til timeout */
657 gPlay.bDiskSleep = true; 657 gPlay.bDiskSleep = true;
658 } 658 }
659 659
660 gBuf.pBufFill += got_now; 660 gBuf.pBufFill += got_now;
661 if (gBuf.pBufFill >= gBuf.pBufEnd) 661 if (gBuf.pBufFill >= gBuf.pBufEnd)
662 gBuf.pBufFill = gBuf.pBufStart; // wrap 662 gBuf.pBufFill = gBuf.pBufStart; /* wrap */
663 663
664 rb->yield(); // have mercy with the other threads 664 rb->yield(); /* have mercy with the other threads */
665 button = rb->button_get(false); 665 button = rb->button_get(false);
666 } 666 }
667 667
668 // check keypresses 668 /* check keypresses */
669 669
670 if (button != BUTTON_NONE) 670 if (button != BUTTON_NONE)
671 { 671 {
672 filepos = rb->lseek(fd, 0, SEEK_CUR); 672 filepos = rb->lseek(fd, 0, SEEK_CUR);
673 673
674 if (gPlay.bHasVideo) // video position is more accurate 674 if (gPlay.bHasVideo) /* video position is more accurate */
675 filepos -= Available(gBuf.pReadVideo); // take video position 675 filepos -= Available(gBuf.pReadVideo); /* take video position */
676 else 676 else
677 filepos -= Available(gBuf.pReadAudio); // else audio 677 filepos -= Available(gBuf.pReadAudio); /* else audio */
678 678
679 switch (button) 679 switch (button) { /* set exit conditions */
680 { // set exit conditions
681 case BUTTON_OFF: 680 case BUTTON_OFF:
682 if (gFileHdr.magic == HEADER_MAGIC // only if file has header 681 if (gFileHdr.magic == HEADER_MAGIC /* only if file has header */
683 && !(gFileHdr.flags & FLAG_LOOP)) // not for stills 682 && !(gFileHdr.flags & FLAG_LOOP)) /* not for stills */
684 { 683 {
685 gFileHdr.resume_pos = filepos; 684 gFileHdr.resume_pos = filepos;
686 rb->lseek(fd, 0, SEEK_SET); // save resume position 685 rb->lseek(fd, 0, SEEK_SET); /* save resume position */
687 rb->write(fd, &gFileHdr, sizeof(gFileHdr)); 686 rb->write(fd, &gFileHdr, sizeof(gFileHdr));
688 } 687 }
689 Cleanup(&fd); 688 Cleanup(&fd);
690 retval = 0; // signal "stopped" to caller 689 retval = 0; /* signal "stopped" to caller */
691 break; 690 break;
692 case VIDEO_STOP_SEEK: 691 case VIDEO_STOP_SEEK:
693#ifdef VIDEO_STOP_SEEK_PRE 692#ifdef VIDEO_STOP_SEEK_PRE
@@ -704,9 +703,9 @@ int PlayTick(int fd)
704 { 703 {
705 gPlay.state = paused; 704 gPlay.state = paused;
706 if (gPlay.bHasAudio) 705 if (gPlay.bHasAudio)
707 rb->mp3_play_pause(false); // pause audio 706 rb->mp3_play_pause(false); /* pause audio */
708 if (gPlay.bHasVideo) 707 if (gPlay.bHasVideo)
709 rb->timer_unregister(); // stop the timer 708 rb->timer_unregister(); /* stop the timer */
710 } 709 }
711 else if (gPlay.state == paused) 710 else if (gPlay.state == paused)
712 { 711 {
@@ -715,10 +714,10 @@ int PlayTick(int fd)
715 { 714 {
716 if (gPlay.bHasVideo) 715 if (gPlay.bHasVideo)
717 SyncVideo(); 716 SyncVideo();
718 rb->mp3_play_pause(true); // play audio 717 rb->mp3_play_pause(true); /* play audio */
719 } 718 }
720 if (gPlay.bHasVideo) 719 if (gPlay.bHasVideo)
721 { // start the video 720 { /* start the video */
722#if FREQ == 12000000 /* Ondio speed kludge */ 721#if FREQ == 12000000 /* Ondio speed kludge */
723 rb->timer_register(1, NULL, 722 rb->timer_register(1, NULL,
724 gPlay.nFrameTimeAdjusted, 1, timer4_isr); 723 gPlay.nFrameTimeAdjusted, 1, timer4_isr);
@@ -741,44 +740,44 @@ int PlayTick(int fd)
741 break; 740 break;
742 case BUTTON_LEFT: 741 case BUTTON_LEFT:
743 case BUTTON_LEFT | BUTTON_REPEAT: 742 case BUTTON_LEFT | BUTTON_REPEAT:
744 if (!gPlay.bSeeking) // prepare seek 743 if (!gPlay.bSeeking) /* prepare seek */
745 { 744 {
746 gPlay.nSeekPos = filepos; 745 gPlay.nSeekPos = filepos;
747 gPlay.bSeeking = true; 746 gPlay.bSeeking = true;
748 gPlay.nSeekAcc = 0; 747 gPlay.nSeekAcc = 0;
749 } 748 }
750 else if (gPlay.nSeekAcc > 0) // other direction, stop sliding 749 else if (gPlay.nSeekAcc > 0) /* other direction, stop sliding */
751 gPlay.nSeekAcc = 0; 750 gPlay.nSeekAcc = 0;
752 else 751 else
753 gPlay.nSeekAcc--; 752 gPlay.nSeekAcc--;
754 break; 753 break;
755 case BUTTON_RIGHT: 754 case BUTTON_RIGHT:
756 case BUTTON_RIGHT | BUTTON_REPEAT: 755 case BUTTON_RIGHT | BUTTON_REPEAT:
757 if (!gPlay.bSeeking) // prepare seek 756 if (!gPlay.bSeeking) /* prepare seek */
758 { 757 {
759 gPlay.nSeekPos = filepos; 758 gPlay.nSeekPos = filepos;
760 gPlay.bSeeking = true; 759 gPlay.bSeeking = true;
761 gPlay.nSeekAcc = 0; 760 gPlay.nSeekAcc = 0;
762 } 761 }
763 else if (gPlay.nSeekAcc < 0) // other direction, stop sliding 762 else if (gPlay.nSeekAcc < 0) /* other direction, stop sliding */
764 gPlay.nSeekAcc = 0; 763 gPlay.nSeekAcc = 0;
765 else 764 else
766 gPlay.nSeekAcc++; 765 gPlay.nSeekAcc++;
767 break; 766 break;
768#ifdef VIDEO_DEBUG 767#ifdef VIDEO_DEBUG
769 case VIDEO_DEBUG: // debug key 768 case VIDEO_DEBUG: /* debug key */
770 case VIDEO_DEBUG | BUTTON_REPEAT: 769 case VIDEO_DEBUG | BUTTON_REPEAT:
771 DrawBuf(); // show buffer status 770 DrawBuf(); /* show buffer status */
772 gPlay.nTimeOSD = 30; 771 gPlay.nTimeOSD = 30;
773 gPlay.bDirtyOSD = true; 772 gPlay.bDirtyOSD = true;
774 break; 773 break;
775#endif 774#endif
776 case VIDEO_CONTRAST_DOWN: // contrast down 775 case VIDEO_CONTRAST_DOWN: /* contrast down */
777 case VIDEO_CONTRAST_DOWN | BUTTON_REPEAT: 776 case VIDEO_CONTRAST_DOWN | BUTTON_REPEAT:
778 if (gPlay.bHasVideo) 777 if (gPlay.bHasVideo)
779 ChangeContrast(-1); 778 ChangeContrast(-1);
780 break; 779 break;
781 case VIDEO_CONTRAST_UP: // contrast up 780 case VIDEO_CONTRAST_UP: /* contrast up */
782 case VIDEO_CONTRAST_UP | BUTTON_REPEAT: 781 case VIDEO_CONTRAST_UP | BUTTON_REPEAT:
783 if (gPlay.bHasVideo) 782 if (gPlay.bHasVideo)
784 ChangeContrast(1); 783 ChangeContrast(1);
@@ -786,7 +785,7 @@ int PlayTick(int fd)
786 default: 785 default:
787 if (rb->default_event_handler_ex(button, Cleanup, &fd) 786 if (rb->default_event_handler_ex(button, Cleanup, &fd)
788 == SYS_USB_CONNECTED) 787 == SYS_USB_CONNECTED)
789 retval = -1; // signal "aborted" to caller 788 retval = -1; /* signal "aborted" to caller */
790 break; 789 break;
791 } 790 }
792 791
@@ -794,9 +793,9 @@ int PlayTick(int fd)
794 } /* if (button != BUTTON_NONE) */ 793 } /* if (button != BUTTON_NONE) */
795 794
796 795
797 // handle seeking 796 /* handle seeking */
798 797
799 if (gPlay.bSeeking) // seeking? 798 if (gPlay.bSeeking) /* seeking? */
800 { 799 {
801 if (gPlay.nSeekAcc < -MAX_ACC) 800 if (gPlay.nSeekAcc < -MAX_ACC)
802 gPlay.nSeekAcc = -MAX_ACC; 801 gPlay.nSeekAcc = -MAX_ACC;
@@ -815,23 +814,23 @@ int PlayTick(int fd)
815 } 814 }
816 815
817 816
818 // check + recover underruns 817 /* check + recover underruns */
819 818
820 if ((gPlay.bAudioUnderrun || gPlay.bVideoUnderrun) && !gBuf.bEOF) 819 if ((gPlay.bAudioUnderrun || gPlay.bVideoUnderrun) && !gBuf.bEOF)
821 { 820 {
822 gBuf.spinup_safety += HZ/2; // add extra spinup time for the future 821 gBuf.spinup_safety += HZ/2; /* add extra spinup time for the future */
823 filepos = rb->lseek(fd, 0, SEEK_CUR); 822 filepos = rb->lseek(fd, 0, SEEK_CUR);
824 823
825 if (gPlay.bHasVideo && gPlay.bVideoUnderrun) 824 if (gPlay.bHasVideo && gPlay.bVideoUnderrun)
826 { 825 {
827 gStats.nVideoUnderruns++; 826 gStats.nVideoUnderruns++;
828 filepos -= Available(gBuf.pReadVideo); // take video position 827 filepos -= Available(gBuf.pReadVideo); /* take video position */
829 SeekTo(fd, filepos); 828 SeekTo(fd, filepos);
830 } 829 }
831 else if (gPlay.bHasAudio && gPlay.bAudioUnderrun) 830 else if (gPlay.bHasAudio && gPlay.bAudioUnderrun)
832 { 831 {
833 gStats.nAudioUnderruns++; 832 gStats.nAudioUnderruns++;
834 filepos -= Available(gBuf.pReadAudio); // else audio 833 filepos -= Available(gBuf.pReadAudio); /* else audio */
835 SeekTo(fd, filepos); 834 SeekTo(fd, filepos);
836 } 835 }
837 } 836 }
@@ -848,46 +847,46 @@ int main(char* filename)
848 int button = 0; 847 int button = 0;
849 int retval; 848 int retval;
850 849
851 // try to open the file 850 /* try to open the file */
852 fd = rb->open(filename, O_RDWR); 851 fd = rb->open(filename, O_RDWR);
853 if (fd < 0) 852 if (fd < 0)
854 return PLUGIN_ERROR; 853 return PLUGIN_ERROR;
855 file_size = rb->filesize(fd); 854 file_size = rb->filesize(fd);
856 855
857 // reset pitch value to ensure synchronous playback 856 /* reset pitch value to ensure synchronous playback */
858 rb->sound_set_pitch(1000); 857 rb->sound_set_pitch(1000);
859 858
860 // init statistics 859 /* init statistics */
861 rb->memset(&gStats, 0, sizeof(gStats)); 860 rb->memset(&gStats, 0, sizeof(gStats));
862 gStats.minAudioAvail = gStats.minVideoAvail = INT_MAX; 861 gStats.minAudioAvail = gStats.minVideoAvail = INT_MAX;
863 gStats.minSpinup = INT_MAX; 862 gStats.minSpinup = INT_MAX;
864 863
865 // init playback state 864 /* init playback state */
866 rb->memset(&gPlay, 0, sizeof(gPlay)); 865 rb->memset(&gPlay, 0, sizeof(gPlay));
867 866
868 // init buffer 867 /* init buffer */
869 rb->memset(&gBuf, 0, sizeof(gBuf)); 868 rb->memset(&gBuf, 0, sizeof(gBuf));
870 gBuf.pOSD = rb->lcd_framebuffer + LCD_WIDTH*7; // last screen line 869 gBuf.pOSD = rb->lcd_framebuffer + LCD_WIDTH*7; /* last screen line */
871 gBuf.pBufStart = rb->plugin_get_audio_buffer(&gBuf.bufsize); 870 gBuf.pBufStart = rb->plugin_get_audio_buffer(&gBuf.bufsize);
872 //gBuf.bufsize = 1700*1024; // test, like 2MB version!!!! 871 /*gBuf.bufsize = 1700*1024; // test, like 2MB version!!!! */
873 gBuf.pBufFill = gBuf.pBufStart; // all empty 872 gBuf.pBufFill = gBuf.pBufStart; /* all empty */
874 873
875 // load file header 874 /* load file header */
876 read_now = sizeof(gFileHdr); 875 read_now = sizeof(gFileHdr);
877 got_now = rb->read(fd, &gFileHdr, read_now); 876 got_now = rb->read(fd, &gFileHdr, read_now);
878 rb->lseek(fd, 0, SEEK_SET); // rewind to restart sector-aligned 877 rb->lseek(fd, 0, SEEK_SET); /* rewind to restart sector-aligned */
879 if (got_now != read_now) 878 if (got_now != read_now)
880 { 879 {
881 rb->close(fd); 880 rb->close(fd);
882 return (PLUGIN_ERROR); 881 return (PLUGIN_ERROR);
883 } 882 }
884 883
885 // check header 884 /* check header */
886 if (gFileHdr.magic != HEADER_MAGIC) 885 if (gFileHdr.magic != HEADER_MAGIC)
887 { // old file, use default info 886 { /* old file, use default info */
888 rb->memset(&gFileHdr, 0, sizeof(gFileHdr)); 887 rb->memset(&gFileHdr, 0, sizeof(gFileHdr));
889 gFileHdr.blocksize = SCREENSIZE; 888 gFileHdr.blocksize = SCREENSIZE;
890 if (file_size < SCREENSIZE * FPS) // less than a second 889 if (file_size < SCREENSIZE * FPS) /* less than a second */
891 gFileHdr.flags |= FLAG_LOOP; 890 gFileHdr.flags |= FLAG_LOOP;
892 gFileHdr.video_format = VIDEOFORMAT_RAW; 891 gFileHdr.video_format = VIDEOFORMAT_RAW;
893 gFileHdr.video_width = LCD_WIDTH; 892 gFileHdr.video_width = LCD_WIDTH;
@@ -900,60 +899,60 @@ int main(char* filename)
900 gPlay.nFrameTimeAdjusted = (gFileHdr.video_frametime * 625) / 576; 899 gPlay.nFrameTimeAdjusted = (gFileHdr.video_frametime * 625) / 576;
901#endif 900#endif
902 901
903 // continue buffer init: align the end, calc low water, read sizes 902 /* continue buffer init: align the end, calc low water, read sizes */
904 gBuf.granularity = gFileHdr.blocksize; 903 gBuf.granularity = gFileHdr.blocksize;
905 while (gBuf.granularity % 512) // common multiple of sector size 904 while (gBuf.granularity % 512) /* common multiple of sector size */
906 gBuf.granularity *= 2; 905 gBuf.granularity *= 2;
907 gBuf.bufsize -= gBuf.bufsize % gBuf.granularity; // round down 906 gBuf.bufsize -= gBuf.bufsize % gBuf.granularity; /* round down */
908 gBuf.pBufEnd = gBuf.pBufStart + gBuf.bufsize; 907 gBuf.pBufEnd = gBuf.pBufStart + gBuf.bufsize;
909 gBuf.low_water = SPINUP_INIT * gFileHdr.bps_peak / 8000; 908 gBuf.low_water = SPINUP_INIT * gFileHdr.bps_peak / 8000;
910 gBuf.spinup_safety = SPINUP_SAFETY * HZ / 1000; // in time ticks 909 gBuf.spinup_safety = SPINUP_SAFETY * HZ / 1000; /* in time ticks */
911 if (gFileHdr.audio_min_associated < 0) 910 if (gFileHdr.audio_min_associated < 0)
912 gBuf.high_water = 0 - gFileHdr.audio_min_associated; 911 gBuf.high_water = 0 - gFileHdr.audio_min_associated;
913 else 912 else
914 gBuf.high_water = 1; // never fill buffer completely, would appear empty 913 gBuf.high_water = 1; /* never fill buffer completely, would appear empty */
915 gBuf.nReadChunk = (CHUNK + gBuf.granularity - 1); // round up 914 gBuf.nReadChunk = (CHUNK + gBuf.granularity - 1); /* round up */
916 gBuf.nReadChunk -= gBuf.nReadChunk % gBuf.granularity;// and align 915 gBuf.nReadChunk -= gBuf.nReadChunk % gBuf.granularity;/* and align */
917 gBuf.nSeekChunk = rb->filesize(fd) / FF_TICKS; 916 gBuf.nSeekChunk = rb->filesize(fd) / FF_TICKS;
918 gBuf.nSeekChunk += gBuf.granularity - 1; // round up 917 gBuf.nSeekChunk += gBuf.granularity - 1; /* round up */
919 gBuf.nSeekChunk -= gBuf.nSeekChunk % gBuf.granularity; // and align 918 gBuf.nSeekChunk -= gBuf.nSeekChunk % gBuf.granularity; /* and align */
920 919
921 // prepare video playback, if contained 920 /* prepare video playback, if contained */
922 if (gFileHdr.video_format == VIDEOFORMAT_RAW) 921 if (gFileHdr.video_format == VIDEOFORMAT_RAW)
923 { 922 {
924 gPlay.bHasVideo = true; 923 gPlay.bHasVideo = true;
925 if (rb->global_settings->backlight_timeout > 0) 924 if (rb->global_settings->backlight_timeout > 0)
926 rb->backlight_set_timeout(1); // keep the light on 925 rb->backlight_set_timeout(1); /* keep the light on */
927 } 926 }
928 927
929 // prepare audio playback, if contained 928 /* prepare audio playback, if contained */
930 if (gFileHdr.audio_format == AUDIOFORMAT_MP3_BITSWAPPED) 929 if (gFileHdr.audio_format == AUDIOFORMAT_MP3_BITSWAPPED)
931 { 930 {
932 gPlay.bHasAudio = true; 931 gPlay.bHasAudio = true;
933 } 932 }
934 933
935 // start playback by seeking to zero or resume position 934 /* start playback by seeking to zero or resume position */
936 if (gFileHdr.resume_pos && WantResume(fd)) // ask the user 935 if (gFileHdr.resume_pos && WantResume(fd)) /* ask the user */
937 SeekTo(fd, gFileHdr.resume_pos); 936 SeekTo(fd, gFileHdr.resume_pos);
938 else 937 else
939 SeekTo(fd, 0); 938 SeekTo(fd, 0);
940 939
941 // all that's left to do is keep the buffer full 940 /* all that's left to do is keep the buffer full */
942 do // the main loop 941 do /* the main loop */
943 { 942 {
944 retval = PlayTick(fd); 943 retval = PlayTick(fd);
945 } while (retval > 0); 944 } while (retval > 0);
946 945
947 if (retval < 0) // aborted? 946 if (retval < 0) /* aborted? */
948 { 947 {
949 return PLUGIN_USB_CONNECTED; 948 return PLUGIN_USB_CONNECTED;
950 } 949 }
951 950
952#ifndef DEBUG // for release compilations, only display the stats in case of error 951#ifndef DEBUG /* for release compilations, only display the stats in case of error */
953 if (gStats.nAudioUnderruns || gStats.nVideoUnderruns) 952 if (gStats.nAudioUnderruns || gStats.nVideoUnderruns)
954#endif 953#endif
955 { 954 {
956 // display statistics 955 /* display statistics */
957 rb->lcd_clear_display(); 956 rb->lcd_clear_display();
958 rb->snprintf(gPrint, sizeof(gPrint), "%d Audio Underruns", gStats.nAudioUnderruns); 957 rb->snprintf(gPrint, sizeof(gPrint), "%d Audio Underruns", gStats.nAudioUnderruns);
959 rb->lcd_puts(0, 0, gPrint); 958 rb->lcd_puts(0, 0, gPrint);
@@ -983,7 +982,7 @@ int main(char* filename)
983 982
984enum plugin_status plugin_start(struct plugin_api* api, void* parameter) 983enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
985{ 984{
986 rb = api; // copy to global api pointer 985 rb = api; /* copy to global api pointer */
987 986
988 if (parameter == NULL) 987 if (parameter == NULL)
989 { 988 {
@@ -991,10 +990,10 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
991 return PLUGIN_ERROR; 990 return PLUGIN_ERROR;
992 } 991 }
993 992
994 // now go ahead and have fun! 993 /* now go ahead and have fun! */
995 return main((char*) parameter); 994 return main((char*) parameter);
996} 995}
997 996
998#endif // #ifdef HAVE_LCD_BITMAP 997#endif /* #ifdef HAVE_LCD_BITMAP */
999#endif // #ifndef SIMULATOR 998#endif /* #ifndef SIMULATOR */
1000 999