Rearange menu of mpegplayer. Add new menu with "settings" and "quit", and remove...
[kugel-rb.git] / apps / plugins / mpegplayer / video_thread.c
blob6d60e641319bbdbcd093677f5c289a48186c7829
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * mpegplayer video thread implementation
12 * Copyright (c) 2007 Michael Sevakis
14 * 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.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
23 #include "plugin.h"
24 #include "mpegplayer.h"
25 #include "mpeg2dec_config.h"
26 #include "lib/grey.h"
27 #include "video_out.h"
28 #include "mpeg_settings.h"
30 /** Video stream and thread **/
32 /* Video thread data passed around to its various functions */
33 struct video_thread_data
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 */
42 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 */
50 uint32_t curr_time; /* Current due time of frame */
51 uint32_t period; /* Frame period in clock ticks */
52 int syncf_perfect; /* Last sync fit result */
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)
58 static uint32_t video_stack[VIDEO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR;
59 static struct event_queue video_str_queue SHAREDBSS_ATTR;
60 static struct queue_sender_list video_str_queue_send SHAREDBSS_ATTR;
61 struct stream video_str IBSS_ATTR;
63 static void draw_fps(struct video_thread_data *td)
65 uint32_t start;
66 uint32_t clock_ticks = stream_get_ticks(&start);
67 int fps = 0;
68 int buf_pct;
69 char str[80];
71 clock_ticks -= start;
72 if (clock_ticks != 0)
73 fps = muldiv_uint32(CLOCK_RATE*100, td->num_drawn, clock_ticks);
75 buf_pct = muldiv_uint32(100, pcm_output_used(), PCMOUT_BUFSIZE);
77 rb->snprintf(str, sizeof(str), "v:%d.%02d %d %d a:%02d%% %d %d ",
78 /* Video information */
79 fps / 100, fps % 100, td->num_skipped,
80 td->info->display_picture->temporal_reference,
81 /* Audio information */
82 buf_pct, pcm_underruns, pcm_skipped);
83 lcd_(putsxy)(0, 0, str);
85 vo_lock();
86 lcd_(update_rect)(0, 0, LCD_WIDTH, 8);
87 vo_unlock();
89 td->last_showfps = *rb->current_tick;
92 #if defined(DEBUG) || defined(SIMULATOR)
93 static unsigned char pic_coding_type_char(unsigned type)
95 switch (type)
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? */
109 #endif /* defined(DEBUG) || defined(SIMULATOR) */
111 /* Multi-use:
112 * 1) Find the sequence header and initialize video out
113 * 2) Find the end of the final frame
115 static int video_str_scan(struct video_thread_data *td,
116 struct str_sync_data *sd)
118 int retval = STREAM_ERROR;
119 uint32_t time = INVALID_TIMESTAMP;
120 uint32_t period = 0;
121 struct stream tmp_str;
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;
127 mpeg2_reset(td->mpeg2dec, false);
128 mpeg2_skip(td->mpeg2dec, 1);
130 while (1)
132 mpeg2_state_t mp2state = mpeg2_parse(td->mpeg2dec);
133 rb->yield();
135 switch (mp2state)
137 case STATE_BUFFER:
138 switch (parser_get_next_data(&tmp_str, STREAM_PM_RANDOM_ACCESS))
140 case STREAM_DATA_END:
141 DEBUGF("video_stream_scan:STREAM_DATA_END\n");
142 goto scan_finished;
144 case STREAM_OK:
145 if (tmp_str.pkt_flags & PKT_HAS_TS)
146 mpeg2_tag_picture(td->mpeg2dec, tmp_str.pts, 0);
148 mpeg2_buffer(td->mpeg2dec, tmp_str.curr_packet,
149 tmp_str.curr_packet_end);
150 td->info = mpeg2_info(td->mpeg2dec);
151 break;
153 break;
155 case STATE_SEQUENCE:
156 DEBUGF("video_stream_scan:STATE_SEQUENCE\n");
157 vo_setup(td->info->sequence);
159 if (td->ev.id == VIDEO_GET_SIZE)
161 retval = STREAM_OK;
162 goto scan_finished;
164 break;
166 case STATE_SLICE:
167 case STATE_END:
168 case STATE_INVALID_END:
170 if (td->info->display_picture == NULL)
171 break;
173 switch (td->ev.id)
175 case STREAM_SYNC:
176 retval = STREAM_OK;
177 goto scan_finished;
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;
185 period = TC_TO_TS(td->info->sequence->frame_period);
186 break;
189 break;
192 default:
193 break;
197 scan_finished:
199 if (td->ev.id == STREAM_FIND_END_TIME)
201 if (time != INVALID_TIMESTAMP)
203 sd->time = time + period;
204 retval = STREAM_PERFECT_MATCH;
206 else
208 retval = STREAM_NOT_FOUND;
212 mpeg2_skip(td->mpeg2dec, 0);
213 return retval;
216 static bool init_sequence(struct video_thread_data *td)
218 struct str_sync_data sd;
220 sd.time = 0; /* Ignored */
221 sd.sk.pos = 0;
222 sd.sk.len = 1024*1024;
223 sd.sk.dir = SSCAN_FORWARD;
225 return video_str_scan(td, &sd) == STREAM_OK;
228 static bool check_needs_sync(struct video_thread_data *td, uint32_t time)
230 uint32_t end_time;
232 DEBUGF("check_needs_sync:\n");
233 if (td->info == NULL || td->info->display_fbuf == NULL)
235 DEBUGF(" no fbuf\n");
236 return true;
239 if (td->syncf_perfect == 0)
241 DEBUGF(" no frame\n");
242 return true;
245 time = clip_time(&video_str, time);
246 end_time = td->curr_time + td->period;
248 DEBUGF(" sft:%u t:%u sfte:%u\n", (unsigned)td->curr_time,
249 (unsigned)time, (unsigned)end_time);
251 if (time < td->curr_time)
252 return true;
254 if (time >= end_time)
255 return time < video_str.end_pts || end_time < video_str.end_pts;
257 return false;
260 /* Do any needed decoding/slide up to the specified time */
261 static int sync_decoder(struct video_thread_data *td,
262 struct str_sync_data *sd)
264 int retval = STREAM_ERROR;
265 int ipic = 0, ppic = 0;
266 uint32_t time = clip_time(&video_str, sd->time);
268 td->syncf_perfect = 0;
269 td->curr_time = 0;
270 td->period = 0;
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))
276 DEBUGF("sync_decoder=>init_sequence failed\n");
277 goto sync_finished;
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);
285 while (1)
287 mpeg2_state_t mp2state = mpeg2_parse(td->mpeg2dec);
289 switch (mp2state)
291 case STATE_BUFFER:
292 switch (parser_get_next_data(&video_str, STREAM_PM_RANDOM_ACCESS))
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))
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;
305 goto sync_finished;
307 case STREAM_OK:
308 if (video_str.pkt_flags & PKT_HAS_TS)
309 mpeg2_tag_picture(td->mpeg2dec, video_str.pts, 0);
311 mpeg2_buffer(td->mpeg2dec, video_str.curr_packet,
312 video_str.curr_packet_end);
313 td->info = mpeg2_info(td->mpeg2dec);
314 break;
316 break;
318 case STATE_SEQUENCE:
319 DEBUGF(" STATE_SEQUENCE\n");
320 vo_setup(td->info->sequence);
321 break;
323 case STATE_GOP:
324 DEBUGF(" STATE_GOP: (%s)\n",
325 (td->info->gop->flags & GOP_FLAG_CLOSED_GOP) ?
326 "closed" : "open");
327 break;
329 case STATE_PICTURE:
331 int type = td->info->current_picture->flags
332 & PIC_MASK_CODING_TYPE;
334 switch (type)
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;
347 if (td->info->current_picture->flags & PIC_FLAG_TAGS)
349 DEBUGF(" STATE_PICTURE (%c): %u\n", pic_coding_type_char(type),
350 (unsigned)td->info->current_picture->tag);
352 else
354 DEBUGF(" STATE_PICTURE (%c): -\n", pic_coding_type_char(type));
357 break;
360 case STATE_SLICE:
361 case STATE_END:
362 case STATE_INVALID_END:
364 uint32_t end_time;
366 if (td->info->display_picture == NULL)
368 DEBUGF(" td->info->display_picture == NULL\n");
369 break; /* No picture */
372 int type = td->info->display_picture->flags
373 & PIC_MASK_CODING_TYPE;
375 if (td->info->display_picture->flags & PIC_FLAG_TAGS)
377 td->curr_time = td->info->display_picture->tag;
378 DEBUGF(" frame tagged:%u (%c%s)\n", (unsigned)td->curr_time,
379 pic_coding_type_char(type),
380 (td->info->display_picture->flags & PIC_FLAG_SKIP) ?
381 " skipped" : "");
383 else
385 td->curr_time += td->period;
386 DEBUGF(" add period:%u (%c%s)\n", (unsigned)td->curr_time,
387 pic_coding_type_char(type),
388 (td->info->display_picture->flags & PIC_FLAG_SKIP) ?
389 " skipped" : "");
392 td->period = TC_TO_TS(td->info->sequence->frame_period);
393 end_time = td->curr_time + td->period;
395 DEBUGF(" ft:%u t:%u fe:%u (%c%s)",
396 (unsigned)td->curr_time,
397 (unsigned)time,
398 (unsigned)end_time,
399 pic_coding_type_char(type),
400 (td->info->display_picture->flags & PIC_FLAG_SKIP) ?
401 " skipped" : "");
403 if (end_time <= time && end_time < video_str.end_pts)
405 /* Still too early and have not hit at EOS */
406 DEBUGF(" too early\n");
407 break;
409 else if (!(td->info->display_picture->flags & PIC_FLAG_SKIP))
411 /* One perfect point if dependent frames were decoded */
412 td->syncf_perfect = ipic;
414 if (type == PIC_FLAG_CODING_TYPE_B)
415 td->syncf_perfect &= ppic;
417 if ((td->curr_time <= time && time < end_time) ||
418 end_time >= video_str.end_pts)
420 /* One perfect point for matching time goal */
421 DEBUGF(" ft<=t<fe\n");
422 td->syncf_perfect++;
424 else
426 DEBUGF(" ft>t\n");
429 /* Two or more perfect points = perfect match - yay! */
430 retval = (td->syncf_perfect >= 2) ?
431 STREAM_PERFECT_MATCH : STREAM_MATCH;
433 else
435 /* Too late, no I-Frame yet */
436 DEBUGF("\n");
439 goto sync_finished;
442 default:
443 break;
446 rb->yield();
447 } /* end while */
449 sync_finished:
450 mpeg2_skip(td->mpeg2dec, 0);
451 return retval;
454 /* This only returns to play or quit */
455 static void video_thread_msg(struct video_thread_data *td)
457 while (1)
459 intptr_t reply = 0;
461 switch (td->ev.id)
463 case STREAM_PLAY:
464 td->status = STREAM_PLAYING;
466 switch (td->state)
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;
477 case TSTATE_INIT:
478 /* Begin decoding state */
479 td->state = TSTATE_DECODE;
480 break;
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;
489 reply = td->state != TSTATE_EOS;
490 break;
492 case STREAM_PAUSE:
493 td->status = STREAM_PAUSED;
494 reply = td->state != TSTATE_EOS;
495 break;
497 case STREAM_STOP:
498 if (td->state == TSTATE_DATA)
499 stream_clear_notify(&video_str, DISK_BUF_DATA_NOTIFY);
501 td->status = STREAM_STOPPED;
502 td->state = TSTATE_EOS;
503 reply = true;
504 break;
506 case VIDEO_DISPLAY_IS_VISIBLE:
507 reply = vo_is_visible();
508 break;
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);
515 #ifdef HAVE_LCD_COLOR
516 /* Match graylib behavior as much as possible */
517 if (!td->ev.data == !reply)
518 break;
520 if (td->ev.data)
522 if (td->info != NULL && td->info->display_fbuf != NULL)
523 vo_draw_frame(td->info->display_fbuf->buf);
525 else
527 IF_COP(rb->cpucache_invalidate());
528 vo_lock();
529 rb->lcd_update();
530 vo_unlock();
532 #endif
533 break;
535 case STREAM_RESET:
536 if (td->state == TSTATE_DATA)
537 stream_clear_notify(&video_str, DISK_BUF_DATA_NOTIFY);
539 td->state = TSTATE_INIT;
540 td->status = STREAM_STOPPED;
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;
554 reply = true;
555 break;
557 case STREAM_NEEDS_SYNC:
558 reply = check_needs_sync(td, td->ev.data);
559 break;
561 case STREAM_SYNC:
562 if (td->state == TSTATE_INIT)
563 reply = sync_decoder(td, (struct str_sync_data *)td->ev.data);
564 break;
566 case DISK_BUF_DATA_NOTIFY:
567 /* Our bun is done */
568 if (td->state != TSTATE_DATA)
569 break;
571 td->state = TSTATE_DECODE;
572 str_data_notify_received(&video_str);
573 break;
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)
580 vo_draw_frame_thumb(td->info->display_fbuf->buf,
581 (struct vo_rect *)td->ev.data);
582 reply = true;
584 break;
586 case VIDEO_SET_CLIP_RECT:
587 vo_set_clip_rect((const struct vo_rect *)td->ev.data);
588 break;
590 case VIDEO_PRINT_FRAME:
591 /* Print the last frame decoded */
592 if (td->info != NULL && td->info->display_fbuf != NULL)
594 vo_draw_frame(td->info->display_fbuf->buf);
595 reply = true;
597 break;
599 case VIDEO_GET_SIZE:
601 if (td->state != TSTATE_INIT)
602 break;
604 if (init_sequence(td))
606 reply = true;
607 vo_dimensions((struct vo_ext *)td->ev.data);
609 break;
612 case STREAM_FIND_END_TIME:
613 if (td->state != TSTATE_INIT)
615 reply = STREAM_ERROR;
616 break;
619 reply = video_str_scan(td, (struct str_sync_data *)td->ev.data);
620 break;
622 case STREAM_QUIT:
623 /* Time to go - make thread exit */
624 td->state = TSTATE_EOS;
625 return;
628 str_reply_msg(&video_str, reply);
630 if (td->status == STREAM_PLAYING)
632 switch (td->state)
634 case TSTATE_DECODE:
635 case TSTATE_RENDER:
636 case TSTATE_RENDER_WAIT:
637 /* These return when in playing state */
638 return;
642 str_get_msg(&video_str, &td->ev);
646 static void video_thread(void)
648 struct video_thread_data td;
650 td.status = STREAM_STOPPED;
651 td.state = TSTATE_EOS;
652 td.mpeg2dec = mpeg2_init();
653 td.info = NULL;
654 td.syncf_perfect = 0;
655 td.curr_time = 0;
656 td.period = 0;
658 if (td.mpeg2dec == NULL)
660 td.status = STREAM_ERROR;
661 /* Loop and wait for quit message */
662 while (1)
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);
671 vo_init();
673 goto message_wait;
675 while (1)
677 mpeg2_state_t mp2state;
678 td.state = TSTATE_DECODE;
680 /* Check for any pending messages and process them */
681 if (str_have_msg(&video_str))
683 message_wait:
684 /* Wait for a message to be queued */
685 str_get_msg(&video_str, &td.ev);
687 message_process:
688 /* Process a message already dequeued */
689 video_thread_msg(&td);
691 switch (td.state)
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;
705 picture_decode:
706 mp2state = mpeg2_parse (td.mpeg2dec);
708 switch (mp2state)
710 case STATE_BUFFER:
711 /* Request next packet data */
712 switch (parser_get_next_data(&video_str, STREAM_PM_STREAMING))
714 case STREAM_DATA_NOT_READY:
715 /* Wait for data to be buffered */
716 td.state = TSTATE_DATA;
717 goto message_wait;
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;
726 case STREAM_OK:
727 if (video_str.pkt_flags & PKT_HAS_TS)
728 mpeg2_tag_picture(td.mpeg2dec, video_str.pts, 0);
730 mpeg2_buffer(td.mpeg2dec, video_str.curr_packet,
731 video_str.curr_packet_end);
732 td.info = mpeg2_info(td.mpeg2dec);
733 break;
735 break;
737 case STATE_SEQUENCE:
738 /* New video sequence, inform output of any changes */
739 vo_setup(td.info->sequence);
740 break;
742 case STATE_PICTURE:
744 int skip = 0; /* Assume no skip */
746 if (td.frame_drop_level >= 1 || td.skip_level > 0)
748 /* A frame will be dropped in the decoder */
750 /* Frame type: I/P/B/D */
751 int type = td.info->current_picture->flags
752 & PIC_MASK_CODING_TYPE;
754 switch (type)
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)
764 td.frame_drop_level = 1;
765 td.skip_level = 0; /* reset */
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)
773 td.frame_drop_level = 1;
774 td.skip_level = 0; /* reset */
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--;
786 skip |= td.frame_drop_level;
789 mpeg2_skip(td.mpeg2dec, skip);
790 break;
793 case STATE_SLICE:
794 case STATE_END:
795 case STATE_INVALID_END:
797 int32_t offset; /* Tick adjustment to keep sync */
799 /* draw current picture */
800 if (td.info->display_fbuf == NULL)
801 break; /* No picture */
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) ?
806 td.info->display_picture->tag : (td.curr_time + td.period);
808 td.period = TC_TO_TS(td.info->sequence->frame_period);
810 /* No limiting => no dropping - draw this frame */
811 if (!settings.limitfps)
813 goto picture_draw;
816 td.eta_video = td.curr_time;
817 td.eta_stream = TICKS_TO_TS(stream_get_time());
819 /* How early/late are we? > 0 = late, < 0 early */
820 offset = td.eta_stream - td.eta_video;
822 if (!settings.skipframes)
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;
831 td.eta_late = AVERAGE(td.eta_late, offset, 4);
832 offset = td.eta_late;
834 if ((uint32_t)offset > td.eta_video)
835 offset = td.eta_video;
837 td.eta_video -= offset;
838 goto picture_wait;
841 /** Possibly skip this frame **/
843 /* Frameskipping has the following order of preference:
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
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.
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 */
861 td.eta_early = 0; /* Not early now :( */
863 td.eta_late = AVERAGE(td.eta_late, offset, 4);
864 offset = td.eta_late;
866 if ((uint32_t)offset > td.eta_video)
867 offset = td.eta_video;
869 td.eta_video -= offset;
871 else
873 td.eta_late = 0; /* Not late now :) */
875 if (offset > td.eta_early)
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;
883 td.eta_video += offset;
885 else
887 /* Just early with an offset, do exponential drift back */
888 if (td.eta_early != 0)
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);
895 offset = td.eta_early;
899 if (td.info->display_picture->flags & PIC_FLAG_SKIP)
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;
908 if (td.skip_level == 3 &&
909 TIME_BEFORE(*rb->current_tick, td.last_render + HZ/2))
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;
919 /* At this point a frame _will_ be drawn - a skip may happen on
920 the next however */
921 td.skip_level = 0;
923 if (offset > TS_SECOND*110/1000)
925 /* Decide which skip level is needed in order to catch up */
927 /* TODO: Calculate this rather than if...else - this is rather
928 exponential though */
929 if (offset > TS_SECOND*367/1000)
930 td.skip_level = 5; /* Decoder skip: I/D */
931 if (offset > TS_SECOND*233/1000)
932 td.skip_level = 4; /* Decoder skip: P */
933 else if (offset > TS_SECOND*167/1000)
934 td.skip_level = 3; /* Render skip */
935 else if (offset > TS_SECOND*133/1000)
936 td.skip_level = 2; /* Decoder skip: B */
937 else
938 td.skip_level = 1; /* Decoder skip: B */
941 picture_wait:
942 td.state = TSTATE_RENDER_WAIT;
944 /* Wait until time catches up */
945 while (td.eta_video > td.eta_stream)
947 /* Watch for messages while waiting for the frame time */
948 int32_t eta_remaining = td.eta_video - td.eta_stream;
949 if (eta_remaining > TS_SECOND/HZ)
951 /* Several ticks to wait - do some sleeping */
952 int timeout = (eta_remaining - HZ) / (TS_SECOND/HZ);
953 str_get_msg_w_tmo(&video_str, &td.ev, MAX(timeout, 1));
954 if (td.ev.id != SYS_TIMEOUT)
955 goto message_process;
957 else
959 /* Just a little left - spin and be accurate */
960 rb->yield();
961 if (str_have_msg(&video_str))
962 goto message_wait;
965 td.eta_stream = TICKS_TO_TS(stream_get_time());
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++;
974 picture_skip:
975 if (!settings.showfps)
976 break;
978 if (TIME_BEFORE(*rb->current_tick, td.last_showfps + HZ))
979 break;
981 /* Calculate and display fps */
982 draw_fps(&td);
983 break;
986 default:
987 break;
990 rb->yield();
991 } /* end while */
994 /* Initializes the video thread */
995 bool video_thread_init(void)
997 intptr_t rep;
999 IF_COP(rb->cpucache_flush());
1001 video_str.hdr.q = &video_str_queue;
1002 rb->queue_init(video_str.hdr.q, false);
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));
1009 rb->queue_enable_queue_send(video_str.hdr.q, &video_str_queue_send,
1010 video_str.thread);
1012 if (video_str.thread == 0)
1013 return false;
1015 /* Wait for thread to initialize */
1016 rep = str_send_msg(&video_str, STREAM_NULL, 0);
1017 IF_COP(rb->cpucache_invalidate());
1019 return rep == 0; /* Normally STREAM_NULL should be ignored */
1022 /* Terminates the video thread */
1023 void video_thread_exit(void)
1025 if (video_str.thread != 0)
1027 str_post_msg(&video_str, STREAM_QUIT, 0);
1028 rb->thread_wait(video_str.thread);
1029 IF_COP(rb->cpucache_invalidate());
1030 video_str.thread = 0;