diff options
Diffstat (limited to 'apps/plugins/mpegplayer/mpegplayer.c')
-rw-r--r-- | apps/plugins/mpegplayer/mpegplayer.c | 153 |
1 files changed, 146 insertions, 7 deletions
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c index be028c01f8..67569a7e1c 100644 --- a/apps/plugins/mpegplayer/mpegplayer.c +++ b/apps/plugins/mpegplayer/mpegplayer.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "plugin.h" | 27 | #include "plugin.h" |
28 | 28 | ||
29 | #include "mpeg2.h" | 29 | #include "mpeg2.h" |
30 | #include "mpeg_settings.h" | ||
30 | #include "video_out.h" | 31 | #include "video_out.h" |
31 | 32 | ||
32 | PLUGIN_HEADER | 33 | PLUGIN_HEADER |
@@ -41,44 +42,88 @@ extern char iend[]; | |||
41 | 42 | ||
42 | struct plugin_api* rb; | 43 | struct plugin_api* rb; |
43 | 44 | ||
44 | /* The main buffer storing the compressed video data */ | ||
45 | #define BUFFER_SIZE (MEM-6)*1024*1024 | ||
46 | |||
47 | static mpeg2dec_t * mpeg2dec; | 45 | static mpeg2dec_t * mpeg2dec; |
48 | static int total_offset = 0; | 46 | static int total_offset = 0; |
49 | 47 | ||
50 | /* button definitions */ | 48 | /* button definitions */ |
51 | #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) | 49 | #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) |
50 | #define MPEG_MENU BUTTON_MODE | ||
52 | #define MPEG_STOP BUTTON_OFF | 51 | #define MPEG_STOP BUTTON_OFF |
53 | #define MPEG_PAUSE BUTTON_ON | 52 | #define MPEG_PAUSE BUTTON_ON |
54 | 53 | ||
55 | #elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD) | 54 | #elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD) |
56 | #define MPEG_STOP BUTTON_MENU | 55 | #define MPEG_MENU BUTTON_MENU |
57 | #define MPEG_PAUSE BUTTON_PLAY | 56 | #define MPEG_PAUSE (BUTTON_PLAY | BUTTON_REL) |
57 | #define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT) | ||
58 | 58 | ||
59 | #elif CONFIG_KEYPAD == IAUDIO_X5_PAD | 59 | #elif CONFIG_KEYPAD == IAUDIO_X5_PAD |
60 | #define MPEG_MENU (BUTTON_REC | BUTTON_REL) | ||
60 | #define MPEG_STOP BUTTON_POWER | 61 | #define MPEG_STOP BUTTON_POWER |
61 | #define MPEG_PAUSE BUTTON_PLAY | 62 | #define MPEG_PAUSE BUTTON_PLAY |
62 | 63 | ||
63 | #elif CONFIG_KEYPAD == GIGABEAT_PAD | 64 | #elif CONFIG_KEYPAD == GIGABEAT_PAD |
65 | #define MPEG_MENU BUTTON_MENU | ||
64 | #define MPEG_STOP BUTTON_A | 66 | #define MPEG_STOP BUTTON_A |
65 | #define MPEG_PAUSE BUTTON_SELECT | 67 | #define MPEG_PAUSE BUTTON_SELECT |
66 | 68 | ||
67 | #elif CONFIG_KEYPAD == IRIVER_H10_PAD | 69 | #elif CONFIG_KEYPAD == IRIVER_H10_PAD |
70 | #define MPEG_MENU (BUTTON_REW | BUTTON_REL) | ||
68 | #define MPEG_STOP BUTTON_POWER | 71 | #define MPEG_STOP BUTTON_POWER |
69 | #define MPEG_PAUSE BUTTON_PLAY | 72 | #define MPEG_PAUSE BUTTON_PLAY |
70 | 73 | ||
71 | #else | 74 | #else |
72 | #error MPEGPLAYER: Unsupported keypad | 75 | #error MPEGPLAYER: Unsupported keypad |
73 | #endif | 76 | #endif |
77 | |||
78 | static int tick_enabled = 0; | ||
79 | |||
80 | #define MPEG_CURRENT_TICK ((unsigned int)((*rb->current_tick - tick_offset))) | ||
81 | |||
82 | /* The value to subtract from current_tick to get the current mpeg tick */ | ||
83 | static int tick_offset; | ||
84 | |||
85 | /* The last tick - i.e. the time to reset the tick_offset to when unpausing */ | ||
86 | static int last_tick; | ||
87 | |||
88 | void start_timer(void) | ||
89 | { | ||
90 | last_tick = 0; | ||
91 | tick_offset = *rb->current_tick; | ||
92 | } | ||
93 | |||
94 | void unpause_timer(void) | ||
95 | { | ||
96 | tick_offset = *rb->current_tick - last_tick; | ||
97 | } | ||
98 | |||
99 | void pause_timer(void) | ||
100 | { | ||
101 | /* Save the current MPEG tick */ | ||
102 | last_tick = *rb->current_tick - tick_offset; | ||
103 | } | ||
104 | |||
105 | |||
74 | static bool button_loop(void) | 106 | static bool button_loop(void) |
75 | { | 107 | { |
108 | bool result; | ||
76 | int button = rb->button_get(false); | 109 | int button = rb->button_get(false); |
110 | |||
77 | switch (button) | 111 | switch (button) |
78 | { | 112 | { |
113 | case MPEG_MENU: | ||
114 | pause_timer(); | ||
115 | |||
116 | result = mpeg_menu(); | ||
117 | |||
118 | unpause_timer(); | ||
119 | |||
120 | return result; | ||
121 | |||
79 | case MPEG_STOP: | 122 | case MPEG_STOP: |
80 | return true; | 123 | return true; |
124 | |||
81 | case MPEG_PAUSE: | 125 | case MPEG_PAUSE: |
126 | pause_timer(); /* Freeze time */ | ||
82 | button = BUTTON_NONE; | 127 | button = BUTTON_NONE; |
83 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 128 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
84 | rb->cpu_boost(false); | 129 | rb->cpu_boost(false); |
@@ -91,7 +136,9 @@ static bool button_loop(void) | |||
91 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 136 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
92 | rb->cpu_boost(true); | 137 | rb->cpu_boost(true); |
93 | #endif | 138 | #endif |
139 | unpause_timer(); /* Resume time */ | ||
94 | break; | 140 | break; |
141 | |||
95 | default: | 142 | default: |
96 | if(rb->default_event_handler(button) == SYS_USB_CONNECTED) | 143 | if(rb->default_event_handler(button) == SYS_USB_CONNECTED) |
97 | return true; | 144 | return true; |
@@ -99,10 +146,59 @@ static bool button_loop(void) | |||
99 | return false; | 146 | return false; |
100 | } | 147 | } |
101 | 148 | ||
149 | /* | ||
150 | |||
151 | NOTES: | ||
152 | |||
153 | MPEG System Clock is 27MHz - i.e. 27000000 ticks/second. | ||
154 | |||
155 | FPS is represented in terms of a frame period - this is always an | ||
156 | integer number of 27MHz ticks. | ||
157 | |||
158 | e.g. 29.97fps (30000/1001) NTSC video has an exact frame period of | ||
159 | 900900 27MHz ticks. | ||
160 | |||
161 | In libmpeg2, info->sequence->frame_period contains the frame_period. | ||
162 | |||
163 | Working with Rockbox's 100Hz tick, the common frame rates would need | ||
164 | to be as follows: | ||
165 | |||
166 | FPS | 27Mhz | 100Hz | ||
167 | --------|---------------- | ||
168 | 10* | 2700000 | 10 | ||
169 | 12* | 2250000 | 8.3333 | ||
170 | 15* | 1800000 | 6.6667 | ||
171 | 23.9760 | 1126125 | 4.170833333 | ||
172 | 24 | 1125000 | 4.166667 | ||
173 | 25 | 1080000 | 4 | ||
174 | 29.9700 | 900900 | 3.336667 | ||
175 | 30 | 900000 | 3.333333 | ||
176 | |||
177 | |||
178 | *Unofficial framerates | ||
179 | |||
180 | */ | ||
181 | |||
182 | static uint64_t eta; | ||
183 | |||
102 | static bool decode_mpeg2 (uint8_t * current, uint8_t * end) | 184 | static bool decode_mpeg2 (uint8_t * current, uint8_t * end) |
103 | { | 185 | { |
104 | const mpeg2_info_t * info; | 186 | const mpeg2_info_t * info; |
105 | mpeg2_state_t state; | 187 | mpeg2_state_t state; |
188 | char str[80]; | ||
189 | static int skipped = 0; | ||
190 | static int frame = 0; | ||
191 | static int starttick = 0; | ||
192 | static int lasttick; | ||
193 | unsigned int eta2; | ||
194 | unsigned int x; | ||
195 | |||
196 | int fps; | ||
197 | |||
198 | if (starttick == 0) { | ||
199 | starttick=*rb->current_tick-1; /* Avoid divby0 */ | ||
200 | lasttick=starttick; | ||
201 | } | ||
106 | 202 | ||
107 | mpeg2_buffer (mpeg2dec, current, end); | 203 | mpeg2_buffer (mpeg2dec, current, end); |
108 | total_offset += end - current; | 204 | total_offset += end - current; |
@@ -122,6 +218,7 @@ static bool decode_mpeg2 (uint8_t * current, uint8_t * end) | |||
122 | info->sequence->chroma_width, | 218 | info->sequence->chroma_width, |
123 | info->sequence->chroma_height); | 219 | info->sequence->chroma_height); |
124 | mpeg2_skip (mpeg2dec, false); | 220 | mpeg2_skip (mpeg2dec, false); |
221 | |||
125 | break; | 222 | break; |
126 | case STATE_PICTURE: | 223 | case STATE_PICTURE: |
127 | break; | 224 | break; |
@@ -129,8 +226,44 @@ static bool decode_mpeg2 (uint8_t * current, uint8_t * end) | |||
129 | case STATE_END: | 226 | case STATE_END: |
130 | case STATE_INVALID_END: | 227 | case STATE_INVALID_END: |
131 | /* draw current picture */ | 228 | /* draw current picture */ |
132 | if (info->display_fbuf) | 229 | if (info->display_fbuf) { |
133 | vo_draw_frame(info->display_fbuf->buf); | 230 | /* We start the timer when we draw the first frame */ |
231 | if (!tick_enabled) { | ||
232 | start_timer(); | ||
233 | tick_enabled = 1 ; | ||
234 | } | ||
235 | |||
236 | eta += (info->sequence->frame_period); | ||
237 | eta2 = eta / (27000000 / HZ); | ||
238 | |||
239 | if (settings.limitfps) { | ||
240 | if (eta2 > MPEG_CURRENT_TICK) { | ||
241 | rb->sleep(eta2-MPEG_CURRENT_TICK); | ||
242 | } | ||
243 | } | ||
244 | x = MPEG_CURRENT_TICK; | ||
245 | |||
246 | /* If we are more than 1/20 second behind schedule (and | ||
247 | more than 1/20 second into the decoding), skip frame */ | ||
248 | if (settings.skipframes && (x > HZ/20) && | ||
249 | (eta2 < (x - (HZ/20)))) { | ||
250 | skipped++; | ||
251 | } else { | ||
252 | vo_draw_frame(info->display_fbuf->buf); | ||
253 | } | ||
254 | |||
255 | /* Calculate fps */ | ||
256 | frame++; | ||
257 | if (settings.showfps && (*rb->current_tick-lasttick>=HZ)) { | ||
258 | fps=(frame*(HZ*10))/x; | ||
259 | rb->snprintf(str,sizeof(str),"%d.%d %d %d %d", | ||
260 | (fps/10),fps%10,skipped,x,eta2); | ||
261 | rb->lcd_putsxy(0,0,str); | ||
262 | rb->lcd_update_rect(0,0,LCD_WIDTH,8); | ||
263 | |||
264 | lasttick = *rb->current_tick; | ||
265 | } | ||
266 | } | ||
134 | break; | 267 | break; |
135 | default: | 268 | default: |
136 | break; | 269 | break; |
@@ -147,8 +280,10 @@ static void es_loop (int in_file, uint8_t* buffer, size_t buffer_size) | |||
147 | if (buffer==NULL) | 280 | if (buffer==NULL) |
148 | return; | 281 | return; |
149 | 282 | ||
283 | eta = 0; | ||
150 | do { | 284 | do { |
151 | rb->splash(0,true,"Buffering..."); | 285 | rb->splash(0,true,"Buffering..."); |
286 | save_settings(); /* Save settings (if they have changed) */ | ||
152 | end = buffer + rb->read (in_file, buffer, buffer_size); | 287 | end = buffer + rb->read (in_file, buffer, buffer_size); |
153 | if (decode_mpeg2 (buffer, end)) | 288 | if (decode_mpeg2 (buffer, end)) |
154 | break; | 289 | break; |
@@ -202,6 +337,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | |||
202 | return PLUGIN_ERROR; | 337 | return PLUGIN_ERROR; |
203 | } | 338 | } |
204 | 339 | ||
340 | init_settings(); | ||
341 | |||
205 | mpeg2dec = mpeg2_init (); | 342 | mpeg2dec = mpeg2_init (); |
206 | 343 | ||
207 | if (mpeg2dec == NULL) | 344 | if (mpeg2dec == NULL) |
@@ -230,6 +367,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | |||
230 | rb->cpu_boost(false); | 367 | rb->cpu_boost(false); |
231 | #endif | 368 | #endif |
232 | 369 | ||
370 | save_settings(); /* Save settings (if they have changed) */ | ||
371 | |||
233 | #ifdef CONFIG_BACKLIGHT | 372 | #ifdef CONFIG_BACKLIGHT |
234 | /* reset backlight settings */ | 373 | /* reset backlight settings */ |
235 | rb->backlight_set_timeout(rb->global_settings->backlight_timeout); | 374 | rb->backlight_set_timeout(rb->global_settings->backlight_timeout); |