blob: 91f08a5a667f011e8168811401e068611f4863b4 [file] [log] [blame]
Michael Sevakisa222f272007-12-29 19:46:35 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * mpegplayer video thread implementation
11 *
12 * Copyright (c) 2007 Michael Sevakis
13 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000014 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
Michael Sevakisa222f272007-12-29 19:46:35 +000018 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23#include "plugin.h"
24#include "mpegplayer.h"
25#include "mpeg2dec_config.h"
Jens Arnoldf4f90c22008-01-13 00:38:03 +000026#include "grey.h"
Michael Sevakisa222f272007-12-29 19:46:35 +000027#include "video_out.h"
28#include "mpeg_settings.h"
29
30/** Video stream and thread **/
31
32/* Video thread data passed around to its various functions */
33struct video_thread_data
34{
35 mpeg2dec_t *mpeg2dec; /* Our video decoder */
36 const mpeg2_info_t *info; /* Info about video stream */
37 int state; /* Thread state */
38 int status; /* Media status */
39 struct queue_event ev; /* Our event queue to receive commands */
40 int num_drawn; /* Number of frames drawn since reset */
41 int num_skipped; /* Number of frames skipped since reset */
Michael Sevakisa222f272007-12-29 19:46:35 +000042 uint32_t eta_stream; /* Current time of stream */
43 uint32_t eta_video; /* Time that frame has been scheduled for */
44 int32_t eta_early; /* How early has the frame been decoded? */
45 int32_t eta_late; /* How late has the frame been decoded? */
46 int frame_drop_level; /* Drop severity */
47 int skip_level; /* Skip severity */
48 long last_showfps; /* Last time the FPS display was updated */
49 long last_render; /* Last time a frame was drawn */
Michael Sevakisc8986302008-01-04 20:36:15 +000050 uint32_t curr_time; /* Current due time of frame */
51 uint32_t period; /* Frame period in clock ticks */
Michael Sevakisa222f272007-12-29 19:46:35 +000052 int syncf_perfect; /* Last sync fit result */
Michael Sevakisa222f272007-12-29 19:46:35 +000053};
54
55/* TODO: Check if 4KB is appropriate - it works for my test streams,
56 so maybe we can reduce it. */
57#define VIDEO_STACKSIZE (4*1024)
58static uint32_t video_stack[VIDEO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR;
Michael Sevakis05099142008-04-06 04:34:57 +000059static struct event_queue video_str_queue SHAREDBSS_ATTR;
60static struct queue_sender_list video_str_queue_send SHAREDBSS_ATTR;
Michael Sevakisa222f272007-12-29 19:46:35 +000061struct stream video_str IBSS_ATTR;
62
63static void draw_fps(struct video_thread_data *td)
64{
65 uint32_t start;
66 uint32_t clock_ticks = stream_get_ticks(&start);
67 int fps = 0;
Michael Sevakisf90cbcb2008-02-01 02:25:15 +000068 int buf_pct;
Michael Sevakisa222f272007-12-29 19:46:35 +000069 char str[80];
70
71 clock_ticks -= start;
72 if (clock_ticks != 0)
73 fps = muldiv_uint32(CLOCK_RATE*100, td->num_drawn, clock_ticks);
74
Michael Sevakisf90cbcb2008-02-01 02:25:15 +000075 buf_pct = muldiv_uint32(100, pcm_output_used(), PCMOUT_BUFSIZE);
76
77 rb->snprintf(str, sizeof(str), "v:%d.%02d %d %d a:%02d%% %d %d ",
78 /* Video information */
Michael Sevakisa222f272007-12-29 19:46:35 +000079 fps / 100, fps % 100, td->num_skipped,
Michael Sevakisf90cbcb2008-02-01 02:25:15 +000080 td->info->display_picture->temporal_reference,
81 /* Audio information */
82 buf_pct, pcm_underruns, pcm_skipped);
Michael Sevakis75380fd2008-01-09 22:19:25 +000083 lcd_(putsxy)(0, 0, str);
Michael Sevakisa5fc3f42008-01-03 17:14:28 +000084
85 vo_lock();
Michael Sevakis75380fd2008-01-09 22:19:25 +000086 lcd_(update_rect)(0, 0, LCD_WIDTH, 8);
Michael Sevakisa5fc3f42008-01-03 17:14:28 +000087 vo_unlock();
Michael Sevakisa222f272007-12-29 19:46:35 +000088
89 td->last_showfps = *rb->current_tick;
90}
91
92#if defined(DEBUG) || defined(SIMULATOR)
93static unsigned char pic_coding_type_char(unsigned type)
94{
95 switch (type)
96 {
97 case PIC_FLAG_CODING_TYPE_I:
98 return 'I'; /* Intra-coded */
99 case PIC_FLAG_CODING_TYPE_P:
100 return 'P'; /* Forward-predicted */
101 case PIC_FLAG_CODING_TYPE_B:
102 return 'B'; /* Bidirectionally-predicted */
103 case PIC_FLAG_CODING_TYPE_D:
104 return 'D'; /* DC-coded */
105 default:
106 return '?'; /* Say what? */
107 }
108}
109#endif /* defined(DEBUG) || defined(SIMULATOR) */
110
111/* Multi-use:
112 * 1) Find the sequence header and initialize video out
113 * 2) Find the end of the final frame
114 */
115static int video_str_scan(struct video_thread_data *td,
116 struct str_sync_data *sd)
117{
118 int retval = STREAM_ERROR;
119 uint32_t time = INVALID_TIMESTAMP;
120 uint32_t period = 0;
121 struct stream tmp_str;
122
123 tmp_str.id = video_str.id;
124 tmp_str.hdr.pos = sd->sk.pos;
125 tmp_str.hdr.limit = sd->sk.pos + sd->sk.len;
126
127 mpeg2_reset(td->mpeg2dec, false);
128 mpeg2_skip(td->mpeg2dec, 1);
129
130 while (1)
131 {
132 mpeg2_state_t mp2state = mpeg2_parse(td->mpeg2dec);
133 rb->yield();
134
135 switch (mp2state)
136 {
137 case STATE_BUFFER:
138 switch (parser_get_next_data(&tmp_str, STREAM_PM_RANDOM_ACCESS))
139 {
140 case STREAM_DATA_END:
141 DEBUGF("video_stream_scan:STREAM_DATA_END\n");
142 goto scan_finished;
143
144 case STREAM_OK:
145 if (tmp_str.pkt_flags & PKT_HAS_TS)
146 mpeg2_tag_picture(td->mpeg2dec, tmp_str.pts, 0);
147
148 mpeg2_buffer(td->mpeg2dec, tmp_str.curr_packet,
149 tmp_str.curr_packet_end);
150 td->info = mpeg2_info(td->mpeg2dec);
151 break;
152 }
153 break;
154
155 case STATE_SEQUENCE:
156 DEBUGF("video_stream_scan:STATE_SEQUENCE\n");
157 vo_setup(td->info->sequence);
158
159 if (td->ev.id == VIDEO_GET_SIZE)
160 {
161 retval = STREAM_OK;
162 goto scan_finished;
163 }
164 break;
165
166 case STATE_SLICE:
167 case STATE_END:
168 case STATE_INVALID_END:
169 {
170 if (td->info->display_picture == NULL)
171 break;
172
173 switch (td->ev.id)
174 {
175 case STREAM_SYNC:
176 retval = STREAM_OK;
177 goto scan_finished;
178
179 case STREAM_FIND_END_TIME:
180 if (td->info->display_picture->flags & PIC_FLAG_TAGS)
181 time = td->info->display_picture->tag;
182 else if (time != INVALID_TIMESTAMP)
183 time += period;
184
185 period = TC_TO_TS(td->info->sequence->frame_period);
186 break;
187 }
188
189 break;
190 }
191
192 default:
193 break;
194 }
195 }
196
197scan_finished:
198
199 if (td->ev.id == STREAM_FIND_END_TIME)
200 {
201 if (time != INVALID_TIMESTAMP)
202 {
203 sd->time = time + period;
204 retval = STREAM_PERFECT_MATCH;
205 }
206 else
207 {
208 retval = STREAM_NOT_FOUND;
209 }
210 }
211
212 mpeg2_skip(td->mpeg2dec, 0);
213 return retval;
214}
215
216static bool init_sequence(struct video_thread_data *td)
217{
218 struct str_sync_data sd;
219
220 sd.time = 0; /* Ignored */
221 sd.sk.pos = 0;
222 sd.sk.len = 1024*1024;
223 sd.sk.dir = SSCAN_FORWARD;
224
225 return video_str_scan(td, &sd) == STREAM_OK;
226}
227
228static bool check_needs_sync(struct video_thread_data *td, uint32_t time)
229{
Michael Sevakisc8986302008-01-04 20:36:15 +0000230 uint32_t end_time;
Michael Sevakisa222f272007-12-29 19:46:35 +0000231
232 DEBUGF("check_needs_sync:\n");
233 if (td->info == NULL || td->info->display_fbuf == NULL)
234 {
235 DEBUGF(" no fbuf\n");
236 return true;
237 }
238
239 if (td->syncf_perfect == 0)
240 {
241 DEBUGF(" no frame\n");
242 return true;
243 }
244
245 time = clip_time(&video_str, time);
Michael Sevakisc8986302008-01-04 20:36:15 +0000246 end_time = td->curr_time + td->period;
Michael Sevakisa222f272007-12-29 19:46:35 +0000247
Michael Sevakisc8986302008-01-04 20:36:15 +0000248 DEBUGF(" sft:%u t:%u sfte:%u\n", (unsigned)td->curr_time,
249 (unsigned)time, (unsigned)end_time);
Michael Sevakisa222f272007-12-29 19:46:35 +0000250
Michael Sevakisc8986302008-01-04 20:36:15 +0000251 if (time < td->curr_time)
Michael Sevakisa222f272007-12-29 19:46:35 +0000252 return true;
253
Michael Sevakisc8986302008-01-04 20:36:15 +0000254 if (time >= end_time)
255 return time < video_str.end_pts || end_time < video_str.end_pts;
Michael Sevakisa222f272007-12-29 19:46:35 +0000256
257 return false;
258}
259
260/* Do any needed decoding/slide up to the specified time */
261static int sync_decoder(struct video_thread_data *td,
262 struct str_sync_data *sd)
263{
264 int retval = STREAM_ERROR;
265 int ipic = 0, ppic = 0;
266 uint32_t time = clip_time(&video_str, sd->time);
267
268 td->syncf_perfect = 0;
Michael Sevakisa222f272007-12-29 19:46:35 +0000269 td->curr_time = 0;
270 td->period = 0;
271
272 /* Sometimes theres no sequence headers nearby and libmpeg2 may have reset
273 * fully at some point */
274 if ((td->info == NULL || td->info->sequence == NULL) && !init_sequence(td))
275 {
276 DEBUGF("sync_decoder=>init_sequence failed\n");
277 goto sync_finished;
278 }
279
280 video_str.hdr.pos = sd->sk.pos;
281 video_str.hdr.limit = sd->sk.pos + sd->sk.len;
282 mpeg2_reset(td->mpeg2dec, false);
283 mpeg2_skip(td->mpeg2dec, 1);
284
285 while (1)
286 {
287 mpeg2_state_t mp2state = mpeg2_parse(td->mpeg2dec);
Michael Sevakisa222f272007-12-29 19:46:35 +0000288
289 switch (mp2state)
290 {
291 case STATE_BUFFER:
292 switch (parser_get_next_data(&video_str, STREAM_PM_RANDOM_ACCESS))
293 {
294 case STREAM_DATA_END:
295 DEBUGF("sync_decoder:STR_DATA_END\n");
296 if (td->info && td->info->display_picture &&
297 !(td->info->display_picture->flags & PIC_FLAG_SKIP))
298 {
299 /* No frame matching the time was found up to the end of
300 * the stream - consider a perfect match since no better
301 * can be made */
302 retval = STREAM_PERFECT_MATCH;
303 td->syncf_perfect = 1;
304 }
305 goto sync_finished;
306
307 case STREAM_OK:
308 if (video_str.pkt_flags & PKT_HAS_TS)
309 mpeg2_tag_picture(td->mpeg2dec, video_str.pts, 0);
310
311 mpeg2_buffer(td->mpeg2dec, video_str.curr_packet,
312 video_str.curr_packet_end);
313 td->info = mpeg2_info(td->mpeg2dec);
314 break;
315 }
316 break;
317
318 case STATE_SEQUENCE:
319 DEBUGF(" STATE_SEQUENCE\n");
320 vo_setup(td->info->sequence);
321 break;
322
323 case STATE_GOP:
324 DEBUGF(" STATE_GOP: (%s)\n",
325 (td->info->gop->flags & GOP_FLAG_CLOSED_GOP) ?
326 "closed" : "open");
327 break;
328
329 case STATE_PICTURE:
330 {
331 int type = td->info->current_picture->flags
332 & PIC_MASK_CODING_TYPE;
333
334 switch (type)
335 {
336 case PIC_FLAG_CODING_TYPE_I:
337 /* I-frame; start decoding */
338 mpeg2_skip(td->mpeg2dec, 0);
339 ipic = 1;
340 break;
341 case PIC_FLAG_CODING_TYPE_P:
342 /* P-frames don't count without I-frames */
343 ppic = ipic;
344 break;
345 }
346
347 if (td->info->current_picture->flags & PIC_FLAG_TAGS)
348 {
349 DEBUGF(" STATE_PICTURE (%c): %u\n", pic_coding_type_char(type),
350 (unsigned)td->info->current_picture->tag);
351 }
352 else
353 {
354 DEBUGF(" STATE_PICTURE (%c): -\n", pic_coding_type_char(type));
355 }
356
357 break;
358 }
359
360 case STATE_SLICE:
361 case STATE_END:
362 case STATE_INVALID_END:
363 {
Michael Sevakisc8986302008-01-04 20:36:15 +0000364 uint32_t end_time;
Michael Sevakisa222f272007-12-29 19:46:35 +0000365
366 if (td->info->display_picture == NULL)
367 {
368 DEBUGF(" td->info->display_picture == NULL\n");
369 break; /* No picture */
370 }
371
372 int type = td->info->display_picture->flags
373 & PIC_MASK_CODING_TYPE;
374
375 if (td->info->display_picture->flags & PIC_FLAG_TAGS)
376 {
Michael Sevakisc8986302008-01-04 20:36:15 +0000377 td->curr_time = td->info->display_picture->tag;
378 DEBUGF(" frame tagged:%u (%c%s)\n", (unsigned)td->curr_time,
Michael Sevakisa222f272007-12-29 19:46:35 +0000379 pic_coding_type_char(type),
380 (td->info->display_picture->flags & PIC_FLAG_SKIP) ?
381 " skipped" : "");
382 }
383 else
384 {
Michael Sevakisc8986302008-01-04 20:36:15 +0000385 td->curr_time += td->period;
386 DEBUGF(" add period:%u (%c%s)\n", (unsigned)td->curr_time,
Michael Sevakisa222f272007-12-29 19:46:35 +0000387 pic_coding_type_char(type),
388 (td->info->display_picture->flags & PIC_FLAG_SKIP) ?
389 " skipped" : "");
390 }
391
Michael Sevakisc8986302008-01-04 20:36:15 +0000392 td->period = TC_TO_TS(td->info->sequence->frame_period);
393 end_time = td->curr_time + td->period;
Michael Sevakisa222f272007-12-29 19:46:35 +0000394
395 DEBUGF(" ft:%u t:%u fe:%u (%c%s)",
Michael Sevakisc8986302008-01-04 20:36:15 +0000396 (unsigned)td->curr_time,
Michael Sevakisa222f272007-12-29 19:46:35 +0000397 (unsigned)time,
Michael Sevakisc8986302008-01-04 20:36:15 +0000398 (unsigned)end_time,
Michael Sevakisa222f272007-12-29 19:46:35 +0000399 pic_coding_type_char(type),
400 (td->info->display_picture->flags & PIC_FLAG_SKIP) ?
401 " skipped" : "");
402
Michael Sevakisc8986302008-01-04 20:36:15 +0000403 if (end_time <= time && end_time < video_str.end_pts)
Michael Sevakisa222f272007-12-29 19:46:35 +0000404 {
405 /* Still too early and have not hit at EOS */
406 DEBUGF(" too early\n");
407 break;
408 }
409 else if (!(td->info->display_picture->flags & PIC_FLAG_SKIP))
410 {
411 /* One perfect point if dependent frames were decoded */
412 td->syncf_perfect = ipic;
413
414 if (type == PIC_FLAG_CODING_TYPE_B)
415 td->syncf_perfect &= ppic;
416
Michael Sevakisc8986302008-01-04 20:36:15 +0000417 if ((td->curr_time <= time && time < end_time) ||
418 end_time >= video_str.end_pts)
Michael Sevakisa222f272007-12-29 19:46:35 +0000419 {
420 /* One perfect point for matching time goal */
421 DEBUGF(" ft<=t<fe\n");
422 td->syncf_perfect++;
423 }
424 else
425 {
426 DEBUGF(" ft>t\n");
427 }
428
429 /* Two or more perfect points = perfect match - yay! */
430 retval = (td->syncf_perfect >= 2) ?
431 STREAM_PERFECT_MATCH : STREAM_MATCH;
432 }
433 else
434 {
435 /* Too late, no I-Frame yet */
436 DEBUGF("\n");
437 }
438
439 goto sync_finished;
440 }
441
442 default:
443 break;
444 }
445
446 rb->yield();
447 } /* end while */
448
449sync_finished:
450 mpeg2_skip(td->mpeg2dec, 0);
451 return retval;
452}
453
454/* This only returns to play or quit */
455static void video_thread_msg(struct video_thread_data *td)
456{
457 while (1)
458 {
459 intptr_t reply = 0;
460
461 switch (td->ev.id)
462 {
463 case STREAM_PLAY:
464 td->status = STREAM_PLAYING;
465
466 switch (td->state)
467 {
468 case TSTATE_RENDER_WAIT:
469 /* Settings may have changed to nonlimited - just draw
470 * what was previously being waited for */
471 if (!settings.limitfps)
472 td->state = TSTATE_RENDER;
473 case TSTATE_DECODE:
474 case TSTATE_RENDER:
475 break;
476
477 case TSTATE_INIT:
478 /* Begin decoding state */
479 td->state = TSTATE_DECODE;
480 break;
481
482 case TSTATE_EOS:
483 /* At end of stream - no playback possible so fire the
484 * completion event */
485 stream_generate_event(&video_str, STREAM_EV_COMPLETE, 0);
486 break;
487 }
488
489 reply = td->state != TSTATE_EOS;
490 break;
491
492 case STREAM_PAUSE:
493 td->status = STREAM_PAUSED;
494 reply = td->state != TSTATE_EOS;
495 break;
496
497 case STREAM_STOP:
498 if (td->state == TSTATE_DATA)
Michael Sevakis75380fd2008-01-09 22:19:25 +0000499 stream_clear_notify(&video_str, DISK_BUF_DATA_NOTIFY);
Michael Sevakisa222f272007-12-29 19:46:35 +0000500
501 td->status = STREAM_STOPPED;
502 td->state = TSTATE_EOS;
503 reply = true;
504 break;
505
506 case VIDEO_DISPLAY_IS_VISIBLE:
507 reply = vo_is_visible();
508 break;
509
510 case VIDEO_DISPLAY_SHOW:
511 /* Show video and draw the last frame we had if any or reveal the
512 * underlying framebuffer if hiding */
513 reply = vo_show(!!td->ev.data);
514
515#ifdef HAVE_LCD_COLOR
516 /* Match graylib behavior as much as possible */
517 if (!td->ev.data == !reply)
518 break;
519
520 if (td->ev.data)
521 {
522 if (td->info != NULL && td->info->display_fbuf != NULL)
523 vo_draw_frame(td->info->display_fbuf->buf);
524 }
525 else
526 {
527 IF_COP(invalidate_icache());
Michael Sevakisa5fc3f42008-01-03 17:14:28 +0000528 vo_lock();
Michael Sevakisa222f272007-12-29 19:46:35 +0000529 rb->lcd_update();
Michael Sevakisa5fc3f42008-01-03 17:14:28 +0000530 vo_unlock();
Michael Sevakisa222f272007-12-29 19:46:35 +0000531 }
Michael Sevakisa222f272007-12-29 19:46:35 +0000532#endif
533 break;
534
535 case STREAM_RESET:
536 if (td->state == TSTATE_DATA)
Michael Sevakis75380fd2008-01-09 22:19:25 +0000537 stream_clear_notify(&video_str, DISK_BUF_DATA_NOTIFY);
Michael Sevakisa222f272007-12-29 19:46:35 +0000538
539 td->state = TSTATE_INIT;
540 td->status = STREAM_STOPPED;
541
542 /* Reset operational info but not sync info */
543 td->eta_stream = UINT32_MAX;
544 td->eta_video = 0;
545 td->eta_early = 0;
546 td->eta_late = 0;
547 td->frame_drop_level = 0;
548 td->skip_level = 0;
549 td->num_drawn = 0;
550 td->num_skipped = 0;
551 td->last_showfps = *rb->current_tick - HZ;
552 td->last_render = td->last_showfps;
553
554 reply = true;
555 break;
556
557 case STREAM_NEEDS_SYNC:
558 reply = check_needs_sync(td, td->ev.data);
559 break;
560
561 case STREAM_SYNC:
562 if (td->state == TSTATE_INIT)
563 reply = sync_decoder(td, (struct str_sync_data *)td->ev.data);
564 break;
565
566 case DISK_BUF_DATA_NOTIFY:
567 /* Our bun is done */
568 if (td->state != TSTATE_DATA)
569 break;
570
571 td->state = TSTATE_DECODE;
572 str_data_notify_received(&video_str);
573 break;
574
575 case VIDEO_PRINT_THUMBNAIL:
576 /* Print a thumbnail of whatever was last decoded - scale and
577 * position to fill the specified rectangle */
578 if (td->info != NULL && td->info->display_fbuf != NULL)
579 {
580 vo_draw_frame_thumb(td->info->display_fbuf->buf,
581 (struct vo_rect *)td->ev.data);
582 reply = true;
583 }
584 break;
585
Michael Sevakisa5fc3f42008-01-03 17:14:28 +0000586 case VIDEO_SET_CLIP_RECT:
587 vo_set_clip_rect((const struct vo_rect *)td->ev.data);
588 break;
589
Michael Sevakisa222f272007-12-29 19:46:35 +0000590 case VIDEO_PRINT_FRAME:
591 /* Print the last frame decoded */
592 if (td->info != NULL && td->info->display_fbuf != NULL)
593 {
594 vo_draw_frame(td->info->display_fbuf->buf);
595 reply = true;
596 }
597 break;
598
599 case VIDEO_GET_SIZE:
600 {
601 if (td->state != TSTATE_INIT)
602 break;
603
604 if (init_sequence(td))
605 {
606 reply = true;
607 vo_dimensions((struct vo_ext *)td->ev.data);
608 }
609 break;
610 }
611
612 case STREAM_FIND_END_TIME:
613 if (td->state != TSTATE_INIT)
614 {
615 reply = STREAM_ERROR;
616 break;
617 }
618
619 reply = video_str_scan(td, (struct str_sync_data *)td->ev.data);
620 break;
621
Michael Sevakisa222f272007-12-29 19:46:35 +0000622 case STREAM_QUIT:
623 /* Time to go - make thread exit */
624 td->state = TSTATE_EOS;
625 return;
626 }
627
628 str_reply_msg(&video_str, reply);
629
630 if (td->status == STREAM_PLAYING)
631 {
632 switch (td->state)
633 {
634 case TSTATE_DECODE:
635 case TSTATE_RENDER:
636 case TSTATE_RENDER_WAIT:
637 /* These return when in playing state */
638 return;
639 }
640 }
641
642 str_get_msg(&video_str, &td->ev);
643 }
644}
645
646static void video_thread(void)
647{
648 struct video_thread_data td;
649
650 td.status = STREAM_STOPPED;
651 td.state = TSTATE_EOS;
652 td.mpeg2dec = mpeg2_init();
653 td.info = NULL;
654 td.syncf_perfect = 0;
Michael Sevakisc8986302008-01-04 20:36:15 +0000655 td.curr_time = 0;
656 td.period = 0;
Michael Sevakisa222f272007-12-29 19:46:35 +0000657
658 if (td.mpeg2dec == NULL)
659 {
660 td.status = STREAM_ERROR;
661 /* Loop and wait for quit message */
662 while (1)
663 {
664 str_get_msg(&video_str, &td.ev);
665 if (td.ev.id == STREAM_QUIT)
666 return;
667 str_reply_msg(&video_str, STREAM_ERROR);
668 }
669 }
670
671 vo_init();
672
673 goto message_wait;
674
675 while (1)
676 {
677 mpeg2_state_t mp2state;
678 td.state = TSTATE_DECODE;
679
680 /* Check for any pending messages and process them */
681 if (str_have_msg(&video_str))
682 {
683 message_wait:
684 /* Wait for a message to be queued */
685 str_get_msg(&video_str, &td.ev);
686
687 message_process:
688 /* Process a message already dequeued */
689 video_thread_msg(&td);
690
691 switch (td.state)
692 {
693 /* These states are the only ones that should return */
694 case TSTATE_DECODE: goto picture_decode;
695 case TSTATE_RENDER: goto picture_draw;
696 case TSTATE_RENDER_WAIT: goto picture_wait;
697 /* Anything else is interpreted as an exit */
698 default:
699 vo_cleanup();
700 mpeg2_close(td.mpeg2dec);
701 return;
702 }
703 }
704
705 picture_decode:
706 mp2state = mpeg2_parse (td.mpeg2dec);
Michael Sevakisa222f272007-12-29 19:46:35 +0000707
708 switch (mp2state)
709 {
710 case STATE_BUFFER:
711 /* Request next packet data */
712 switch (parser_get_next_data(&video_str, STREAM_PM_STREAMING))
713 {
714 case STREAM_DATA_NOT_READY:
715 /* Wait for data to be buffered */
716 td.state = TSTATE_DATA;
717 goto message_wait;
718
719 case STREAM_DATA_END:
720 /* No more data. */
721 td.state = TSTATE_EOS;
722 if (td.status == STREAM_PLAYING)
723 stream_generate_event(&video_str, STREAM_EV_COMPLETE, 0);
724 goto message_wait;
725
726 case STREAM_OK:
727 if (video_str.pkt_flags & PKT_HAS_TS)
728 mpeg2_tag_picture(td.mpeg2dec, video_str.pts, 0);
729
730 mpeg2_buffer(td.mpeg2dec, video_str.curr_packet,
731 video_str.curr_packet_end);
732 td.info = mpeg2_info(td.mpeg2dec);
733 break;
734 }
735 break;
736
737 case STATE_SEQUENCE:
738 /* New video sequence, inform output of any changes */
739 vo_setup(td.info->sequence);
740 break;
741
742 case STATE_PICTURE:
743 {
744 int skip = 0; /* Assume no skip */
745
746 if (td.frame_drop_level >= 1 || td.skip_level > 0)
747 {
748 /* A frame will be dropped in the decoder */
749
750 /* Frame type: I/P/B/D */
751 int type = td.info->current_picture->flags
752 & PIC_MASK_CODING_TYPE;
753
754 switch (type)
755 {
756 case PIC_FLAG_CODING_TYPE_I:
757 case PIC_FLAG_CODING_TYPE_D:
758 /* Level 5: Things are extremely late and all frames will
759 be dropped until the next key frame */
760 if (td.frame_drop_level >= 1)
761 td.frame_drop_level = 0; /* Key frame - reset drop level */
762 if (td.skip_level >= 5)
763 {
764 td.frame_drop_level = 1;
765 td.skip_level = 0; /* reset */
766 }
767 break;
768 case PIC_FLAG_CODING_TYPE_P:
769 /* Level 4: Things are very late and all frames will be
770 dropped until the next key frame */
771 if (td.skip_level >= 4)
772 {
773 td.frame_drop_level = 1;
774 td.skip_level = 0; /* reset */
775 }
776 break;
777 case PIC_FLAG_CODING_TYPE_B:
778 /* We want to drop something, so this B frame won't even
779 be decoded. Drawing can happen on the next frame if so
780 desired. Bring the level down as skips are done. */
781 skip = 1;
782 if (td.skip_level > 0)
783 td.skip_level--;
784 }
785
786 skip |= td.frame_drop_level;
787 }
788
789 mpeg2_skip(td.mpeg2dec, skip);
790 break;
791 }
792
793 case STATE_SLICE:
794 case STATE_END:
795 case STATE_INVALID_END:
796 {
797 int32_t offset; /* Tick adjustment to keep sync */
798
799 /* draw current picture */
800 if (td.info->display_fbuf == NULL)
801 break; /* No picture */
802
803 /* Get presentation times in audio samples - quite accurate
804 enough - add previous frame duration if not stamped */
805 td.curr_time = (td.info->display_picture->flags & PIC_FLAG_TAGS) ?
Michael Sevakisc8986302008-01-04 20:36:15 +0000806 td.info->display_picture->tag : (td.curr_time + td.period);
Michael Sevakisa222f272007-12-29 19:46:35 +0000807
Michael Sevakisc8986302008-01-04 20:36:15 +0000808 td.period = TC_TO_TS(td.info->sequence->frame_period);
Michael Sevakisa222f272007-12-29 19:46:35 +0000809
810 /* No limiting => no dropping - draw this frame */
811 if (!settings.limitfps)
812 {
813 goto picture_draw;
814 }
815
816 td.eta_video = td.curr_time;
Michael Sevakisc8986302008-01-04 20:36:15 +0000817 td.eta_stream = TICKS_TO_TS(stream_get_time());
Michael Sevakisa222f272007-12-29 19:46:35 +0000818
819 /* How early/late are we? > 0 = late, < 0 early */
820 offset = td.eta_stream - td.eta_video;
821
822 if (!settings.skipframes)
823 {
824 /* Make no effort to determine whether this frame should be
825 drawn or not since no action can be taken to correct the
826 situation. We'll just wait if we're early and correct for
827 lateness as much as possible. */
828 if (offset < 0)
829 offset = 0;
830
831 td.eta_late = AVERAGE(td.eta_late, offset, 4);
832 offset = td.eta_late;
833
834 if ((uint32_t)offset > td.eta_video)
835 offset = td.eta_video;
836
837 td.eta_video -= offset;
838 goto picture_wait;
839 }
840
841 /** Possibly skip this frame **/
842
843 /* Frameskipping has the following order of preference:
844 *
845 * Frame Type Who Notes/Rationale
846 * B decoder arbitrarily drop - no decode or draw
847 * Any renderer arbitrarily drop - will be I/D/P
848 * P decoder must wait for I/D-frame - choppy
849 * I/D decoder must wait for I/D-frame - choppy
850 *
851 * If a frame can be drawn and it has been at least 1/2 second,
852 * the image will be updated no matter how late it is just to
853 * avoid looking stuck.
854 */
855
856 /* If we're late, set the eta to play the frame early so
857 we may catch up. If early, especially because of a drop,
858 mitigate a "snap" by moving back gradually. */
859 if (offset >= 0) /* late or on time */
860 {
861 td.eta_early = 0; /* Not early now :( */
862
863 td.eta_late = AVERAGE(td.eta_late, offset, 4);
864 offset = td.eta_late;
865
866 if ((uint32_t)offset > td.eta_video)
867 offset = td.eta_video;
868
869 td.eta_video -= offset;
870 }
871 else
872 {
873 td.eta_late = 0; /* Not late now :) */
874
875 if (offset > td.eta_early)
876 {
877 /* Just dropped a frame and we're now early or we're
878 coming back from being early */
879 td.eta_early = offset;
880 if ((uint32_t)-offset > td.eta_video)
881 offset = -td.eta_video;
882
883 td.eta_video += offset;
884 }
885 else
886 {
887 /* Just early with an offset, do exponential drift back */
888 if (td.eta_early != 0)
889 {
890 td.eta_early = AVERAGE(td.eta_early, 0, 8);
891 td.eta_video = ((uint32_t)-td.eta_early > td.eta_video) ?
892 0 : (td.eta_video + td.eta_early);
893 }
894
895 offset = td.eta_early;
896 }
897 }
898
899 if (td.info->display_picture->flags & PIC_FLAG_SKIP)
900 {
901 /* This frame was set to skip so skip it after having updated
902 timing information */
903 td.num_skipped++;
904 td.eta_early = INT32_MIN;
905 goto picture_skip;
906 }
907
908 if (td.skip_level == 3 &&
909 TIME_BEFORE(*rb->current_tick, td.last_render + HZ/2))
910 {
911 /* Render drop was set previously but nothing was dropped in the
912 decoder or it's been to long since drawing the last frame. */
913 td.skip_level = 0;
914 td.num_skipped++;
915 td.eta_early = INT32_MIN;
916 goto picture_skip;
917 }
918
919 /* At this point a frame _will_ be drawn - a skip may happen on
920 the next however */
921 td.skip_level = 0;
922
Michael Sevakisc8986302008-01-04 20:36:15 +0000923 if (offset > TS_SECOND*110/1000)
Michael Sevakisa222f272007-12-29 19:46:35 +0000924 {
925 /* Decide which skip level is needed in order to catch up */
926
927 /* TODO: Calculate this rather than if...else - this is rather
928 exponential though */
Michael Sevakisc8986302008-01-04 20:36:15 +0000929 if (offset > TS_SECOND*367/1000)
Michael Sevakisa222f272007-12-29 19:46:35 +0000930 td.skip_level = 5; /* Decoder skip: I/D */
Michael Sevakisc8986302008-01-04 20:36:15 +0000931 if (offset > TS_SECOND*233/1000)
Michael Sevakisa222f272007-12-29 19:46:35 +0000932 td.skip_level = 4; /* Decoder skip: P */
Michael Sevakisc8986302008-01-04 20:36:15 +0000933 else if (offset > TS_SECOND*167/1000)
Michael Sevakisa222f272007-12-29 19:46:35 +0000934 td.skip_level = 3; /* Render skip */
Michael Sevakisc8986302008-01-04 20:36:15 +0000935 else if (offset > TS_SECOND*133/1000)
Michael Sevakisa222f272007-12-29 19:46:35 +0000936 td.skip_level = 2; /* Decoder skip: B */
937 else
938 td.skip_level = 1; /* Decoder skip: B */
939 }
940
941 picture_wait:
942 td.state = TSTATE_RENDER_WAIT;
943
944 /* Wait until time catches up */
945 while (td.eta_video > td.eta_stream)
946 {
947 /* Watch for messages while waiting for the frame time */
948 int32_t eta_remaining = td.eta_video - td.eta_stream;
Michael Sevakisc8986302008-01-04 20:36:15 +0000949 if (eta_remaining > TS_SECOND/HZ)
Michael Sevakisa222f272007-12-29 19:46:35 +0000950 {
951 /* Several ticks to wait - do some sleeping */
Michael Sevakisc8986302008-01-04 20:36:15 +0000952 int timeout = (eta_remaining - HZ) / (TS_SECOND/HZ);
Michael Sevakisa222f272007-12-29 19:46:35 +0000953 str_get_msg_w_tmo(&video_str, &td.ev, MAX(timeout, 1));
954 if (td.ev.id != SYS_TIMEOUT)
955 goto message_process;
956 }
957 else
958 {
959 /* Just a little left - spin and be accurate */
Michael Sevakis27cf6772008-03-25 02:34:12 +0000960 rb->yield();
Michael Sevakisa222f272007-12-29 19:46:35 +0000961 if (str_have_msg(&video_str))
962 goto message_wait;
963 }
964
Michael Sevakisc8986302008-01-04 20:36:15 +0000965 td.eta_stream = TICKS_TO_TS(stream_get_time());
Michael Sevakisa222f272007-12-29 19:46:35 +0000966 }
967
968 picture_draw:
969 /* Record last frame time */
970 td.last_render = *rb->current_tick;
971 vo_draw_frame(td.info->display_fbuf->buf);
972 td.num_drawn++;
973
974 picture_skip:
975 if (!settings.showfps)
976 break;
977
978 if (TIME_BEFORE(*rb->current_tick, td.last_showfps + HZ))
979 break;
980
981 /* Calculate and display fps */
982 draw_fps(&td);
983 break;
984 }
985
986 default:
987 break;
988 }
989
990 rb->yield();
991 } /* end while */
992}
993
994/* Initializes the video thread */
995bool video_thread_init(void)
996{
997 intptr_t rep;
998
999 IF_COP(flush_icache());
1000
1001 video_str.hdr.q = &video_str_queue;
1002 rb->queue_init(video_str.hdr.q, false);
Michael Sevakisa222f272007-12-29 19:46:35 +00001003
1004 /* We put the video thread on another processor for multi-core targets. */
1005 video_str.thread = rb->create_thread(
1006 video_thread, video_stack, VIDEO_STACKSIZE, 0,
1007 "mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK) IF_COP(, COP));
1008
Michael Sevakis27cf6772008-03-25 02:34:12 +00001009 rb->queue_enable_queue_send(video_str.hdr.q, &video_str_queue_send,
1010 video_str.thread);
1011
Michael Sevakisa222f272007-12-29 19:46:35 +00001012 if (video_str.thread == NULL)
1013 return false;
1014
1015 /* Wait for thread to initialize */
1016 rep = str_send_msg(&video_str, STREAM_NULL, 0);
1017 IF_COP(invalidate_icache());
1018
1019 return rep == 0; /* Normally STREAM_NULL should be ignored */
1020}
1021
1022/* Terminates the video thread */
1023void video_thread_exit(void)
1024{
1025 if (video_str.thread != NULL)
1026 {
1027 str_post_msg(&video_str, STREAM_QUIT, 0);
1028 rb->thread_wait(video_str.thread);
1029 IF_COP(invalidate_icache());
1030 video_str.thread = NULL;
1031 }
Michael Sevakisa222f272007-12-29 19:46:35 +00001032}