mpegplayer: Move libmpeg2 files into their own subdirectory so things are less cluttered.
[kugel-rb.git] / apps / plugins / mpegplayer / video_thread.c
blob5119712396151edaaa996cfacf120b4ecce55ebd
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 "libmpeg2/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 /* Stream data */
36 mpeg2dec_t *mpeg2dec; /* Our video decoder */
37 const mpeg2_info_t *info; /* Info about video stream */
38 int state; /* Thread state */
39 int status; /* Media status */
40 struct queue_event ev;/* Our event queue to receive commands */
41 /* Operational info */
42 uint32_t stream_time; /* Current time from beginning of stream */
43 uint32_t goal_time; /* Scheduled time of current frame */
44 int32_t remain_time; /* T-minus value to frame_time (-:early, +:late) */
45 int skip_ref_pics; /* Severe skipping - wait for I-frame */
46 int skip_level; /* Number of frames still to skip */
47 int num_picture; /* Number of picture headers read */
48 int num_intra; /* Number of I-picture headers read */
49 int group_est; /* Estmated number remaining as of last I */
50 long last_render; /* Last time a frame was drawn */
51 /* Sync info */
52 uint32_t frame_time; /* Current due time of frame (unadjusted) */
53 uint32_t frame_period; /* Frame period in clock ticks */
54 int num_ref_pics; /* Number of I and P frames since sync/skip */
55 int syncf_perfect; /* Last sync fit result */
58 /* Number drawn since reset */
59 static int video_num_drawn SHAREDBSS_ATTR;
60 /* Number skipped since reset */
61 static int video_num_skipped SHAREDBSS_ATTR;
63 /* TODO: Check if 4KB is appropriate - it works for my test streams,
64 so maybe we can reduce it. */
65 #define VIDEO_STACKSIZE (4*1024)
66 static uint32_t video_stack[VIDEO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR;
67 static struct event_queue video_str_queue SHAREDBSS_ATTR;
68 static struct queue_sender_list video_str_queue_send SHAREDBSS_ATTR;
69 struct stream video_str IBSS_ATTR;
71 #define DEFAULT_GOP_SIZE INT_MAX /* no I/P skips until it learns */
72 #define DROP_THRESHOLD (100*TS_SECOND/1000)
73 #define MAX_EARLINESS (120*TS_SECOND/1000)
75 #if defined(DEBUG) || defined(SIMULATOR)
76 static unsigned char pic_coding_type_char(unsigned type)
78 switch (type)
80 case PIC_FLAG_CODING_TYPE_I:
81 return 'I'; /* Intra-coded */
82 case PIC_FLAG_CODING_TYPE_P:
83 return 'P'; /* Forward-predicted */
84 case PIC_FLAG_CODING_TYPE_B:
85 return 'B'; /* Bidirectionally-predicted */
86 case PIC_FLAG_CODING_TYPE_D:
87 return 'D'; /* DC-coded */
88 default:
89 return '?'; /* Say what? */
92 #endif /* defined(DEBUG) || defined(SIMULATOR) */
94 /* Multi-use:
95 * 1) Find the sequence header and initialize video out
96 * 2) Find the end of the final frame
98 static int video_str_scan(struct video_thread_data *td,
99 struct str_sync_data *sd)
101 int retval = STREAM_ERROR;
102 uint32_t time = INVALID_TIMESTAMP;
103 uint32_t period = 0;
104 struct stream tmp_str;
106 tmp_str.id = video_str.id;
107 tmp_str.hdr.pos = sd->sk.pos;
108 tmp_str.hdr.limit = sd->sk.pos + sd->sk.len;
110 /* Fully reset if obtaining size for a new stream */
111 mpeg2_reset(td->mpeg2dec, td->ev.id == VIDEO_GET_SIZE);
112 mpeg2_skip(td->mpeg2dec, 1);
114 while (1)
116 mpeg2_state_t mp2state = mpeg2_parse(td->mpeg2dec);
117 rb->yield();
119 switch (mp2state)
121 case STATE_BUFFER:
122 switch (parser_get_next_data(&tmp_str, STREAM_PM_RANDOM_ACCESS))
124 case STREAM_DATA_END:
125 DEBUGF("video_stream_scan:STREAM_DATA_END\n");
126 goto scan_finished;
128 case STREAM_OK:
129 if (tmp_str.pkt_flags & PKT_HAS_TS)
130 mpeg2_tag_picture(td->mpeg2dec, tmp_str.pts, 0);
132 mpeg2_buffer(td->mpeg2dec, tmp_str.curr_packet,
133 tmp_str.curr_packet_end);
134 td->info = mpeg2_info(td->mpeg2dec);
135 break;
137 break;
139 case STATE_SEQUENCE:
140 DEBUGF("video_stream_scan:STATE_SEQUENCE\n");
141 vo_setup(td->info->sequence);
143 if (td->ev.id == VIDEO_GET_SIZE)
145 retval = STREAM_OK;
146 goto scan_finished;
148 break;
150 case STATE_SLICE:
151 case STATE_END:
152 case STATE_INVALID_END:
154 if (td->info->display_picture == NULL)
155 break;
157 switch (td->ev.id)
159 case STREAM_SYNC:
160 retval = STREAM_OK;
161 goto scan_finished;
163 case STREAM_FIND_END_TIME:
164 if (td->info->display_picture->flags & PIC_FLAG_TAGS)
165 time = td->info->display_picture->tag;
166 else if (time != INVALID_TIMESTAMP)
167 time += period;
169 period = TC_TO_TS(td->info->sequence->frame_period);
170 break;
173 break;
176 default:
177 break;
181 scan_finished:
183 if (td->ev.id == STREAM_FIND_END_TIME)
185 if (time != INVALID_TIMESTAMP)
187 sd->time = time + period;
188 retval = STREAM_PERFECT_MATCH;
190 else
192 retval = STREAM_NOT_FOUND;
196 mpeg2_skip(td->mpeg2dec, 0);
197 return retval;
200 static bool init_sequence(struct video_thread_data *td)
202 struct str_sync_data sd;
204 sd.time = 0; /* Ignored */
205 sd.sk.pos = 0;
206 sd.sk.len = 1024*1024;
207 sd.sk.dir = SSCAN_FORWARD;
209 return video_str_scan(td, &sd) == STREAM_OK;
212 static bool check_needs_sync(struct video_thread_data *td, uint32_t time)
214 uint32_t end_time;
216 DEBUGF("check_needs_sync:\n");
217 if (td->info == NULL || td->info->display_fbuf == NULL)
219 DEBUGF(" no fbuf\n");
220 return true;
223 if (td->syncf_perfect == 0)
225 DEBUGF(" no frame\n");
226 return true;
229 time = clip_time(&video_str, time);
230 end_time = td->frame_time + td->frame_period;
232 DEBUGF(" sft:%u t:%u sfte:%u\n", (unsigned)td->frame_time,
233 (unsigned)time, (unsigned)end_time);
235 if (time < td->frame_time)
236 return true;
238 if (time >= end_time)
239 return time < video_str.end_pts || end_time < video_str.end_pts;
241 return false;
244 /* Do any needed decoding/slide up to the specified time */
245 static int sync_decoder(struct video_thread_data *td,
246 struct str_sync_data *sd)
248 int retval = STREAM_ERROR;
249 uint32_t time = clip_time(&video_str, sd->time);
251 td->syncf_perfect = 0;
252 td->frame_time = 0;
253 td->frame_period = 0;
254 td->num_ref_pics = 0;
256 /* Sometimes theres no sequence headers nearby and libmpeg2 may have reset
257 * fully at some point */
258 if ((td->info == NULL || td->info->sequence == NULL) && !init_sequence(td))
260 DEBUGF("sync_decoder=>init_sequence failed\n");
261 goto sync_finished;
264 video_str.hdr.pos = sd->sk.pos;
265 video_str.hdr.limit = sd->sk.pos + sd->sk.len;
266 mpeg2_reset(td->mpeg2dec, false);
267 mpeg2_skip(td->mpeg2dec, 1);
269 while (1)
271 mpeg2_state_t mp2state = mpeg2_parse(td->mpeg2dec);
273 switch (mp2state)
275 case STATE_BUFFER:
276 switch (parser_get_next_data(&video_str, STREAM_PM_RANDOM_ACCESS))
278 case STREAM_DATA_END:
279 DEBUGF("sync_decoder:STR_DATA_END\n");
280 if (td->info && td->info->display_picture &&
281 !(td->info->display_picture->flags & PIC_FLAG_SKIP))
283 /* No frame matching the time was found up to the end of
284 * the stream - consider a perfect match since no better
285 * can be made */
286 retval = STREAM_PERFECT_MATCH;
287 td->syncf_perfect = 1;
289 goto sync_finished;
291 case STREAM_OK:
292 if (video_str.pkt_flags & PKT_HAS_TS)
293 mpeg2_tag_picture(td->mpeg2dec, video_str.pts, 0);
294 mpeg2_buffer(td->mpeg2dec, video_str.curr_packet,
295 video_str.curr_packet_end);
296 td->info = mpeg2_info(td->mpeg2dec);
297 break;
299 break;
301 case STATE_SEQUENCE:
302 DEBUGF(" STATE_SEQUENCE\n");
303 vo_setup(td->info->sequence);
304 break;
306 case STATE_GOP:
307 DEBUGF(" STATE_GOP: (%s)\n",
308 (td->info->gop->flags & GOP_FLAG_CLOSED_GOP) ?
309 "closed" : "open");
310 break;
312 case STATE_PICTURE:
314 int type = td->info->current_picture->flags
315 & PIC_MASK_CODING_TYPE;
317 switch (type)
319 case PIC_FLAG_CODING_TYPE_I:
320 /* I-frame; start decoding */
321 mpeg2_skip(td->mpeg2dec, 0);
322 td->num_ref_pics++;
323 break;
325 case PIC_FLAG_CODING_TYPE_P:
326 /* P-frames don't count without I-frames */
327 if (td->num_ref_pics > 0)
328 td->num_ref_pics++;
329 break;
332 if (td->info->current_picture->flags & PIC_FLAG_TAGS)
334 DEBUGF(" STATE_PICTURE (%c): %u\n", pic_coding_type_char(type),
335 (unsigned)td->info->current_picture->tag);
337 else
339 DEBUGF(" STATE_PICTURE (%c): -\n", pic_coding_type_char(type));
342 break;
345 case STATE_SLICE:
346 case STATE_END:
347 case STATE_INVALID_END:
349 uint32_t end_time;
351 if (td->info->display_picture == NULL)
353 DEBUGF(" td->info->display_picture == NULL\n");
354 break; /* No picture */
357 int type = td->info->display_picture->flags
358 & PIC_MASK_CODING_TYPE;
360 if (td->info->display_picture->flags & PIC_FLAG_TAGS)
362 td->frame_time = td->info->display_picture->tag;
363 DEBUGF(" frame tagged:%u (%c%s)\n", (unsigned)td->frame_time,
364 pic_coding_type_char(type),
365 (td->info->display_picture->flags & PIC_FLAG_SKIP) ?
366 " skipped" : "");
368 else
370 td->frame_time += td->frame_period;
371 DEBUGF(" add frame_period:%u (%c%s)\n", (unsigned)td->frame_time,
372 pic_coding_type_char(type),
373 (td->info->display_picture->flags & PIC_FLAG_SKIP) ?
374 " skipped" : "");
377 td->frame_period = TC_TO_TS(td->info->sequence->frame_period);
378 end_time = td->frame_time + td->frame_period;
380 DEBUGF(" ft:%u t:%u fe:%u (%c%s)",
381 (unsigned)td->frame_time,
382 (unsigned)time,
383 (unsigned)end_time,
384 pic_coding_type_char(type),
385 (td->info->display_picture->flags & PIC_FLAG_SKIP) ?
386 " skipped" : "");
388 if (end_time <= time && end_time < video_str.end_pts)
390 /* Still too early and have not hit at EOS */
391 DEBUGF(" too early\n");
392 break;
394 else if (!(td->info->display_picture->flags & PIC_FLAG_SKIP))
396 /* One perfect point if dependent frames were decoded */
397 switch (type)
399 case PIC_FLAG_CODING_TYPE_B:
400 if (td->num_ref_pics > 1)
402 case PIC_FLAG_CODING_TYPE_P:
403 if (td->num_ref_pics > 0)
405 case PIC_FLAG_CODING_TYPE_I:
406 td->syncf_perfect = 1;
407 break;
412 if ((td->frame_time <= time && time < end_time) ||
413 end_time >= video_str.end_pts)
415 /* One perfect point for matching time goal */
416 DEBUGF(" ft<=t<fe\n");
417 td->syncf_perfect++;
419 else
421 DEBUGF(" ft>t\n");
424 /* Two or more perfect points = perfect match - yay! */
425 retval = (td->syncf_perfect >= 2) ?
426 STREAM_PERFECT_MATCH : STREAM_MATCH;
428 else
430 /* Too late, no I-Frame yet */
431 DEBUGF("\n");
434 goto sync_finished;
437 default:
438 break;
441 rb->yield();
442 } /* end while */
444 sync_finished:
445 mpeg2_skip(td->mpeg2dec, 0);
446 return retval;
449 static bool frame_print_handler(struct video_thread_data *td)
451 bool retval;
452 uint8_t * const * buf = NULL;
454 if (td->info != NULL && td->info->display_fbuf != NULL &&
455 td->syncf_perfect > 0)
456 buf = td->info->display_fbuf->buf;
458 if (td->ev.id == VIDEO_PRINT_THUMBNAIL)
460 /* Print a thumbnail of whatever was last decoded - scale and
461 * position to fill the specified rectangle */
462 retval = vo_draw_frame_thumb(buf, (struct vo_rect *)td->ev.data);
464 else
466 /* Print the last frame decoded */
467 vo_draw_frame(buf);
468 retval = buf != NULL;
471 return retval;
474 /* This only returns to play or quit */
475 static void video_thread_msg(struct video_thread_data *td)
477 while (1)
479 intptr_t reply = 0;
481 switch (td->ev.id)
483 case STREAM_PLAY:
484 td->status = STREAM_PLAYING;
486 switch (td->state)
488 case TSTATE_INIT:
489 /* Begin decoding state */
490 td->state = TSTATE_DECODE;
491 /* */
492 case TSTATE_DECODE:
493 if (td->syncf_perfect <= 0)
494 break;
495 /* There should be a frame already, just draw it */
496 td->goal_time = td->frame_time;
497 td->state = TSTATE_RENDER_WAIT;
498 /* */
499 case TSTATE_RENDER_WAIT:
500 /* Settings may have changed to nonlimited - just draw
501 * what was previously being waited for */
502 td->stream_time = TICKS_TO_TS(stream_get_time());
503 if (!settings.limitfps)
504 td->state = TSTATE_RENDER;
505 /* */
506 case TSTATE_RENDER:
507 break;
509 case TSTATE_EOS:
510 /* At end of stream - no playback possible so fire the
511 * completion event */
512 stream_generate_event(&video_str, STREAM_EV_COMPLETE, 0);
513 break;
516 reply = td->state != TSTATE_EOS;
517 break;
519 case STREAM_PAUSE:
520 td->status = STREAM_PAUSED;
521 reply = td->state != TSTATE_EOS;
522 break;
524 case STREAM_STOP:
525 if (td->state == TSTATE_DATA)
526 stream_clear_notify(&video_str, DISK_BUF_DATA_NOTIFY);
528 td->status = STREAM_STOPPED;
529 td->state = TSTATE_EOS;
530 reply = true;
531 break;
533 case VIDEO_DISPLAY_IS_VISIBLE:
534 reply = vo_is_visible();
535 break;
537 case VIDEO_DISPLAY_SHOW:
538 /* Show video and draw the last frame we had if any or reveal the
539 * underlying framebuffer if hiding */
540 reply = vo_show(!!td->ev.data);
542 #ifdef HAVE_LCD_COLOR
543 /* Match graylib behavior as much as possible */
544 if (!td->ev.data == !reply)
545 break;
547 if (td->ev.data)
549 frame_print_handler(td);
551 else
553 IF_COP(rb->cpucache_invalidate());
554 vo_lock();
555 rb->lcd_update();
556 vo_unlock();
558 #endif
559 break;
561 case STREAM_RESET:
562 if (td->state == TSTATE_DATA)
563 stream_clear_notify(&video_str, DISK_BUF_DATA_NOTIFY);
565 td->state = TSTATE_INIT;
566 td->status = STREAM_STOPPED;
568 /* Reset operational info but not sync info */
569 td->stream_time = UINT32_MAX;
570 td->goal_time = 0;
571 td->remain_time = 0;
572 td->skip_ref_pics = 0;
573 td->skip_level = 0;
574 td->num_picture = 0;
575 td->num_intra = 0;
576 td->group_est = DEFAULT_GOP_SIZE;
577 td->last_render = *rb->current_tick - HZ;
578 video_num_drawn = 0;
579 video_num_skipped = 0;
581 reply = true;
582 break;
584 case STREAM_NEEDS_SYNC:
585 reply = check_needs_sync(td, td->ev.data);
586 break;
588 case STREAM_SYNC:
589 if (td->state == TSTATE_INIT)
590 reply = sync_decoder(td, (struct str_sync_data *)td->ev.data);
591 break;
593 case DISK_BUF_DATA_NOTIFY:
594 /* Our bun is done */
595 if (td->state != TSTATE_DATA)
596 break;
598 td->state = TSTATE_DECODE;
599 str_data_notify_received(&video_str);
600 break;
602 case VIDEO_PRINT_FRAME:
603 case VIDEO_PRINT_THUMBNAIL:
604 reply = frame_print_handler(td);
605 break;
607 case VIDEO_SET_CLIP_RECT:
608 vo_set_clip_rect((const struct vo_rect *)td->ev.data);
609 break;
611 case VIDEO_GET_CLIP_RECT:
612 reply = vo_get_clip_rect((struct vo_rect *)td->ev.data);
613 break;
615 case VIDEO_GET_SIZE:
617 if (td->state != TSTATE_INIT)
618 break; /* Can only use after a reset was issued */
620 /* This will reset the decoder in full for this particular event */
621 if (init_sequence(td))
623 reply = true;
624 vo_dimensions((struct vo_ext *)td->ev.data);
626 break;
629 case STREAM_FIND_END_TIME:
630 if (td->state != TSTATE_INIT)
632 reply = STREAM_ERROR;
633 break;
636 reply = video_str_scan(td, (struct str_sync_data *)td->ev.data);
637 break;
639 case VIDEO_SET_POST_FRAME_CALLBACK:
640 vo_set_post_draw_callback((void (*)(void))td->ev.data);
641 reply = true;
642 break;
644 case STREAM_QUIT:
645 /* Time to go - make thread exit */
646 td->state = TSTATE_EOS;
647 return;
650 str_reply_msg(&video_str, reply);
652 if (td->status == STREAM_PLAYING)
654 switch (td->state)
656 case TSTATE_DECODE:
657 case TSTATE_RENDER:
658 case TSTATE_RENDER_WAIT:
659 /* These return when in playing state */
660 return;
664 str_get_msg(&video_str, &td->ev);
668 static void video_thread(void)
670 struct video_thread_data td;
672 memset(&td, 0, sizeof (td));
673 td.mpeg2dec = mpeg2_init();
674 td.status = STREAM_STOPPED;
675 td.state = TSTATE_EOS;
677 if (td.mpeg2dec == NULL)
679 td.status = STREAM_ERROR;
680 /* Loop and wait for quit message */
681 while (1)
683 str_get_msg(&video_str, &td.ev);
684 if (td.ev.id == STREAM_QUIT)
685 return;
686 str_reply_msg(&video_str, STREAM_ERROR);
690 vo_init();
692 goto message_wait;
694 while (1)
696 mpeg2_state_t mp2state;
697 td.state = TSTATE_DECODE;
699 /* Check for any pending messages and process them */
700 if (str_have_msg(&video_str))
702 message_wait:
703 /* Wait for a message to be queued */
704 str_get_msg(&video_str, &td.ev);
706 message_process:
707 /* Process a message already dequeued */
708 video_thread_msg(&td);
710 switch (td.state)
712 /* These states are the only ones that should return */
713 case TSTATE_DECODE: goto picture_decode;
714 case TSTATE_RENDER: goto picture_draw;
715 case TSTATE_RENDER_WAIT: goto picture_wait;
716 /* Anything else is interpreted as an exit */
717 default: goto video_exit;
721 picture_decode:
722 mp2state = mpeg2_parse (td.mpeg2dec);
724 switch (mp2state)
726 case STATE_BUFFER:
727 /* Request next packet data */
728 switch (parser_get_next_data(&video_str, STREAM_PM_STREAMING))
730 case STREAM_DATA_NOT_READY:
731 /* Wait for data to be buffered */
732 td.state = TSTATE_DATA;
733 goto message_wait;
735 case STREAM_DATA_END:
736 /* No more data. */
737 td.state = TSTATE_EOS;
738 if (td.status == STREAM_PLAYING)
739 stream_generate_event(&video_str, STREAM_EV_COMPLETE, 0);
740 goto message_wait;
742 case STREAM_OK:
743 if (video_str.pkt_flags & PKT_HAS_TS)
744 mpeg2_tag_picture(td.mpeg2dec, video_str.pts, 0);
746 mpeg2_buffer(td.mpeg2dec, video_str.curr_packet,
747 video_str.curr_packet_end);
748 td.info = mpeg2_info(td.mpeg2dec);
749 break;
751 break;
753 case STATE_SEQUENCE:
754 /* New video sequence, inform output of any changes */
755 vo_setup(td.info->sequence);
756 break;
758 case STATE_PICTURE:
760 /* This is not in presentation order - do our best anyway */
761 int skip = td.skip_ref_pics;
763 /* Frame type: I/P/B/D */
764 switch (td.info->current_picture->flags & PIC_MASK_CODING_TYPE)
766 case PIC_FLAG_CODING_TYPE_I:
767 if (++td.num_intra >= 2)
768 td.group_est = td.num_picture / (td.num_intra - 1);
770 /* Things are extremely late and all frames will be
771 dropped until the next key frame */
772 if (td.skip_level > 0 && td.skip_level >= td.group_est)
774 td.skip_level--; /* skip frame */
775 skip = td.skip_ref_pics = 1; /* wait for I-frame */
776 td.num_ref_pics = 0;
778 else if (skip != 0)
780 skip = td.skip_ref_pics = 0; /* now, decode */
781 td.num_ref_pics = 1;
783 break;
785 case PIC_FLAG_CODING_TYPE_P:
786 if (skip == 0)
788 td.num_ref_pics++;
790 /* If skip_level at least the estimated number of frames
791 left in I-I span, skip until next I-frame */
792 if (td.group_est > 0 && td.skip_level >= td.group_est)
794 skip = td.skip_ref_pics = 1; /* wait for I-frame */
795 td.num_ref_pics = 0;
799 if (skip != 0)
800 td.skip_level--;
801 break;
803 case PIC_FLAG_CODING_TYPE_B:
804 /* We want to drop something, so this B-frame won't even be
805 decoded. Drawing can happen on the next frame if so desired
806 so long as the B-frames were not dependent upon those from
807 a previous open GOP where the needed reference frames were
808 skipped */
809 if (td.skip_level > 0 || td.num_ref_pics < 2)
811 skip = 1;
812 td.skip_level--;
814 break;
816 default:
817 skip = 1;
818 break;
821 if (td.num_intra > 0)
822 td.num_picture++;
824 td.group_est--;
826 mpeg2_skip(td.mpeg2dec, skip);
827 break;
830 case STATE_SLICE:
831 case STATE_END:
832 case STATE_INVALID_END:
834 int32_t offset; /* Tick adjustment to keep sync */
836 if (td.info->display_fbuf == NULL)
837 break; /* No picture */
839 /* Get presentation times in audio samples - quite accurate
840 enough - add previous frame duration if not stamped */
841 if (td.info->display_picture->flags & PIC_FLAG_TAGS)
842 td.frame_time = td.info->display_picture->tag;
843 else
844 td.frame_time += td.frame_period;
846 td.frame_period = TC_TO_TS(td.info->sequence->frame_period);
848 if (!settings.limitfps)
850 /* No limiting => no dropping or waiting - draw this frame */
851 td.remain_time = 0;
852 td.skip_level = 0;
853 td.syncf_perfect = 1; /* have frame */
854 goto picture_draw;
857 td.goal_time = td.frame_time;
858 td.stream_time = TICKS_TO_TS(stream_get_time());
860 /* How early/late are we? > 0 = late, < 0 early */
861 offset = td.stream_time - td.goal_time;
863 if (offset >= 0)
865 /* Late or on-time */
866 if (td.remain_time < 0)
867 td.remain_time = 0; /* now, late */
869 offset = AVERAGE(td.remain_time, offset, 4);
870 td.remain_time = offset;
872 else
874 /* Early */
875 if (td.remain_time >= 0)
876 td.remain_time = 0; /* now, early */
877 else if (offset > td.remain_time)
878 td.remain_time = MAX(offset, -MAX_EARLINESS); /* less early */
879 else if (td.remain_time != 0)
880 td.remain_time = AVERAGE(td.remain_time, 0, 8); /* earlier/same */
881 /* else there's been no frame drop */
883 offset = -td.remain_time;
886 /* Skip anything not decoded */
887 if (td.info->display_picture->flags & PIC_FLAG_SKIP)
888 goto picture_skip;
890 td.syncf_perfect = 1; /* have frame (assume so from now on) */
892 /* Keep goal_time >= 0 */
893 if ((uint32_t)offset > td.goal_time)
894 offset = td.goal_time;
896 td.goal_time -= offset;
898 if (!settings.skipframes)
900 /* No skipping - just wait if we're early and correct for
901 lateness as much as possible. */
902 td.skip_level = 0;
903 goto picture_wait;
906 /** Possibly skip this frame **/
908 /* Frameskipping has the following order of preference:
910 * Frame Type Who Notes/Rationale
911 * B decoder arbitrarily drop - no decode or draw
912 * Any renderer arbitrarily drop - I/P unless B decoded
913 * P decoder must wait for I-frame
914 * I decoder must wait for I-frame
916 * If a frame can be drawn and it has been at least 1/2 second,
917 * the image will be updated no matter how late it is just to
918 * avoid looking stuck.
920 if (td.skip_level > 0 &&
921 TIME_BEFORE(*rb->current_tick, td.last_render + HZ/2))
923 /* Frame skip was set previously but either there wasn't anything
924 dropped yet or not dropped enough. So we quit at least rendering
925 the actual frame to avoid further increase of a/v-drift. */
926 td.skip_level--;
927 goto picture_skip;
930 /* At this point a frame _will_ be drawn - a skip may happen on
931 the next however */
933 /* Calculate number of frames to drop/skip - allow brief periods
934 of lateness before producing skips */
935 td.skip_level = 0;
936 if (td.remain_time > 0 && (uint32_t)offset > DROP_THRESHOLD)
938 td.skip_level = (offset - DROP_THRESHOLD + td.frame_period)
939 / td.frame_period;
942 picture_wait:
943 td.state = TSTATE_RENDER_WAIT;
945 /* Wait until time catches up */
946 while (1)
948 int32_t twait = td.goal_time - td.stream_time;
949 /* Watch for messages while waiting for the frame time */
951 if (twait <= 0)
952 break;
954 if (twait > TS_SECOND/HZ)
956 /* Several ticks to wait - do some sleeping */
957 int timeout = (twait - HZ) / (TS_SECOND/HZ);
958 str_get_msg_w_tmo(&video_str, &td.ev, MAX(timeout, 1));
959 if (td.ev.id != SYS_TIMEOUT)
960 goto message_process;
962 else
964 /* Just a little left - spin and be accurate */
965 rb->yield();
966 if (str_have_msg(&video_str))
967 goto message_wait;
970 td.stream_time = TICKS_TO_TS(stream_get_time());
973 picture_draw:
974 /* Record last frame time */
975 td.last_render = *rb->current_tick;
977 vo_draw_frame(td.info->display_fbuf->buf);
978 video_num_drawn++;
979 break;
981 picture_skip:
982 if (td.remain_time <= DROP_THRESHOLD)
984 td.skip_level = 0;
985 if (td.remain_time <= 0)
986 td.remain_time = INT32_MIN;
989 video_num_skipped++;
990 break;
993 default:
994 break;
997 rb->yield();
998 } /* end while */
1000 video_exit:
1001 vo_cleanup();
1002 mpeg2_close(td.mpeg2dec);
1005 /* Initializes the video thread */
1006 bool video_thread_init(void)
1008 intptr_t rep;
1010 IF_COP(rb->cpucache_flush());
1012 video_str.hdr.q = &video_str_queue;
1013 rb->queue_init(video_str.hdr.q, false);
1015 /* We put the video thread on another processor for multi-core targets. */
1016 video_str.thread = rb->create_thread(
1017 video_thread, video_stack, VIDEO_STACKSIZE, 0,
1018 "mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK) IF_COP(, COP));
1020 rb->queue_enable_queue_send(video_str.hdr.q, &video_str_queue_send,
1021 video_str.thread);
1023 if (video_str.thread == 0)
1024 return false;
1026 /* Wait for thread to initialize */
1027 rep = str_send_msg(&video_str, STREAM_NULL, 0);
1028 IF_COP(rb->cpucache_invalidate());
1030 return rep == 0; /* Normally STREAM_NULL should be ignored */
1033 /* Terminates the video thread */
1034 void video_thread_exit(void)
1036 if (video_str.thread != 0)
1038 str_post_msg(&video_str, STREAM_QUIT, 0);
1039 rb->thread_wait(video_str.thread);
1040 IF_COP(rb->cpucache_invalidate());
1041 video_str.thread = 0;
1046 /** Misc **/
1047 void video_thread_get_stats(struct video_output_stats *s)
1049 uint32_t start;
1050 uint32_t now = stream_get_ticks(&start);
1051 s->num_drawn = video_num_drawn;
1052 s->num_skipped = video_num_skipped;
1054 s->fps = 0;
1056 if (now > start)
1057 s->fps = muldiv_uint32(CLOCK_RATE*100, s->num_drawn, now - start);