mpegplayer: Use the core DSP to process audio. Removes the sample rate restriction...
[kugel-rb.git] / apps / plugins / mpegplayer / video_thread.c
blob6508d28d1d4758379eb82b2f6eca4bc0104a46c1
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 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "plugin.h"
22 #include "mpegplayer.h"
23 #include "mpeg2dec_config.h"
24 #include "grey.h"
25 #include "video_out.h"
26 #include "mpeg_settings.h"
28 /** Video stream and thread **/
30 /* Video thread data passed around to its various functions */
31 struct video_thread_data
33 mpeg2dec_t *mpeg2dec; /* Our video decoder */
34 const mpeg2_info_t *info; /* Info about video stream */
35 int state; /* Thread state */
36 int status; /* Media status */
37 struct queue_event ev; /* Our event queue to receive commands */
38 int num_drawn; /* Number of frames drawn since reset */
39 int num_skipped; /* Number of frames skipped since reset */
40 uint32_t eta_stream; /* Current time of stream */
41 uint32_t eta_video; /* Time that frame has been scheduled for */
42 int32_t eta_early; /* How early has the frame been decoded? */
43 int32_t eta_late; /* How late has the frame been decoded? */
44 int frame_drop_level; /* Drop severity */
45 int skip_level; /* Skip severity */
46 long last_showfps; /* Last time the FPS display was updated */
47 long last_render; /* Last time a frame was drawn */
48 uint32_t curr_time; /* Current due time of frame */
49 uint32_t period; /* Frame period in clock ticks */
50 int syncf_perfect; /* Last sync fit result */
53 /* TODO: Check if 4KB is appropriate - it works for my test streams,
54 so maybe we can reduce it. */
55 #define VIDEO_STACKSIZE (4*1024)
56 static uint32_t video_stack[VIDEO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR;
57 static struct event_queue video_str_queue NOCACHEBSS_ATTR;
58 static struct queue_sender_list video_str_queue_send NOCACHEBSS_ATTR;
59 struct stream video_str IBSS_ATTR;
61 static void draw_fps(struct video_thread_data *td)
63 uint32_t start;
64 uint32_t clock_ticks = stream_get_ticks(&start);
65 int fps = 0;
66 int buf_pct;
67 char str[80];
69 clock_ticks -= start;
70 if (clock_ticks != 0)
71 fps = muldiv_uint32(CLOCK_RATE*100, td->num_drawn, clock_ticks);
73 buf_pct = muldiv_uint32(100, pcm_output_used(), PCMOUT_BUFSIZE);
75 rb->snprintf(str, sizeof(str), "v:%d.%02d %d %d a:%02d%% %d %d ",
76 /* Video information */
77 fps / 100, fps % 100, td->num_skipped,
78 td->info->display_picture->temporal_reference,
79 /* Audio information */
80 buf_pct, pcm_underruns, pcm_skipped);
81 lcd_(putsxy)(0, 0, str);
83 vo_lock();
84 lcd_(update_rect)(0, 0, LCD_WIDTH, 8);
85 vo_unlock();
87 td->last_showfps = *rb->current_tick;
90 #if defined(DEBUG) || defined(SIMULATOR)
91 static unsigned char pic_coding_type_char(unsigned type)
93 switch (type)
95 case PIC_FLAG_CODING_TYPE_I:
96 return 'I'; /* Intra-coded */
97 case PIC_FLAG_CODING_TYPE_P:
98 return 'P'; /* Forward-predicted */
99 case PIC_FLAG_CODING_TYPE_B:
100 return 'B'; /* Bidirectionally-predicted */
101 case PIC_FLAG_CODING_TYPE_D:
102 return 'D'; /* DC-coded */
103 default:
104 return '?'; /* Say what? */
107 #endif /* defined(DEBUG) || defined(SIMULATOR) */
109 /* Multi-use:
110 * 1) Find the sequence header and initialize video out
111 * 2) Find the end of the final frame
113 static int video_str_scan(struct video_thread_data *td,
114 struct str_sync_data *sd)
116 int retval = STREAM_ERROR;
117 uint32_t time = INVALID_TIMESTAMP;
118 uint32_t period = 0;
119 struct stream tmp_str;
121 tmp_str.id = video_str.id;
122 tmp_str.hdr.pos = sd->sk.pos;
123 tmp_str.hdr.limit = sd->sk.pos + sd->sk.len;
125 mpeg2_reset(td->mpeg2dec, false);
126 mpeg2_skip(td->mpeg2dec, 1);
128 while (1)
130 mpeg2_state_t mp2state = mpeg2_parse(td->mpeg2dec);
131 rb->yield();
133 switch (mp2state)
135 case STATE_BUFFER:
136 switch (parser_get_next_data(&tmp_str, STREAM_PM_RANDOM_ACCESS))
138 case STREAM_DATA_END:
139 DEBUGF("video_stream_scan:STREAM_DATA_END\n");
140 goto scan_finished;
142 case STREAM_OK:
143 if (tmp_str.pkt_flags & PKT_HAS_TS)
144 mpeg2_tag_picture(td->mpeg2dec, tmp_str.pts, 0);
146 mpeg2_buffer(td->mpeg2dec, tmp_str.curr_packet,
147 tmp_str.curr_packet_end);
148 td->info = mpeg2_info(td->mpeg2dec);
149 break;
151 break;
153 case STATE_SEQUENCE:
154 DEBUGF("video_stream_scan:STATE_SEQUENCE\n");
155 vo_setup(td->info->sequence);
157 if (td->ev.id == VIDEO_GET_SIZE)
159 retval = STREAM_OK;
160 goto scan_finished;
162 break;
164 case STATE_SLICE:
165 case STATE_END:
166 case STATE_INVALID_END:
168 if (td->info->display_picture == NULL)
169 break;
171 switch (td->ev.id)
173 case STREAM_SYNC:
174 retval = STREAM_OK;
175 goto scan_finished;
177 case STREAM_FIND_END_TIME:
178 if (td->info->display_picture->flags & PIC_FLAG_TAGS)
179 time = td->info->display_picture->tag;
180 else if (time != INVALID_TIMESTAMP)
181 time += period;
183 period = TC_TO_TS(td->info->sequence->frame_period);
184 break;
187 break;
190 default:
191 break;
195 scan_finished:
197 if (td->ev.id == STREAM_FIND_END_TIME)
199 if (time != INVALID_TIMESTAMP)
201 sd->time = time + period;
202 retval = STREAM_PERFECT_MATCH;
204 else
206 retval = STREAM_NOT_FOUND;
210 mpeg2_skip(td->mpeg2dec, 0);
211 return retval;
214 static bool init_sequence(struct video_thread_data *td)
216 struct str_sync_data sd;
218 sd.time = 0; /* Ignored */
219 sd.sk.pos = 0;
220 sd.sk.len = 1024*1024;
221 sd.sk.dir = SSCAN_FORWARD;
223 return video_str_scan(td, &sd) == STREAM_OK;
226 static bool check_needs_sync(struct video_thread_data *td, uint32_t time)
228 uint32_t end_time;
230 DEBUGF("check_needs_sync:\n");
231 if (td->info == NULL || td->info->display_fbuf == NULL)
233 DEBUGF(" no fbuf\n");
234 return true;
237 if (td->syncf_perfect == 0)
239 DEBUGF(" no frame\n");
240 return true;
243 time = clip_time(&video_str, time);
244 end_time = td->curr_time + td->period;
246 DEBUGF(" sft:%u t:%u sfte:%u\n", (unsigned)td->curr_time,
247 (unsigned)time, (unsigned)end_time);
249 if (time < td->curr_time)
250 return true;
252 if (time >= end_time)
253 return time < video_str.end_pts || end_time < video_str.end_pts;
255 return false;
258 /* Do any needed decoding/slide up to the specified time */
259 static int sync_decoder(struct video_thread_data *td,
260 struct str_sync_data *sd)
262 int retval = STREAM_ERROR;
263 int ipic = 0, ppic = 0;
264 uint32_t time = clip_time(&video_str, sd->time);
266 td->syncf_perfect = 0;
267 td->curr_time = 0;
268 td->period = 0;
270 /* Sometimes theres no sequence headers nearby and libmpeg2 may have reset
271 * fully at some point */
272 if ((td->info == NULL || td->info->sequence == NULL) && !init_sequence(td))
274 DEBUGF("sync_decoder=>init_sequence failed\n");
275 goto sync_finished;
278 video_str.hdr.pos = sd->sk.pos;
279 video_str.hdr.limit = sd->sk.pos + sd->sk.len;
280 mpeg2_reset(td->mpeg2dec, false);
281 mpeg2_skip(td->mpeg2dec, 1);
283 while (1)
285 mpeg2_state_t mp2state = mpeg2_parse(td->mpeg2dec);
287 switch (mp2state)
289 case STATE_BUFFER:
290 switch (parser_get_next_data(&video_str, STREAM_PM_RANDOM_ACCESS))
292 case STREAM_DATA_END:
293 DEBUGF("sync_decoder:STR_DATA_END\n");
294 if (td->info && td->info->display_picture &&
295 !(td->info->display_picture->flags & PIC_FLAG_SKIP))
297 /* No frame matching the time was found up to the end of
298 * the stream - consider a perfect match since no better
299 * can be made */
300 retval = STREAM_PERFECT_MATCH;
301 td->syncf_perfect = 1;
303 goto sync_finished;
305 case STREAM_OK:
306 if (video_str.pkt_flags & PKT_HAS_TS)
307 mpeg2_tag_picture(td->mpeg2dec, video_str.pts, 0);
309 mpeg2_buffer(td->mpeg2dec, video_str.curr_packet,
310 video_str.curr_packet_end);
311 td->info = mpeg2_info(td->mpeg2dec);
312 break;
314 break;
316 case STATE_SEQUENCE:
317 DEBUGF(" STATE_SEQUENCE\n");
318 vo_setup(td->info->sequence);
319 break;
321 case STATE_GOP:
322 DEBUGF(" STATE_GOP: (%s)\n",
323 (td->info->gop->flags & GOP_FLAG_CLOSED_GOP) ?
324 "closed" : "open");
325 break;
327 case STATE_PICTURE:
329 int type = td->info->current_picture->flags
330 & PIC_MASK_CODING_TYPE;
332 switch (type)
334 case PIC_FLAG_CODING_TYPE_I:
335 /* I-frame; start decoding */
336 mpeg2_skip(td->mpeg2dec, 0);
337 ipic = 1;
338 break;
339 case PIC_FLAG_CODING_TYPE_P:
340 /* P-frames don't count without I-frames */
341 ppic = ipic;
342 break;
345 if (td->info->current_picture->flags & PIC_FLAG_TAGS)
347 DEBUGF(" STATE_PICTURE (%c): %u\n", pic_coding_type_char(type),
348 (unsigned)td->info->current_picture->tag);
350 else
352 DEBUGF(" STATE_PICTURE (%c): -\n", pic_coding_type_char(type));
355 break;
358 case STATE_SLICE:
359 case STATE_END:
360 case STATE_INVALID_END:
362 uint32_t end_time;
364 if (td->info->display_picture == NULL)
366 DEBUGF(" td->info->display_picture == NULL\n");
367 break; /* No picture */
370 int type = td->info->display_picture->flags
371 & PIC_MASK_CODING_TYPE;
373 if (td->info->display_picture->flags & PIC_FLAG_TAGS)
375 td->curr_time = td->info->display_picture->tag;
376 DEBUGF(" frame tagged:%u (%c%s)\n", (unsigned)td->curr_time,
377 pic_coding_type_char(type),
378 (td->info->display_picture->flags & PIC_FLAG_SKIP) ?
379 " skipped" : "");
381 else
383 td->curr_time += td->period;
384 DEBUGF(" add period:%u (%c%s)\n", (unsigned)td->curr_time,
385 pic_coding_type_char(type),
386 (td->info->display_picture->flags & PIC_FLAG_SKIP) ?
387 " skipped" : "");
390 td->period = TC_TO_TS(td->info->sequence->frame_period);
391 end_time = td->curr_time + td->period;
393 DEBUGF(" ft:%u t:%u fe:%u (%c%s)",
394 (unsigned)td->curr_time,
395 (unsigned)time,
396 (unsigned)end_time,
397 pic_coding_type_char(type),
398 (td->info->display_picture->flags & PIC_FLAG_SKIP) ?
399 " skipped" : "");
401 if (end_time <= time && end_time < video_str.end_pts)
403 /* Still too early and have not hit at EOS */
404 DEBUGF(" too early\n");
405 break;
407 else if (!(td->info->display_picture->flags & PIC_FLAG_SKIP))
409 /* One perfect point if dependent frames were decoded */
410 td->syncf_perfect = ipic;
412 if (type == PIC_FLAG_CODING_TYPE_B)
413 td->syncf_perfect &= ppic;
415 if ((td->curr_time <= time && time < end_time) ||
416 end_time >= video_str.end_pts)
418 /* One perfect point for matching time goal */
419 DEBUGF(" ft<=t<fe\n");
420 td->syncf_perfect++;
422 else
424 DEBUGF(" ft>t\n");
427 /* Two or more perfect points = perfect match - yay! */
428 retval = (td->syncf_perfect >= 2) ?
429 STREAM_PERFECT_MATCH : STREAM_MATCH;
431 else
433 /* Too late, no I-Frame yet */
434 DEBUGF("\n");
437 goto sync_finished;
440 default:
441 break;
444 rb->yield();
445 } /* end while */
447 sync_finished:
448 mpeg2_skip(td->mpeg2dec, 0);
449 return retval;
452 /* This only returns to play or quit */
453 static void video_thread_msg(struct video_thread_data *td)
455 while (1)
457 intptr_t reply = 0;
459 switch (td->ev.id)
461 case STREAM_PLAY:
462 td->status = STREAM_PLAYING;
464 switch (td->state)
466 case TSTATE_RENDER_WAIT:
467 /* Settings may have changed to nonlimited - just draw
468 * what was previously being waited for */
469 if (!settings.limitfps)
470 td->state = TSTATE_RENDER;
471 case TSTATE_DECODE:
472 case TSTATE_RENDER:
473 break;
475 case TSTATE_INIT:
476 /* Begin decoding state */
477 td->state = TSTATE_DECODE;
478 break;
480 case TSTATE_EOS:
481 /* At end of stream - no playback possible so fire the
482 * completion event */
483 stream_generate_event(&video_str, STREAM_EV_COMPLETE, 0);
484 break;
487 reply = td->state != TSTATE_EOS;
488 break;
490 case STREAM_PAUSE:
491 td->status = STREAM_PAUSED;
492 reply = td->state != TSTATE_EOS;
493 break;
495 case STREAM_STOP:
496 if (td->state == TSTATE_DATA)
497 stream_clear_notify(&video_str, DISK_BUF_DATA_NOTIFY);
499 td->status = STREAM_STOPPED;
500 td->state = TSTATE_EOS;
501 reply = true;
502 break;
504 case VIDEO_DISPLAY_IS_VISIBLE:
505 reply = vo_is_visible();
506 break;
508 case VIDEO_DISPLAY_SHOW:
509 /* Show video and draw the last frame we had if any or reveal the
510 * underlying framebuffer if hiding */
511 reply = vo_show(!!td->ev.data);
513 #ifdef HAVE_LCD_COLOR
514 /* Match graylib behavior as much as possible */
515 if (!td->ev.data == !reply)
516 break;
518 if (td->ev.data)
520 if (td->info != NULL && td->info->display_fbuf != NULL)
521 vo_draw_frame(td->info->display_fbuf->buf);
523 else
525 IF_COP(invalidate_icache());
526 vo_lock();
527 rb->lcd_update();
528 vo_unlock();
530 #endif
531 break;
533 case STREAM_RESET:
534 if (td->state == TSTATE_DATA)
535 stream_clear_notify(&video_str, DISK_BUF_DATA_NOTIFY);
537 td->state = TSTATE_INIT;
538 td->status = STREAM_STOPPED;
540 /* Reset operational info but not sync info */
541 td->eta_stream = UINT32_MAX;
542 td->eta_video = 0;
543 td->eta_early = 0;
544 td->eta_late = 0;
545 td->frame_drop_level = 0;
546 td->skip_level = 0;
547 td->num_drawn = 0;
548 td->num_skipped = 0;
549 td->last_showfps = *rb->current_tick - HZ;
550 td->last_render = td->last_showfps;
552 reply = true;
553 break;
555 case STREAM_NEEDS_SYNC:
556 reply = check_needs_sync(td, td->ev.data);
557 break;
559 case STREAM_SYNC:
560 if (td->state == TSTATE_INIT)
561 reply = sync_decoder(td, (struct str_sync_data *)td->ev.data);
562 break;
564 case DISK_BUF_DATA_NOTIFY:
565 /* Our bun is done */
566 if (td->state != TSTATE_DATA)
567 break;
569 td->state = TSTATE_DECODE;
570 str_data_notify_received(&video_str);
571 break;
573 case VIDEO_PRINT_THUMBNAIL:
574 /* Print a thumbnail of whatever was last decoded - scale and
575 * position to fill the specified rectangle */
576 if (td->info != NULL && td->info->display_fbuf != NULL)
578 vo_draw_frame_thumb(td->info->display_fbuf->buf,
579 (struct vo_rect *)td->ev.data);
580 reply = true;
582 break;
584 case VIDEO_SET_CLIP_RECT:
585 vo_set_clip_rect((const struct vo_rect *)td->ev.data);
586 break;
588 case VIDEO_PRINT_FRAME:
589 /* Print the last frame decoded */
590 if (td->info != NULL && td->info->display_fbuf != NULL)
592 vo_draw_frame(td->info->display_fbuf->buf);
593 reply = true;
595 break;
597 case VIDEO_GET_SIZE:
599 if (td->state != TSTATE_INIT)
600 break;
602 if (init_sequence(td))
604 reply = true;
605 vo_dimensions((struct vo_ext *)td->ev.data);
607 break;
610 case STREAM_FIND_END_TIME:
611 if (td->state != TSTATE_INIT)
613 reply = STREAM_ERROR;
614 break;
617 reply = video_str_scan(td, (struct str_sync_data *)td->ev.data);
618 break;
620 case STREAM_QUIT:
621 /* Time to go - make thread exit */
622 td->state = TSTATE_EOS;
623 return;
626 str_reply_msg(&video_str, reply);
628 if (td->status == STREAM_PLAYING)
630 switch (td->state)
632 case TSTATE_DECODE:
633 case TSTATE_RENDER:
634 case TSTATE_RENDER_WAIT:
635 /* These return when in playing state */
636 return;
640 str_get_msg(&video_str, &td->ev);
644 static void video_thread(void)
646 struct video_thread_data td;
648 td.status = STREAM_STOPPED;
649 td.state = TSTATE_EOS;
650 td.mpeg2dec = mpeg2_init();
651 td.info = NULL;
652 td.syncf_perfect = 0;
653 td.curr_time = 0;
654 td.period = 0;
656 if (td.mpeg2dec == NULL)
658 td.status = STREAM_ERROR;
659 /* Loop and wait for quit message */
660 while (1)
662 str_get_msg(&video_str, &td.ev);
663 if (td.ev.id == STREAM_QUIT)
664 return;
665 str_reply_msg(&video_str, STREAM_ERROR);
669 vo_init();
671 goto message_wait;
673 while (1)
675 mpeg2_state_t mp2state;
676 td.state = TSTATE_DECODE;
678 /* Check for any pending messages and process them */
679 if (str_have_msg(&video_str))
681 message_wait:
682 /* Wait for a message to be queued */
683 str_get_msg(&video_str, &td.ev);
685 message_process:
686 /* Process a message already dequeued */
687 video_thread_msg(&td);
689 switch (td.state)
691 /* These states are the only ones that should return */
692 case TSTATE_DECODE: goto picture_decode;
693 case TSTATE_RENDER: goto picture_draw;
694 case TSTATE_RENDER_WAIT: goto picture_wait;
695 /* Anything else is interpreted as an exit */
696 default:
697 vo_cleanup();
698 mpeg2_close(td.mpeg2dec);
699 return;
703 picture_decode:
704 mp2state = mpeg2_parse (td.mpeg2dec);
706 switch (mp2state)
708 case STATE_BUFFER:
709 /* Request next packet data */
710 switch (parser_get_next_data(&video_str, STREAM_PM_STREAMING))
712 case STREAM_DATA_NOT_READY:
713 /* Wait for data to be buffered */
714 td.state = TSTATE_DATA;
715 goto message_wait;
717 case STREAM_DATA_END:
718 /* No more data. */
719 td.state = TSTATE_EOS;
720 if (td.status == STREAM_PLAYING)
721 stream_generate_event(&video_str, STREAM_EV_COMPLETE, 0);
722 goto message_wait;
724 case STREAM_OK:
725 if (video_str.pkt_flags & PKT_HAS_TS)
726 mpeg2_tag_picture(td.mpeg2dec, video_str.pts, 0);
728 mpeg2_buffer(td.mpeg2dec, video_str.curr_packet,
729 video_str.curr_packet_end);
730 td.info = mpeg2_info(td.mpeg2dec);
731 break;
733 break;
735 case STATE_SEQUENCE:
736 /* New video sequence, inform output of any changes */
737 vo_setup(td.info->sequence);
738 break;
740 case STATE_PICTURE:
742 int skip = 0; /* Assume no skip */
744 if (td.frame_drop_level >= 1 || td.skip_level > 0)
746 /* A frame will be dropped in the decoder */
748 /* Frame type: I/P/B/D */
749 int type = td.info->current_picture->flags
750 & PIC_MASK_CODING_TYPE;
752 switch (type)
754 case PIC_FLAG_CODING_TYPE_I:
755 case PIC_FLAG_CODING_TYPE_D:
756 /* Level 5: Things are extremely late and all frames will
757 be dropped until the next key frame */
758 if (td.frame_drop_level >= 1)
759 td.frame_drop_level = 0; /* Key frame - reset drop level */
760 if (td.skip_level >= 5)
762 td.frame_drop_level = 1;
763 td.skip_level = 0; /* reset */
765 break;
766 case PIC_FLAG_CODING_TYPE_P:
767 /* Level 4: Things are very late and all frames will be
768 dropped until the next key frame */
769 if (td.skip_level >= 4)
771 td.frame_drop_level = 1;
772 td.skip_level = 0; /* reset */
774 break;
775 case PIC_FLAG_CODING_TYPE_B:
776 /* We want to drop something, so this B frame won't even
777 be decoded. Drawing can happen on the next frame if so
778 desired. Bring the level down as skips are done. */
779 skip = 1;
780 if (td.skip_level > 0)
781 td.skip_level--;
784 skip |= td.frame_drop_level;
787 mpeg2_skip(td.mpeg2dec, skip);
788 break;
791 case STATE_SLICE:
792 case STATE_END:
793 case STATE_INVALID_END:
795 int32_t offset; /* Tick adjustment to keep sync */
797 /* draw current picture */
798 if (td.info->display_fbuf == NULL)
799 break; /* No picture */
801 /* Get presentation times in audio samples - quite accurate
802 enough - add previous frame duration if not stamped */
803 td.curr_time = (td.info->display_picture->flags & PIC_FLAG_TAGS) ?
804 td.info->display_picture->tag : (td.curr_time + td.period);
806 td.period = TC_TO_TS(td.info->sequence->frame_period);
808 /* No limiting => no dropping - draw this frame */
809 if (!settings.limitfps)
811 goto picture_draw;
814 td.eta_video = td.curr_time;
815 td.eta_stream = TICKS_TO_TS(stream_get_time());
817 /* How early/late are we? > 0 = late, < 0 early */
818 offset = td.eta_stream - td.eta_video;
820 if (!settings.skipframes)
822 /* Make no effort to determine whether this frame should be
823 drawn or not since no action can be taken to correct the
824 situation. We'll just wait if we're early and correct for
825 lateness as much as possible. */
826 if (offset < 0)
827 offset = 0;
829 td.eta_late = AVERAGE(td.eta_late, offset, 4);
830 offset = td.eta_late;
832 if ((uint32_t)offset > td.eta_video)
833 offset = td.eta_video;
835 td.eta_video -= offset;
836 goto picture_wait;
839 /** Possibly skip this frame **/
841 /* Frameskipping has the following order of preference:
843 * Frame Type Who Notes/Rationale
844 * B decoder arbitrarily drop - no decode or draw
845 * Any renderer arbitrarily drop - will be I/D/P
846 * P decoder must wait for I/D-frame - choppy
847 * I/D decoder must wait for I/D-frame - choppy
849 * If a frame can be drawn and it has been at least 1/2 second,
850 * the image will be updated no matter how late it is just to
851 * avoid looking stuck.
854 /* If we're late, set the eta to play the frame early so
855 we may catch up. If early, especially because of a drop,
856 mitigate a "snap" by moving back gradually. */
857 if (offset >= 0) /* late or on time */
859 td.eta_early = 0; /* Not early now :( */
861 td.eta_late = AVERAGE(td.eta_late, offset, 4);
862 offset = td.eta_late;
864 if ((uint32_t)offset > td.eta_video)
865 offset = td.eta_video;
867 td.eta_video -= offset;
869 else
871 td.eta_late = 0; /* Not late now :) */
873 if (offset > td.eta_early)
875 /* Just dropped a frame and we're now early or we're
876 coming back from being early */
877 td.eta_early = offset;
878 if ((uint32_t)-offset > td.eta_video)
879 offset = -td.eta_video;
881 td.eta_video += offset;
883 else
885 /* Just early with an offset, do exponential drift back */
886 if (td.eta_early != 0)
888 td.eta_early = AVERAGE(td.eta_early, 0, 8);
889 td.eta_video = ((uint32_t)-td.eta_early > td.eta_video) ?
890 0 : (td.eta_video + td.eta_early);
893 offset = td.eta_early;
897 if (td.info->display_picture->flags & PIC_FLAG_SKIP)
899 /* This frame was set to skip so skip it after having updated
900 timing information */
901 td.num_skipped++;
902 td.eta_early = INT32_MIN;
903 goto picture_skip;
906 if (td.skip_level == 3 &&
907 TIME_BEFORE(*rb->current_tick, td.last_render + HZ/2))
909 /* Render drop was set previously but nothing was dropped in the
910 decoder or it's been to long since drawing the last frame. */
911 td.skip_level = 0;
912 td.num_skipped++;
913 td.eta_early = INT32_MIN;
914 goto picture_skip;
917 /* At this point a frame _will_ be drawn - a skip may happen on
918 the next however */
919 td.skip_level = 0;
921 if (offset > TS_SECOND*110/1000)
923 /* Decide which skip level is needed in order to catch up */
925 /* TODO: Calculate this rather than if...else - this is rather
926 exponential though */
927 if (offset > TS_SECOND*367/1000)
928 td.skip_level = 5; /* Decoder skip: I/D */
929 if (offset > TS_SECOND*233/1000)
930 td.skip_level = 4; /* Decoder skip: P */
931 else if (offset > TS_SECOND*167/1000)
932 td.skip_level = 3; /* Render skip */
933 else if (offset > TS_SECOND*133/1000)
934 td.skip_level = 2; /* Decoder skip: B */
935 else
936 td.skip_level = 1; /* Decoder skip: B */
939 picture_wait:
940 td.state = TSTATE_RENDER_WAIT;
942 /* Wait until time catches up */
943 while (td.eta_video > td.eta_stream)
945 /* Watch for messages while waiting for the frame time */
946 int32_t eta_remaining = td.eta_video - td.eta_stream;
947 if (eta_remaining > TS_SECOND/HZ)
949 /* Several ticks to wait - do some sleeping */
950 int timeout = (eta_remaining - HZ) / (TS_SECOND/HZ);
951 str_get_msg_w_tmo(&video_str, &td.ev, MAX(timeout, 1));
952 if (td.ev.id != SYS_TIMEOUT)
953 goto message_process;
955 else
957 /* Just a little left - spin and be accurate */
958 rb->priority_yield();
959 if (str_have_msg(&video_str))
960 goto message_wait;
963 td.eta_stream = TICKS_TO_TS(stream_get_time());
966 picture_draw:
967 /* Record last frame time */
968 td.last_render = *rb->current_tick;
969 vo_draw_frame(td.info->display_fbuf->buf);
970 td.num_drawn++;
972 picture_skip:
973 if (!settings.showfps)
974 break;
976 if (TIME_BEFORE(*rb->current_tick, td.last_showfps + HZ))
977 break;
979 /* Calculate and display fps */
980 draw_fps(&td);
981 break;
984 default:
985 break;
988 rb->yield();
989 } /* end while */
992 /* Initializes the video thread */
993 bool video_thread_init(void)
995 intptr_t rep;
997 IF_COP(flush_icache());
999 video_str.hdr.q = &video_str_queue;
1000 rb->queue_init(video_str.hdr.q, false);
1001 rb->queue_enable_queue_send(video_str.hdr.q, &video_str_queue_send);
1003 /* We put the video thread on another processor for multi-core targets. */
1004 video_str.thread = rb->create_thread(
1005 video_thread, video_stack, VIDEO_STACKSIZE, 0,
1006 "mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK) IF_COP(, COP));
1008 if (video_str.thread == NULL)
1009 return false;
1011 /* Wait for thread to initialize */
1012 rep = str_send_msg(&video_str, STREAM_NULL, 0);
1013 IF_COP(invalidate_icache());
1015 return rep == 0; /* Normally STREAM_NULL should be ignored */
1018 /* Terminates the video thread */
1019 void video_thread_exit(void)
1021 if (video_str.thread != NULL)
1023 str_post_msg(&video_str, STREAM_QUIT, 0);
1024 rb->thread_wait(video_str.thread);
1025 IF_COP(invalidate_icache());
1026 video_str.thread = NULL;