diff options
-rw-r--r-- | apps/plugins/video.c | 210 |
1 files changed, 181 insertions, 29 deletions
diff --git a/apps/plugins/video.c b/apps/plugins/video.c index 292b61a69c..c08708b19c 100644 --- a/apps/plugins/video.c +++ b/apps/plugins/video.c | |||
@@ -25,12 +25,120 @@ | |||
25 | #ifndef SIMULATOR /* not for simulator by now */ | 25 | #ifndef SIMULATOR /* not for simulator by now */ |
26 | #ifdef HAVE_LCD_BITMAP /* and definitely not for the Player, haha */ | 26 | #ifdef HAVE_LCD_BITMAP /* and definitely not for the Player, haha */ |
27 | 27 | ||
28 | #define DEFAULT_FILENAME "/default.rvf" | 28 | #define INT_MAX ((int)(~(unsigned)0 >> 1)) |
29 | #define INT_MIN (-INT_MAX-1) | ||
30 | |||
29 | #define SCREENSIZE (LCD_WIDTH*LCD_HEIGHT/8) /* in bytes */ | 31 | #define SCREENSIZE (LCD_WIDTH*LCD_HEIGHT/8) /* in bytes */ |
30 | #define FILEBUFSIZE SCREENSIZE*4 /* must result in a multiple of 512 */ | 32 | #define FILEBUFSIZE SCREENSIZE*4 /* must result in a multiple of 512 */ |
31 | 33 | ||
34 | #define WIND_STEP 5 | ||
35 | |||
36 | |||
37 | /* globals */ | ||
32 | static struct plugin_api* rb; /* here is a global api struct pointer */ | 38 | static struct plugin_api* rb; /* here is a global api struct pointer */ |
33 | 39 | ||
40 | static enum | ||
41 | { | ||
42 | playing, | ||
43 | paused, | ||
44 | stop, | ||
45 | exit | ||
46 | } state = playing; | ||
47 | |||
48 | static int playstep = 1; /* forcurrent speed and direction */ | ||
49 | static long time; /* to calculate the playing time */ | ||
50 | |||
51 | |||
52 | /* test for button, returns relative frame and may change state */ | ||
53 | int check_button(void) | ||
54 | { | ||
55 | int button; | ||
56 | int frame; | ||
57 | bool loop; | ||
58 | |||
59 | frame = playstep; /* default */ | ||
60 | |||
61 | do | ||
62 | { | ||
63 | loop = false; | ||
64 | if (state == playing) | ||
65 | button = rb->button_get(false); | ||
66 | else | ||
67 | { | ||
68 | long current = *rb->current_tick; | ||
69 | button = rb->button_get(true); /* block */ | ||
70 | time += *rb->current_tick - current; /* don't time while waiting */ | ||
71 | } | ||
72 | |||
73 | switch(button) | ||
74 | { | ||
75 | case BUTTON_NONE: | ||
76 | break; /* quick exit */ | ||
77 | |||
78 | case BUTTON_LEFT | BUTTON_REPEAT: | ||
79 | if (state == paused) | ||
80 | frame = -1; /* single step back */ | ||
81 | else if (state == playing) | ||
82 | playstep = -WIND_STEP; /* FR */ | ||
83 | break; | ||
84 | |||
85 | case BUTTON_RIGHT | BUTTON_REPEAT: | ||
86 | if (state == paused) | ||
87 | frame = 1; /* single step */ | ||
88 | else if (state == playing) | ||
89 | playstep = WIND_STEP; /* FF */ | ||
90 | break; | ||
91 | |||
92 | case BUTTON_PLAY: | ||
93 | if (state == playing && playstep == 1) | ||
94 | state = paused; | ||
95 | else if (state == paused) | ||
96 | state = playing; | ||
97 | playstep = 1; | ||
98 | break; | ||
99 | |||
100 | case BUTTON_LEFT: | ||
101 | if (state == paused) | ||
102 | frame = -1; /* single step back */ | ||
103 | else if (state == playing) | ||
104 | playstep = -1; /* rewind */ | ||
105 | break; | ||
106 | |||
107 | case BUTTON_RIGHT: | ||
108 | if (state == paused) | ||
109 | frame = 1; /* single step */ | ||
110 | else if (state == playing) | ||
111 | playstep = 1; /* forward */ | ||
112 | break; | ||
113 | |||
114 | case BUTTON_UP: | ||
115 | if (state == paused) | ||
116 | frame = INT_MAX; /* end of clip */ | ||
117 | break; | ||
118 | |||
119 | case BUTTON_DOWN: | ||
120 | frame = INT_MIN; /* start of clip */ | ||
121 | break; | ||
122 | |||
123 | case BUTTON_OFF: | ||
124 | state = stop; | ||
125 | break; | ||
126 | |||
127 | case SYS_USB_CONNECTED: | ||
128 | state = exit; | ||
129 | break; | ||
130 | |||
131 | default: | ||
132 | if (state != playing) | ||
133 | loop = true; | ||
134 | } | ||
135 | } | ||
136 | while (loop); | ||
137 | |||
138 | return frame; | ||
139 | } | ||
140 | |||
141 | |||
34 | int WaitForButton(void) | 142 | int WaitForButton(void) |
35 | { | 143 | { |
36 | int button; | 144 | int button; |
@@ -50,36 +158,44 @@ int show_buffer(unsigned char* p_start, int frames) | |||
50 | unsigned char* p_current = p_start; | 158 | unsigned char* p_current = p_start; |
51 | unsigned char* p_end = p_start + SCREENSIZE * frames; | 159 | unsigned char* p_end = p_start + SCREENSIZE * frames; |
52 | int shown = 0; | 160 | int shown = 0; |
53 | int button; | 161 | int delta; /* next frame */ |
54 | 162 | ||
55 | do | 163 | do |
56 | { | 164 | { |
57 | rb->lcd_blit(p_current, 0, 0, LCD_WIDTH, LCD_HEIGHT/8, LCD_WIDTH); | 165 | rb->lcd_blit(p_current, 0, 0, LCD_WIDTH, LCD_HEIGHT/8, LCD_WIDTH); |
58 | p_current += SCREENSIZE; | ||
59 | if (p_current >= p_end) | ||
60 | p_current = p_start; /* wrap */ | ||
61 | 166 | ||
62 | rb->yield(); /* yield to the other treads */ | 167 | rb->yield(); /* yield to the other treads */ |
63 | shown++; | 168 | shown++; |
64 | 169 | ||
65 | button = rb->button_get(false); | 170 | delta = check_button(); |
66 | } while(button != BUTTON_OFF && button != SYS_USB_CONNECTED); | 171 | if (delta == INT_MIN) |
172 | p_current = p_start; | ||
173 | else if (delta == INT_MAX) | ||
174 | p_current = p_end - SCREENSIZE; | ||
175 | else | ||
176 | { | ||
177 | p_current += delta * SCREENSIZE; | ||
178 | if (p_current >= p_end || p_current < p_start) | ||
179 | p_current = p_start; /* wrap */ | ||
180 | } | ||
181 | |||
182 | } while(state != stop && state != exit); | ||
67 | 183 | ||
68 | return (button != SYS_USB_CONNECTED) ? shown : SYS_USB_CONNECTED; | 184 | return (state != exit) ? shown : -1; |
69 | } | 185 | } |
70 | 186 | ||
71 | 187 | ||
72 | /* play from file, exit if OFF is pressed */ | 188 | /* play from file, exit if OFF is pressed */ |
73 | int show_file(unsigned char* p_buffer, int fd) | 189 | int show_file(unsigned char* p_buffer, int fd) |
74 | { | 190 | { |
75 | int got_now; /* how many gotten for this frame */ | ||
76 | int shown = 0; | 191 | int shown = 0; |
77 | int button = BUTTON_NONE; | 192 | int delta; /* next frame */ |
78 | /* tricky buffer handling to read only whole sectors, then no copying needed */ | 193 | /* tricky buffer handling to read only whole sectors, then no copying needed */ |
79 | unsigned char* p_file = p_buffer; /* file read */ | 194 | unsigned char* p_file = p_buffer; /* file read */ |
80 | unsigned char* p_screen = p_buffer; /* display */ | 195 | unsigned char* p_screen = p_buffer; /* display */ |
81 | unsigned char* p_end = p_buffer + FILEBUFSIZE; /* for wraparound test */ | 196 | unsigned char* p_end = p_buffer + FILEBUFSIZE; /* for wraparound test */ |
82 | int needed; /* read how much data to complete a frame */ | 197 | int needed; /* read how much data to complete a frame */ |
198 | int got_now; /* how many gotten for this frame */ | ||
83 | int read_now; /* size to read for this frame, 512 or 1024 */ | 199 | int read_now; /* size to read for this frame, 512 or 1024 */ |
84 | 200 | ||
85 | do | 201 | do |
@@ -98,19 +214,54 @@ int show_file(unsigned char* p_buffer, int fd) | |||
98 | if (p_file >= p_end) | 214 | if (p_file >= p_end) |
99 | p_file = p_buffer; /* wrap */ | 215 | p_file = p_buffer; /* wrap */ |
100 | 216 | ||
217 | delta = check_button(); | ||
218 | |||
101 | if (read_now < SCREENSIZE) /* below average? time to do something else */ | 219 | if (read_now < SCREENSIZE) /* below average? time to do something else */ |
102 | { | ||
103 | rb->yield(); /* yield to the other treads */ | 220 | rb->yield(); /* yield to the other treads */ |
104 | button = rb->button_get(false); | 221 | |
222 | if (delta != 1) | ||
223 | { /* need to seek */ | ||
224 | long newpos; | ||
225 | |||
226 | rb->yield(); /* yield in case we didn't do it above */ | ||
227 | |||
228 | if (delta == INT_MIN) | ||
229 | newpos = 0; | ||
230 | else if (delta == INT_MAX) | ||
231 | newpos = rb->filesize(fd) - SCREENSIZE; | ||
232 | else | ||
233 | { | ||
234 | bool pause = false; | ||
235 | newpos = rb->lseek(fd, 0, SEEK_CUR) - (p_file - p_screen) + (delta-1) * SCREENSIZE; | ||
236 | |||
237 | if (newpos < 0) | ||
238 | { | ||
239 | newpos = 0; | ||
240 | pause = true; /* go in paused mode */ | ||
241 | } | ||
242 | |||
243 | if (newpos > rb->filesize(fd) - SCREENSIZE) | ||
244 | { | ||
245 | newpos = rb->filesize(fd) - SCREENSIZE; | ||
246 | pause = true; /* go in paused mode */ | ||
247 | } | ||
248 | |||
249 | if (pause && state == playing) | ||
250 | state = paused; | ||
251 | } | ||
252 | |||
253 | newpos -= newpos % SCREENSIZE; /* should be "even", just to make shure */ | ||
254 | |||
255 | rb->lseek(fd, newpos & ~(SECTOR_SIZE-1), SEEK_SET); /* round down to sector */ | ||
256 | newpos %= FILEBUFSIZE; /* make it an offset within buffer */ | ||
257 | p_screen = p_buffer + newpos; | ||
258 | p_file = p_buffer + (newpos & ~(SECTOR_SIZE-1)); | ||
105 | } | 259 | } |
106 | 260 | ||
107 | shown++; | 261 | shown++; |
262 | } while (got_now >= needed && state != stop && state != exit); | ||
108 | 263 | ||
109 | } while (got_now >= needed | 264 | return (state != exit) ? shown : -1; |
110 | && button != BUTTON_OFF | ||
111 | && button != SYS_USB_CONNECTED); | ||
112 | |||
113 | return (button != SYS_USB_CONNECTED) ? shown : SYS_USB_CONNECTED; | ||
114 | } | 265 | } |
115 | 266 | ||
116 | 267 | ||
@@ -122,19 +273,13 @@ int main(char* filename) | |||
122 | int fd; /* file descriptor handle */ | 273 | int fd; /* file descriptor handle */ |
123 | int got_now; /* how many bytes read from file */ | 274 | int got_now; /* how many bytes read from file */ |
124 | int frames, shown; | 275 | int frames, shown; |
125 | long time; | ||
126 | int button; | 276 | int button; |
277 | int fps; | ||
127 | 278 | ||
128 | p_buffer = rb->plugin_get_buffer(&buffer_size); | 279 | p_buffer = rb->plugin_get_buffer(&buffer_size); |
129 | if (buffer_size < FILEBUFSIZE) | 280 | if (buffer_size < FILEBUFSIZE) |
130 | return PLUGIN_ERROR; /* not enough memory */ | 281 | return PLUGIN_ERROR; /* not enough memory */ |
131 | 282 | ||
132 | /* compose filename if none given */ | ||
133 | if (filename == NULL) | ||
134 | { | ||
135 | filename = DEFAULT_FILENAME; | ||
136 | } | ||
137 | |||
138 | fd = rb->open(filename, O_RDONLY); | 283 | fd = rb->open(filename, O_RDONLY); |
139 | if (fd < 0) | 284 | if (fd < 0) |
140 | return PLUGIN_ERROR; | 285 | return PLUGIN_ERROR; |
@@ -157,17 +302,17 @@ int main(char* filename) | |||
157 | rb->close(fd); | 302 | rb->close(fd); |
158 | } | 303 | } |
159 | 304 | ||
160 | rb->close(fd); | 305 | if (shown == -1) /* exception */ |
161 | |||
162 | if (shown == SYS_USB_CONNECTED) /* exception */ | ||
163 | return PLUGIN_USB_CONNECTED; | 306 | return PLUGIN_USB_CONNECTED; |
164 | 307 | ||
308 | fps = (shown * HZ *100) / time; /* 100 times fps */ | ||
309 | |||
165 | rb->lcd_clear_display(); | 310 | rb->lcd_clear_display(); |
166 | rb->snprintf(buf, sizeof(buf), "%d frames", shown); | 311 | rb->snprintf(buf, sizeof(buf), "%d frames shown", shown); |
167 | rb->lcd_puts(0, 0, buf); | 312 | rb->lcd_puts(0, 0, buf); |
168 | rb->snprintf(buf, sizeof(buf), "%d.%02d seconds", time/HZ, time%HZ); | 313 | rb->snprintf(buf, sizeof(buf), "%d.%02d seconds", time/HZ, time%HZ); |
169 | rb->lcd_puts(0, 1, buf); | 314 | rb->lcd_puts(0, 1, buf); |
170 | rb->snprintf(buf, sizeof(buf), "%d fps", (shown * HZ + time/2) / time); | 315 | rb->snprintf(buf, sizeof(buf), "%d.%02d fps", fps/100, fps%100); |
171 | rb->lcd_puts(0, 2, buf); | 316 | rb->lcd_puts(0, 2, buf); |
172 | rb->snprintf(buf, sizeof(buf), "file: %d bytes", file_size); | 317 | rb->snprintf(buf, sizeof(buf), "file: %d bytes", file_size); |
173 | rb->lcd_puts(0, 6, buf); | 318 | rb->lcd_puts(0, 6, buf); |
@@ -177,6 +322,7 @@ int main(char* filename) | |||
177 | button = WaitForButton(); | 322 | button = WaitForButton(); |
178 | return (button == SYS_USB_CONNECTED) ? PLUGIN_USB_CONNECTED : PLUGIN_OK; | 323 | return (button == SYS_USB_CONNECTED) ? PLUGIN_USB_CONNECTED : PLUGIN_OK; |
179 | 324 | ||
325 | |||
180 | } | 326 | } |
181 | 327 | ||
182 | 328 | ||
@@ -191,6 +337,12 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | |||
191 | 337 | ||
192 | rb = api; /* copy to global api pointer */ | 338 | rb = api; /* copy to global api pointer */ |
193 | 339 | ||
340 | if (parameter == NULL) | ||
341 | { | ||
342 | rb->splash(HZ*2, 0, true, "play .rfv file"); | ||
343 | return PLUGIN_ERROR; | ||
344 | } | ||
345 | |||
194 | /* now go ahead and have fun! */ | 346 | /* now go ahead and have fun! */ |
195 | return main((char*) parameter); | 347 | return main((char*) parameter); |
196 | } | 348 | } |