summaryrefslogtreecommitdiff
path: root/apps/plugins/mpegplayer
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mpegplayer')
-rw-r--r--apps/plugins/mpegplayer/alloc.c6
-rw-r--r--apps/plugins/mpegplayer/header.c7
-rw-r--r--apps/plugins/mpegplayer/idct.c6
-rw-r--r--apps/plugins/mpegplayer/idct_arm_c.c6
-rw-r--r--apps/plugins/mpegplayer/mpeg_settings.c410
-rw-r--r--apps/plugins/mpegplayer/mpeg_settings.h17
-rw-r--r--apps/plugins/mpegplayer/mpegplayer.c770
-rw-r--r--apps/plugins/mpegplayer/video_out.h2
-rw-r--r--apps/plugins/mpegplayer/video_out_rockbox.c108
9 files changed, 1117 insertions, 215 deletions
diff --git a/apps/plugins/mpegplayer/alloc.c b/apps/plugins/mpegplayer/alloc.c
index 0ba86a51f3..ae482de112 100644
--- a/apps/plugins/mpegplayer/alloc.c
+++ b/apps/plugins/mpegplayer/alloc.c
@@ -54,6 +54,8 @@ static void * mpeg_malloc_internal (unsigned char *mallocbuf,
54 x = &mallocbuf[*mem_ptr]; 54 x = &mallocbuf[*mem_ptr];
55 *mem_ptr += (size + 3) & ~3; /* Keep memory 32-bit aligned */ 55 *mem_ptr += (size + 3) & ~3; /* Keep memory 32-bit aligned */
56 56
57 rb->memset(x,0,size);
58
57 return x; 59 return x;
58 (void)reason; 60 (void)reason;
59} 61}
@@ -116,7 +118,7 @@ void * mpeg2_malloc(unsigned size, mpeg2_alloc_t reason)
116 118
117void mpeg2_free(void *ptr) 119void mpeg2_free(void *ptr)
118{ 120{
119 (void)ptr; 121 mpeg2_mem_ptr = (void *)ptr - (void *)mpeg2_mallocbuf;
120} 122}
121 123
122/* The following are expected by libmad */ 124/* The following are expected by libmad */
@@ -141,7 +143,7 @@ void * codec_calloc(size_t nmemb, size_t size)
141 143
142void codec_free(void* ptr) 144void codec_free(void* ptr)
143{ 145{
144 (void)ptr; 146 mem_ptr = (void *)ptr - (void *)mallocbuf;
145} 147}
146 148
147void *memmove(void *dest, const void *src, size_t n) 149void *memmove(void *dest, const void *src, size_t n)
diff --git a/apps/plugins/mpegplayer/header.c b/apps/plugins/mpegplayer/header.c
index 7f94705f52..7486b0ebf0 100644
--- a/apps/plugins/mpegplayer/header.c
+++ b/apps/plugins/mpegplayer/header.c
@@ -58,7 +58,7 @@ static const uint8_t default_intra_quantizer_matrix[64] ICONST_ATTR = {
58 83 58 83
59}; 59};
60 60
61uint8_t mpeg2_scan_norm[64] IDATA_ATTR = { 61uint8_t default_mpeg2_scan_norm[64] IDATA_ATTR = {
62 /* Zig-Zag scan pattern */ 62 /* Zig-Zag scan pattern */
63 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 63 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5,
64 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 64 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28,
@@ -66,7 +66,7 @@ uint8_t mpeg2_scan_norm[64] IDATA_ATTR = {
66 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 66 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
67}; 67};
68 68
69uint8_t mpeg2_scan_alt[64] IDATA_ATTR = { 69uint8_t default_mpeg2_scan_alt[64] IDATA_ATTR = {
70 /* Alternate scan pattern */ 70 /* Alternate scan pattern */
71 0, 8, 16, 24, 1, 9, 2, 10, 17, 25, 32, 40, 48, 56, 57, 49, 71 0, 8, 16, 24, 1, 9, 2, 10, 17, 25, 32, 40, 48, 56, 57, 49,
72 41, 33, 26, 18, 3, 11, 4, 12, 19, 27, 34, 42, 50, 58, 35, 43, 72 41, 33, 26, 18, 3, 11, 4, 12, 19, 27, 34, 42, 50, 58, 35, 43,
@@ -74,6 +74,9 @@ uint8_t mpeg2_scan_alt[64] IDATA_ATTR = {
74 53, 61, 22, 30, 7, 15, 23, 31, 38, 46, 54, 62, 39, 47, 55, 63 74 53, 61, 22, 30, 7, 15, 23, 31, 38, 46, 54, 62, 39, 47, 55, 63
75}; 75};
76 76
77uint8_t mpeg2_scan_norm[64] IDATA_ATTR;
78uint8_t mpeg2_scan_alt[64] IDATA_ATTR;
79
77void mpeg2_header_state_init (mpeg2dec_t * mpeg2dec) 80void mpeg2_header_state_init (mpeg2dec_t * mpeg2dec)
78{ 81{
79 if (mpeg2dec->sequence.width != (unsigned)-1) { 82 if (mpeg2dec->sequence.width != (unsigned)-1) {
diff --git a/apps/plugins/mpegplayer/idct.c b/apps/plugins/mpegplayer/idct.c
index ee02e72a6f..bf705c6a2f 100644
--- a/apps/plugins/mpegplayer/idct.c
+++ b/apps/plugins/mpegplayer/idct.c
@@ -260,6 +260,8 @@ static void mpeg2_idct_add_c (const int last, int16_t * block,
260 260
261void mpeg2_idct_init (void) 261void mpeg2_idct_init (void)
262{ 262{
263 extern uint8_t default_mpeg2_scan_norm[64];
264 extern uint8_t default_mpeg2_scan_alt[64];
263 extern uint8_t mpeg2_scan_norm[64]; 265 extern uint8_t mpeg2_scan_norm[64];
264 extern uint8_t mpeg2_scan_alt[64]; 266 extern uint8_t mpeg2_scan_alt[64];
265 int i, j; 267 int i, j;
@@ -274,10 +276,10 @@ void mpeg2_idct_init (void)
274 276
275 for (i = 0; i < 64; i++) 277 for (i = 0; i < 64; i++)
276 { 278 {
277 j = mpeg2_scan_norm[i]; 279 j = default_mpeg2_scan_norm[i];
278 mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); 280 mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2);
279 281
280 j = mpeg2_scan_alt[i]; 282 j = default_mpeg2_scan_alt[i];
281 mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); 283 mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2);
282 } 284 }
283} 285}
diff --git a/apps/plugins/mpegplayer/idct_arm_c.c b/apps/plugins/mpegplayer/idct_arm_c.c
index be9971f5c3..9805f421a6 100644
--- a/apps/plugins/mpegplayer/idct_arm_c.c
+++ b/apps/plugins/mpegplayer/idct_arm_c.c
@@ -509,6 +509,8 @@ static void mpeg2_idct_add_c (int last, int16_t * block,
509 509
510void mpeg2_idct_init (void) 510void mpeg2_idct_init (void)
511{ 511{
512 extern uint8_t default_mpeg2_scan_norm[64];
513 extern uint8_t default_mpeg2_scan_alt[64];
512 extern uint8_t mpeg2_scan_norm[64]; 514 extern uint8_t mpeg2_scan_norm[64];
513 extern uint8_t mpeg2_scan_alt[64]; 515 extern uint8_t mpeg2_scan_alt[64];
514 int i, j; 516 int i, j;
@@ -518,10 +520,10 @@ void mpeg2_idct_init (void)
518 520
519 for (i = 0; i < 64; i++) 521 for (i = 0; i < 64; i++)
520 { 522 {
521 j = mpeg2_scan_norm[i]; 523 j = default_mpeg2_scan_norm[i];
522 mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); 524 mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2);
523 525
524 j = mpeg2_scan_alt[i]; 526 j = default_mpeg2_scan_alt[i];
525 mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); 527 mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2);
526 } 528 }
527} 529}
diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c
index 28062f4567..197fa09236 100644
--- a/apps/plugins/mpegplayer/mpeg_settings.c
+++ b/apps/plugins/mpegplayer/mpeg_settings.c
@@ -7,20 +7,99 @@
7extern struct plugin_api* rb; 7extern struct plugin_api* rb;
8 8
9struct mpeg_settings settings; 9struct mpeg_settings settings;
10static struct mpeg_settings old_settings; 10
11ssize_t seek_PTS(int in_file, int startTime, int accept_button);
12void display_thumb(int in_file);
13
14#ifndef HAVE_LCD_COLOR
15void gray_show(bool enable);
16#endif
11 17
12#define SETTINGS_VERSION 2 18#define SETTINGS_VERSION 2
13#define SETTINGS_MIN_VERSION 1 19#define SETTINGS_MIN_VERSION 1
14#define SETTINGS_FILENAME "mpegplayer.cfg" 20#define SETTINGS_FILENAME "mpegplayer.cfg"
15 21
22enum slider_state_t {state0, state1, state2,
23 state3, state4, state5} slider_state;
24
25volatile long thumbDelayTimer;
26
27/* button definitions */
28#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
29 (CONFIG_KEYPAD == IRIVER_H300_PAD)
30#define MPEG_SELECT BUTTON_ON
31#define MPEG_RIGHT BUTTON_RIGHT
32#define MPEG_LEFT BUTTON_LEFT
33#define MPEG_SCROLL_DOWN BUTTON_UP
34#define MPEG_SCROLL_UP BUTTON_DOWN
35#define MPEG_EXIT BUTTON_OFF
36
37#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
38#define MPEG_SELECT BUTTON_PLAY
39#define MPEG_RIGHT BUTTON_RIGHT
40#define MPEG_LEFT BUTTON_LEFT
41#define MPEG_SCROLL_DOWN BUTTON_UP
42#define MPEG_SCROLL_UP BUTTON_DOWN
43#define MPEG_EXIT BUTTON_POWER
44
45#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
46 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
47 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
48#define MPEG_SELECT BUTTON_SELECT
49#define MPEG_RIGHT BUTTON_RIGHT
50#define MPEG_LEFT BUTTON_LEFT
51#define MPEG_SCROLL_DOWN BUTTON_SCROLL_FWD
52#define MPEG_SCROLL_UP BUTTON_SCROLL_BACK
53#define MPEG_EXIT BUTTON_MENU
54
55#elif CONFIG_KEYPAD == GIGABEAT_PAD
56#define MPEG_SELECT BUTTON_SELECT
57#define MPEG_LEFT BUTTON_LEFT
58#define MPEG_RIGHT BUTTON_RIGHT
59#define MPEG_UP BUTTON_UP
60#define MPEG_DOWN BUTTON_DOWN
61#define MPEG_SCROLL_DOWN BUTTON_VOL_DOWN
62#define MPEG_SCROLL_UP BUTTON_VOL_UP
63#define MPEG_EXIT BUTTON_POWER
64
65#elif CONFIG_KEYPAD == IRIVER_H10_PAD
66#define MPEG_SELECT BUTTON_PLAY
67#define MPEG_SCROLL_UP BUTTON_SCROLL_UP
68#define MPEG_SCROLL_DOWN BUTTON_SCROLL_DOWN
69#define MPEG_LEFT BUTTON_LEFT
70#define MPEG_RIGHT BUTTON_RIGHT
71#define MPEG_EXIT BUTTON_POWER
72
73#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
74#define MPEG_SELECT BUTTON_SELECT
75#define MPEG_SCROLL_UP BUTTON_SCROLL_UP
76#define MPEG_SCROLL_DOWN BUTTON_SCROLL_DOWN
77#define MPEG_LEFT BUTTON_LEFT
78#define MPEG_RIGHT BUTTON_RIGHT
79#define MPEG_UP BUTTON_UP
80#define MPEG_DOWN BUTTON_DOWN
81#define MPEG_EXIT BUTTON_POWER
82
83#elif (CONFIG_KEYPAD == SANSA_C200_PAD)
84#define MPEG_SELECT BUTTON_SELECT
85#define MPEG_SCROLL_UP BUTTON_VOL_UP
86#define MPEG_SCROLL_DOWN BUTTON_VOL_DOWN
87#define MPEG_LEFT BUTTON_LEFT
88#define MPEG_RIGHT BUTTON_RIGHT
89#define MPEG_UP BUTTON_UP
90#define MPEG_DOWN BUTTON_DOWN
91#define MPEG_EXIT BUTTON_POWER
92
93#else
94#error MPEGPLAYER: Unsupported keypad
95#endif
96
16static struct configdata config[] = 97static struct configdata config[] =
17{ 98{
18 {TYPE_ENUM, 0, 2, &settings.showfps, "Show FPS", 99 {TYPE_INT, 0, 2, &settings.showfps, "Show FPS", NULL, NULL},
19 (char *[]){ "No", "Yes" }, NULL}, 100 {TYPE_INT, 0, 2, &settings.limitfps, "Limit FPS", NULL, NULL},
20 {TYPE_ENUM, 0, 2, &settings.limitfps, "Limit FPS", 101 {TYPE_INT, 0, 2, &settings.skipframes, "Skip frames", NULL, NULL},
21 (char *[]){ "No", "Yes" }, NULL}, 102
22 {TYPE_ENUM, 0, 2, &settings.skipframes, "Skip frames",
23 (char *[]){ "No", "Yes" }, NULL},
24#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 103#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200)
25 {TYPE_INT, 0, INT_MAX, &settings.displayoptions, "Display options", 104 {TYPE_INT, 0, INT_MAX, &settings.displayoptions, "Display options",
26 NULL, NULL}, 105 NULL, NULL},
@@ -36,6 +115,7 @@ enum mpeg_menu_ids
36 MPEG_OPTION_DISPLAY_FPS, 115 MPEG_OPTION_DISPLAY_FPS,
37 MPEG_OPTION_LIMIT_FPS, 116 MPEG_OPTION_LIMIT_FPS,
38 MPEG_OPTION_SKIP_FRAMES, 117 MPEG_OPTION_SKIP_FRAMES,
118 MPEG_OPTION_CLEAR_RESUMES,
39 MPEG_OPTION_QUIT, 119 MPEG_OPTION_QUIT,
40}; 120};
41 121
@@ -68,13 +148,250 @@ static void display_options(void)
68} 148}
69#endif /* #ifdef TOSHIBA_GIGABEAT_F */ 149#endif /* #ifdef TOSHIBA_GIGABEAT_F */
70 150
151void draw_slider(int slider_ypos, int max_val, int current_val)
152{
153 int slider_margin = LCD_WIDTH*12/100; /* 12% */
154 int slider_width = LCD_WIDTH-(slider_margin*2);
155 char resume_str[32];
156
157 /* max_val and current_val are in half minutes
158 determine value .0 or .5 to display */
159 int max_hol = max_val/2;
160 int max_rem = (max_val-(max_hol*2))*5;
161 int current_hol = current_val/2;
162 int current_rem = (current_val-(current_hol*2))*5;
163
164 rb->snprintf(resume_str, sizeof(resume_str), "0.0");
165 rb->lcd_putsxy(slider_margin, slider_ypos, resume_str);
166
167 rb->snprintf(resume_str, sizeof(resume_str), "%u.%u", max_hol, max_rem);
168 rb->lcd_putsxy(LCD_WIDTH-slider_margin-25, slider_ypos, resume_str);
169
170 rb->lcd_drawrect(slider_margin, slider_ypos+17, slider_width, 8);
171 rb->lcd_fillrect(slider_margin, slider_ypos+17,
172 current_val*slider_width/max_val, 8);
173
174 rb->snprintf(resume_str, sizeof(resume_str), "%u.%u", current_hol,
175 current_rem);
176 rb->lcd_putsxy(slider_margin+(current_val*slider_width/max_val)-16,
177 slider_ypos+29, resume_str);
178
179 rb->lcd_update_rect(0, slider_ypos, LCD_WIDTH, LCD_HEIGHT-slider_ypos);
180}
181
182int get_start_time(int play_time, int in_file)
183{
184 int quit = 0;
185 int button = 0;
186 int resume_time = settings.resume_time;
187 int slider_ypos = LCD_HEIGHT-45;
188 int seek_rtn;
189
190 slider_state = state0;
191 thumbDelayTimer = *(rb->current_tick);
192 rb->lcd_clear_display();
193 rb->lcd_update();
194
195 while(quit == 0)
196 {
197 button = rb->button_get(false);
198 switch (button)
199 {
200#if (CONFIG_KEYPAD == GIGABEAT_PAD) || \
201 (CONFIG_KEYPAD == SANSA_E200_PAD) || \
202 (CONFIG_KEYPAD == SANSA_C200_PAD)
203 case MPEG_DOWN:
204 case MPEG_DOWN | BUTTON_REPEAT:
205 if ((resume_time -= 20) < 0)
206 resume_time = 0;
207 slider_state = state0;
208 thumbDelayTimer = *(rb->current_tick);
209 break;
210 case MPEG_UP:
211 case MPEG_UP | BUTTON_REPEAT:
212 if ((resume_time += 20) > play_time)
213 resume_time = play_time;
214 slider_state = state0;
215 thumbDelayTimer = *(rb->current_tick);
216 break;
217#endif
218 case MPEG_LEFT:
219 case MPEG_LEFT | BUTTON_REPEAT:
220 case MPEG_SCROLL_UP:
221 case MPEG_SCROLL_UP | BUTTON_REPEAT:
222 if (--resume_time < 0)
223 resume_time = 0;
224 slider_state = state0;
225 thumbDelayTimer = *(rb->current_tick);
226 break;
227 case MPEG_RIGHT:
228 case MPEG_RIGHT | BUTTON_REPEAT:
229 case MPEG_SCROLL_DOWN:
230 case MPEG_SCROLL_DOWN | BUTTON_REPEAT:
231 if (++resume_time > play_time)
232 resume_time = play_time;
233 slider_state = state0;
234 thumbDelayTimer = *(rb->current_tick);
235 break;
236 case MPEG_SELECT:
237 quit = 1;
238 break;
239 case MPEG_EXIT:
240 resume_time = -1;
241 quit = 1;
242 break;
243 default:
244 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
245 {
246 resume_time = -1;
247 quit = 1;
248 }
249 break;
250 }
251
252 rb->yield();
253
254 switch(slider_state)
255 {
256 case state0:
257 rb->lcd_clear_display();
258 rb->lcd_update();
259#ifdef HAVE_LCD_COLOR
260 if (resume_time > 0)
261 rb->splash(0, "loading ...");
262#endif
263 slider_state = state1;
264 break;
265 case state1:
266 if (*(rb->current_tick) - thumbDelayTimer > 75)
267 slider_state = state2;
268 if (resume_time == 0)
269 {
270 seek_rtn = 0;
271 slider_state = state5;
272 }
273 draw_slider(slider_ypos, play_time, resume_time);
274 break;
275 case state2:
276 if ( (seek_rtn = seek_PTS(in_file, resume_time, 1)) >= 0)
277 slider_state = state3;
278 else if (seek_rtn == -101)
279 {
280 slider_state = state0;
281 thumbDelayTimer = *(rb->current_tick);
282 }
283 else
284 slider_state = state4;
285 break;
286 case state3:
287 display_thumb(in_file);
288 draw_slider(slider_ypos, play_time, resume_time);
289 slider_state = state4;
290 break;
291 case state4:
292 draw_slider(slider_ypos, play_time, resume_time);
293 slider_state = state5;
294 break;
295 case state5:
296 break;
297 }
298 }
299
300 return resume_time;
301}
302
303int mpeg_start_menu(int play_time, int in_file)
304{
305 int m;
306 int result = 0;
307 int menu_quit = 0;
308
309 /* add the resume time to the menu display */
310 char resume_str[32];
311 int time_hol = (int)(settings.resume_time/2);
312 int time_rem = ((settings.resume_time%2)==0) ? 0 : 5;
313 rb->snprintf(resume_str, sizeof(resume_str),
314 "Resume time (min): %d.%d", time_hol, time_rem);
315
316 struct menu_item items[] = {
317 { "Play from beginning", NULL },
318 { resume_str, NULL },
319 { "Set start time (min)", NULL },
320 { "Quit mpegplayer", NULL },
321 };
322
323 m = menu_init(rb, items, sizeof(items) / sizeof(*items),
324 NULL, NULL, NULL, NULL);
325
326 rb->button_clear_queue();
327
328 while(menu_quit == 0)
329 {
330 result = menu_show(m);
331
332 switch (result)
333 {
334 case 0:
335 menu_quit = 1;
336 result = 0;
337 break;
338 case 1:
339 menu_quit = 1;
340 result = settings.resume_time;
341 break;
342 case 2:
343#ifndef HAVE_LCD_COLOR
344 gray_show(true);
345#endif
346 if ((result = get_start_time(play_time, in_file)) >= 0)
347 menu_quit = 1;
348#ifndef HAVE_LCD_COLOR
349 gray_show(false);
350#endif
351 break;
352 case 3:
353 menu_quit = 1;
354 result = -1;
355 break;
356 default:
357 if (result == MENU_ATTACHED_USB)
358 {
359 menu_quit = 1;
360 result = -1;
361 }
362 break;
363 }
364 }
365 menu_exit(m);
366
367 settings.resume_time = result;
368 return (int)result;
369}
370
371void clear_resume_count(void)
372{
373 configfile_save(SETTINGS_FILENAME, config,
374 sizeof(config)/sizeof(*config),
375 SETTINGS_VERSION);
376
377 settings.resume_count = 0;
378
379 /* add this place holder so the count is above resume entries */
380 configfile_update_entry(SETTINGS_FILENAME, "Resume count", 0);
381}
382
71bool mpeg_menu(void) 383bool mpeg_menu(void)
72{ 384{
73 int m; 385 int m;
74 int result; 386 int result;
75 int menu_quit=0; 387 int menu_quit=0;
76 388
77 static const struct menu_item items[] = { 389 /* add the clear resume option to the menu display */
390 char clear_str[32];
391 rb->snprintf(clear_str, sizeof(clear_str),
392 "Clear all resumes: %u", settings.resume_count);
393
394 struct menu_item items[] = {
78#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 395#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200)
79 [MPEG_OPTION_DISPLAY_SETTINGS] = 396 [MPEG_OPTION_DISPLAY_SETTINGS] =
80 { "Display Options", NULL }, 397 { "Display Options", NULL },
@@ -85,6 +402,8 @@ bool mpeg_menu(void)
85 { "Limit FPS", NULL }, 402 { "Limit FPS", NULL },
86 [MPEG_OPTION_SKIP_FRAMES] = 403 [MPEG_OPTION_SKIP_FRAMES] =
87 { "Skip frames", NULL }, 404 { "Skip frames", NULL },
405 [MPEG_OPTION_CLEAR_RESUMES] =
406 { clear_str, NULL },
88 [MPEG_OPTION_QUIT] = 407 [MPEG_OPTION_QUIT] =
89 { "Quit mpegplayer", NULL }, 408 { "Quit mpegplayer", NULL },
90 }; 409 };
@@ -115,6 +434,11 @@ bool mpeg_menu(void)
115 rb->set_option("Skip frames",&settings.skipframes,INT, 434 rb->set_option("Skip frames",&settings.skipframes,INT,
116 noyes, 2, NULL); 435 noyes, 2, NULL);
117 break; 436 break;
437 case MPEG_OPTION_CLEAR_RESUMES:
438 clear_resume_count();
439 rb->snprintf(clear_str, sizeof(clear_str),
440 "Clear all resumes: %u", 0);
441 break;
118 case MPEG_OPTION_QUIT: 442 case MPEG_OPTION_QUIT:
119 default: 443 default:
120 menu_quit=1; 444 menu_quit=1;
@@ -132,48 +456,82 @@ bool mpeg_menu(void)
132 return (result==MPEG_OPTION_QUIT); 456 return (result==MPEG_OPTION_QUIT);
133} 457}
134 458
135 459void init_settings(const char* filename)
136void init_settings(void)
137{ 460{
138 /* Set the default settings */ 461 /* Set the default settings */
139 settings.showfps = 0; /* Do not show FPS */ 462 settings.showfps = 0; /* Do not show FPS */
140 settings.limitfps = 1; /* Limit FPS */ 463 settings.limitfps = 1; /* Limit FPS */
141 settings.skipframes = 1; /* Skip frames */ 464 settings.skipframes = 1; /* Skip frames */
465 settings.resume_count = -1;
142#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 466#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200)
143 settings.displayoptions = 0; /* No visual effects */ 467 settings.displayoptions = 0; /* No visual effects */
144#endif 468#endif
145 469
146 configfile_init(rb); 470 configfile_init(rb);
147 471
148 if (configfile_load(SETTINGS_FILENAME, config, 472 /* If the config file don't contain resume count
149 sizeof(config)/sizeof(*config), 473 or the load fails, then rebuild the config file.
150 SETTINGS_MIN_VERSION 474 This eliminates the worry for older config files
151 ) < 0) 475 having unused data. */
476 if (((settings.resume_count = configfile_get_value
477 (SETTINGS_FILENAME, "Resume count")) < 0) ||
478 (configfile_load(SETTINGS_FILENAME, config,
479 sizeof(config)/sizeof(*config),
480 SETTINGS_MIN_VERSION) < 0))
152 { 481 {
153 /* If the loading failed, save a new config file (as the disk is 482 /* Generate a new config file with default values */
154 already spinning) */
155 configfile_save(SETTINGS_FILENAME, config, 483 configfile_save(SETTINGS_FILENAME, config,
156 sizeof(config)/sizeof(*config), 484 sizeof(config)/sizeof(*config),
157 SETTINGS_VERSION); 485 SETTINGS_VERSION);
158 } 486 }
159 487
160 /* Keep a copy of the saved version of the settings - so we can check if
161 the settings have changed when we quit */
162 old_settings = settings;
163#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 488#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200)
489 if ((settings.displayoptions =
490 configfile_get_value(SETTINGS_FILENAME, "Display options")) < 0)
491 {
492 configfile_update_entry(SETTINGS_FILENAME, "Display options",
493 (settings.displayoptions=0));
494 }
164 rb->lcd_yuv_set_options(settings.displayoptions); 495 rb->lcd_yuv_set_options(settings.displayoptions);
165#endif 496#endif
497
498 if (settings.resume_count < 0)
499 {
500 settings.resume_count = 0;
501
502 /* add this place holder so the count is above resume entries */
503 configfile_update_entry(SETTINGS_FILENAME, "Resume count", 0);
504 }
505
506 rb->strcpy(settings.resume_filename, filename);
507
508 /* get the resume time for the current mpeg if it exist */
509 if ((settings.resume_time = configfile_get_value
510 (SETTINGS_FILENAME, filename)) < 0)
511 {
512 settings.resume_time = 0;
513 }
166} 514}
167 515
168void save_settings(void) 516void save_settings(void)
169{ 517{
170 /* Save the user settings if they have changed */ 518 configfile_update_entry(SETTINGS_FILENAME, "Show FPS",
171 if (rb->memcmp(&settings,&old_settings,sizeof(settings))!=0) { 519 settings.showfps);
172 configfile_save(SETTINGS_FILENAME, config, 520 configfile_update_entry(SETTINGS_FILENAME, "Limit FPS",
173 sizeof(config)/sizeof(*config), 521 settings.limitfps);
174 SETTINGS_VERSION); 522 configfile_update_entry(SETTINGS_FILENAME, "Skip frames",
523 settings.skipframes);
175 524
176 /* Store the settings in old_settings - to check for future changes */ 525 /* If this was a new resume entry then update the total resume count */
177 old_settings = settings; 526 if (configfile_update_entry(SETTINGS_FILENAME, settings.resume_filename,
527 settings.resume_time) == 0)
528 {
529 configfile_update_entry(SETTINGS_FILENAME, "Resume count",
530 ++settings.resume_count);
178 } 531 }
532
533#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200)
534 configfile_update_entry(SETTINGS_FILENAME, "Display options",
535 settings.displayoptions);
536#endif
179} 537}
diff --git a/apps/plugins/mpegplayer/mpeg_settings.h b/apps/plugins/mpegplayer/mpeg_settings.h
index 7721c46f64..690667f632 100644
--- a/apps/plugins/mpegplayer/mpeg_settings.h
+++ b/apps/plugins/mpegplayer/mpeg_settings.h
@@ -2,16 +2,23 @@
2#include "plugin.h" 2#include "plugin.h"
3 3
4struct mpeg_settings { 4struct mpeg_settings {
5 int showfps; 5 int showfps; /* flag to display fps */
6 int limitfps; 6 int limitfps; /* flag to limit fps */
7 int skipframes; 7 int skipframes; /* flag to skip frames */
8 int resume_count; /* total # of resumes in config file */
9 int resume_time; /* resume time for current mpeg (in half minutes) */
10 char resume_filename[128]; /* filename of current mpeg */
11
8#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 12#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200)
9 unsigned displayoptions; 13 int displayoptions;
10#endif 14#endif
11}; 15};
12 16
13extern struct mpeg_settings settings; 17extern struct mpeg_settings settings;
14 18
19int get_start_time(int play_time, int in_file);
20int mpeg_start_menu(int play_time, int in_file);
15bool mpeg_menu(void); 21bool mpeg_menu(void);
16void init_settings(void); 22void init_settings(const char* filename);
17void save_settings(void); 23void save_settings(void);
24void clear_resume_count(void);
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
diff --git a/apps/plugins/mpegplayer/video_out.h b/apps/plugins/mpegplayer/video_out.h
index 0d91eb7b1c..ec3f7c65d3 100644
--- a/apps/plugins/mpegplayer/video_out.h
+++ b/apps/plugins/mpegplayer/video_out.h
@@ -22,4 +22,6 @@
22 */ 22 */
23 23
24void vo_draw_frame (uint8_t * const * buf); 24void vo_draw_frame (uint8_t * const * buf);
25void vo_draw_frame_thumb (uint8_t * const * buf);
25void vo_setup (const mpeg2_sequence_t * sequence); 26void vo_setup (const mpeg2_sequence_t * sequence);
27void vo_cleanup (void);
diff --git a/apps/plugins/mpegplayer/video_out_rockbox.c b/apps/plugins/mpegplayer/video_out_rockbox.c
index 2aac0b8039..490f04411f 100644
--- a/apps/plugins/mpegplayer/video_out_rockbox.c
+++ b/apps/plugins/mpegplayer/video_out_rockbox.c
@@ -43,8 +43,7 @@ static int output_height;
43void vo_draw_frame (uint8_t * const * buf) 43void vo_draw_frame (uint8_t * const * buf)
44{ 44{
45#ifdef HAVE_LCD_COLOR 45#ifdef HAVE_LCD_COLOR
46 rb->lcd_yuv_blit(buf, 46 rb->lcd_yuv_blit(buf, 0,0,image_width,
47 0,0,image_width,
48 output_x,output_y,output_width,output_height); 47 output_x,output_y,output_width,output_height);
49#else 48#else
50 gray_ub_gray_bitmap_part(buf[0],0,0,image_width, 49 gray_ub_gray_bitmap_part(buf[0],0,0,image_width,
@@ -60,10 +59,105 @@ void vo_draw_frame (uint8_t * const * buf)
60#define SCREEN_HEIGHT LCD_WIDTH 59#define SCREEN_HEIGHT LCD_WIDTH
61#endif 60#endif
62 61
62uint8_t* tmpbufa = 0;
63uint8_t* tmpbufb = 0;
64uint8_t* tmpbufc = 0;
65uint8_t* tmpbuf[3];
66
67void vo_draw_frame_thumb (uint8_t * const * buf)
68{
69 int r,c;
70
71#if LCD_WIDTH >= LCD_HEIGHT
72 for (r=0;r<image_width/2;r++)
73 for (c=0;c<image_height/2;c++)
74 *(tmpbuf[0]+c*image_width/2+r) =
75 *(buf[0]+2*c*image_width+2*r);
76
77 for (r=0;r<image_width/4;r++)
78 for (c=0;c<image_height/4;c++)
79 {
80 *(tmpbuf[1]+c*image_width/4+r) =
81 *(buf[1]+2*c*image_width/2+2*r);
82 *(tmpbuf[2]+c*image_width/4+r) =
83 *(buf[2]+2*c*image_width/2+2*r);
84 }
85#else
86 for (r=0;r<image_width/2;r++)
87 for (c=0;c<image_height/2;c++)
88 *(tmpbuf[0]+(image_width/2-1-r)*image_height/2+c) =
89 *(buf[0]+2*c*image_width+2*r);
90
91 for (r=0;r<image_width/4;r++)
92 for (c=0;c<image_height/4;c++)
93 {
94 *(tmpbuf[1]+(image_width/4-1-r)*image_height/4+c) =
95 *(buf[1]+2*c*image_width/2+2*r);
96 *(tmpbuf[2]+(image_width/4-1-r)*image_height/4+c) =
97 *(buf[2]+2*c*image_width/2+2*r);
98 }
99#endif
100
101rb->lcd_clear_display();
102rb->lcd_update();
103
104#ifdef HAVE_LCD_COLOR
105#ifdef SIMULATOR
106#if LCD_WIDTH >= LCD_HEIGHT
107 rb->lcd_yuv_blit(tmpbuf,0,0,image_width/2,
108 (LCD_WIDTH-1-image_width/2)/2,
109 LCD_HEIGHT-50-(image_height/2),
110 output_width/2,output_height/2);
111
112#else
113 rb->lcd_yuv_blit(tmpbuf,0,0,image_height/2,
114 LCD_HEIGHT-50-(image_height/2),
115 (LCD_WIDTH-1-image_width/2)/2,
116 output_height/2,output_width/2);
117#endif
118#else
119#if LCD_WIDTH >= LCD_HEIGHT
120 rb->lcd_yuv_blit(tmpbuf,0,0,image_width/2,
121 (LCD_WIDTH-1-image_width/2)/2,
122 LCD_HEIGHT-50-(image_height/2),
123 output_width/2,output_height/2);
124#else
125 rb->lcd_yuv_blit(tmpbuf,0,0,image_height/2,
126 LCD_HEIGHT-50-(image_height/2),
127 (LCD_WIDTH-1-image_width/2)/2,
128 output_height/2,output_width/2);
129#endif
130#endif
131#else
132#if LCD_WIDTH >= LCD_HEIGHT
133 gray_ub_gray_bitmap_part(tmpbuf[0],0,0,image_width/2,
134 (LCD_WIDTH-1-image_width/2)/2,
135 LCD_HEIGHT-50-(image_height/2),
136 output_width/2,output_height/2);
137#else
138 gray_ub_gray_bitmap_part(tmpbuf[0],0,0,image_height/2,
139 LCD_HEIGHT-50-(image_height/2),
140 (LCD_WIDTH-1-image_width/2)/2,
141 output_height/2,output_width/2);
142#endif
143#endif
144}
145
63void vo_setup(const mpeg2_sequence_t * sequence) 146void vo_setup(const mpeg2_sequence_t * sequence)
64{ 147{
65 image_width=sequence->width; 148 image_width=sequence->width;
66 image_height=sequence->height; 149 image_height=sequence->height;
150
151 tmpbufa = (uint8_t*)mpeg2_malloc(sizeof(uint8_t)*image_width/2*
152 image_height/2, -2);
153 tmpbufb = (uint8_t*)mpeg2_malloc(sizeof(uint8_t)*image_width/4*
154 image_height/4, -2);
155 tmpbufc = (uint8_t*)mpeg2_malloc(sizeof(uint8_t)*image_width/4*
156 image_height/4, -2);
157 tmpbuf[0] = tmpbufa;
158 tmpbuf[1] = tmpbufb;
159 tmpbuf[2] = tmpbufc;
160
67 image_chroma_x=image_width/sequence->chroma_width; 161 image_chroma_x=image_width/sequence->chroma_width;
68 image_chroma_y=image_height/sequence->chroma_height; 162 image_chroma_y=image_height/sequence->chroma_height;
69 163
@@ -83,3 +177,13 @@ void vo_setup(const mpeg2_sequence_t * sequence)
83 output_y = (SCREEN_HEIGHT-sequence->display_height)/2; 177 output_y = (SCREEN_HEIGHT-sequence->display_height)/2;
84 } 178 }
85} 179}
180
181void vo_cleanup(void)
182{
183 if (tmpbufc)
184 mpeg2_free(tmpbufc);
185 if (tmpbufb)
186 mpeg2_free(tmpbufb);
187 if (tmpbufa)
188 mpeg2_free(tmpbufa);
189}