1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
24 #include "mpegplayer.h"
25 #include "libmpeg2/mpeg2dec_config.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
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 */
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
)
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 */
89 return '?'; /* Say what? */
92 #endif /* defined(DEBUG) || defined(SIMULATOR) */
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
;
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);
116 mpeg2_state_t mp2state
= mpeg2_parse(td
->mpeg2dec
);
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");
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
);
140 DEBUGF("video_stream_scan:STATE_SEQUENCE\n");
141 vo_setup(td
->info
->sequence
);
143 if (td
->ev
.id
== VIDEO_GET_SIZE
)
152 case STATE_INVALID_END
:
154 if (td
->info
->display_picture
== NULL
)
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
)
169 period
= TC_TO_TS(td
->info
->sequence
->frame_period
);
183 if (td
->ev
.id
== STREAM_FIND_END_TIME
)
185 if (time
!= INVALID_TIMESTAMP
)
187 sd
->time
= time
+ period
;
188 retval
= STREAM_PERFECT_MATCH
;
192 retval
= STREAM_NOT_FOUND
;
196 mpeg2_skip(td
->mpeg2dec
, 0);
200 static bool init_sequence(struct video_thread_data
*td
)
202 struct str_sync_data sd
;
204 sd
.time
= 0; /* Ignored */
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
)
216 DEBUGF("check_needs_sync:\n");
217 if (td
->info
== NULL
|| td
->info
->display_fbuf
== NULL
)
219 DEBUGF(" no fbuf\n");
223 if (td
->syncf_perfect
== 0)
225 DEBUGF(" no frame\n");
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
)
238 if (time
>= end_time
)
239 return time
< video_str
.end_pts
|| end_time
< video_str
.end_pts
;
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;
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");
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);
271 mpeg2_state_t mp2state
= mpeg2_parse(td
->mpeg2dec
);
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
286 retval
= STREAM_PERFECT_MATCH
;
287 td
->syncf_perfect
= 1;
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
);
302 DEBUGF(" STATE_SEQUENCE\n");
303 vo_setup(td
->info
->sequence
);
307 DEBUGF(" STATE_GOP: (%s)\n",
308 (td
->info
->gop
->flags
& GOP_FLAG_CLOSED_GOP
) ?
314 int type
= td
->info
->current_picture
->flags
315 & PIC_MASK_CODING_TYPE
;
319 case PIC_FLAG_CODING_TYPE_I
:
320 /* I-frame; start decoding */
321 mpeg2_skip(td
->mpeg2dec
, 0);
325 case PIC_FLAG_CODING_TYPE_P
:
326 /* P-frames don't count without I-frames */
327 if (td
->num_ref_pics
> 0)
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
);
339 DEBUGF(" STATE_PICTURE (%c): -\n", pic_coding_type_char(type
));
347 case STATE_INVALID_END
:
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
) ?
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
) ?
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
,
384 pic_coding_type_char(type
),
385 (td
->info
->display_picture
->flags
& PIC_FLAG_SKIP
) ?
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");
394 else if (!(td
->info
->display_picture
->flags
& PIC_FLAG_SKIP
))
396 /* One perfect point if dependent frames were decoded */
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;
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");
424 /* Two or more perfect points = perfect match - yay! */
425 retval
= (td
->syncf_perfect
>= 2) ?
426 STREAM_PERFECT_MATCH
: STREAM_MATCH
;
430 /* Too late, no I-Frame yet */
445 mpeg2_skip(td
->mpeg2dec
, 0);
449 static bool frame_print_handler(struct video_thread_data
*td
)
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
);
466 /* Print the last frame decoded */
468 retval
= buf
!= NULL
;
474 /* This only returns to play or quit */
475 static void video_thread_msg(struct video_thread_data
*td
)
484 td
->status
= STREAM_PLAYING
;
489 /* Begin decoding state */
490 td
->state
= TSTATE_DECODE
;
493 if (td
->syncf_perfect
<= 0)
495 /* There should be a frame already, just draw it */
496 td
->goal_time
= td
->frame_time
;
497 td
->state
= TSTATE_RENDER_WAIT
;
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
;
510 /* At end of stream - no playback possible so fire the
511 * completion event */
512 stream_generate_event(&video_str
, STREAM_EV_COMPLETE
, 0);
516 reply
= td
->state
!= TSTATE_EOS
;
520 td
->status
= STREAM_PAUSED
;
521 reply
= td
->state
!= TSTATE_EOS
;
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
;
533 case VIDEO_DISPLAY_IS_VISIBLE
:
534 reply
= vo_is_visible();
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
)
549 frame_print_handler(td
);
553 IF_COP(rb
->cpucache_invalidate());
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
;
572 td
->skip_ref_pics
= 0;
576 td
->group_est
= DEFAULT_GOP_SIZE
;
577 td
->last_render
= *rb
->current_tick
- HZ
;
579 video_num_skipped
= 0;
584 case STREAM_NEEDS_SYNC
:
585 reply
= check_needs_sync(td
, td
->ev
.data
);
589 if (td
->state
== TSTATE_INIT
)
590 reply
= sync_decoder(td
, (struct str_sync_data
*)td
->ev
.data
);
593 case DISK_BUF_DATA_NOTIFY
:
594 /* Our bun is done */
595 if (td
->state
!= TSTATE_DATA
)
598 td
->state
= TSTATE_DECODE
;
599 str_data_notify_received(&video_str
);
602 case VIDEO_PRINT_FRAME
:
603 case VIDEO_PRINT_THUMBNAIL
:
604 reply
= frame_print_handler(td
);
607 case VIDEO_SET_CLIP_RECT
:
608 vo_set_clip_rect((const struct vo_rect
*)td
->ev
.data
);
611 case VIDEO_GET_CLIP_RECT
:
612 reply
= vo_get_clip_rect((struct vo_rect
*)td
->ev
.data
);
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
))
624 vo_dimensions((struct vo_ext
*)td
->ev
.data
);
629 case STREAM_FIND_END_TIME
:
630 if (td
->state
!= TSTATE_INIT
)
632 reply
= STREAM_ERROR
;
636 reply
= video_str_scan(td
, (struct str_sync_data
*)td
->ev
.data
);
639 case VIDEO_SET_POST_FRAME_CALLBACK
:
640 vo_set_post_draw_callback((void (*)(void))td
->ev
.data
);
645 /* Time to go - make thread exit */
646 td
->state
= TSTATE_EOS
;
650 str_reply_msg(&video_str
, reply
);
652 if (td
->status
== STREAM_PLAYING
)
658 case TSTATE_RENDER_WAIT
:
659 /* These return when in playing state */
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 */
683 str_get_msg(&video_str
, &td
.ev
);
684 if (td
.ev
.id
== STREAM_QUIT
)
686 str_reply_msg(&video_str
, STREAM_ERROR
);
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
))
703 /* Wait for a message to be queued */
704 str_get_msg(&video_str
, &td
.ev
);
707 /* Process a message already dequeued */
708 video_thread_msg(&td
);
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
;
722 mp2state
= mpeg2_parse (td
.mpeg2dec
);
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
;
735 case STREAM_DATA_END
:
737 td
.state
= TSTATE_EOS
;
738 if (td
.status
== STREAM_PLAYING
)
739 stream_generate_event(&video_str
, STREAM_EV_COMPLETE
, 0);
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
);
754 /* New video sequence, inform output of any changes */
755 vo_setup(td
.info
->sequence
);
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 */
780 skip
= td
.skip_ref_pics
= 0; /* now, decode */
785 case PIC_FLAG_CODING_TYPE_P
:
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 */
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
809 if (td
.skip_level
> 0 || td
.num_ref_pics
< 2)
821 if (td
.num_intra
> 0)
826 mpeg2_skip(td
.mpeg2dec
, skip
);
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
;
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 */
853 td
.syncf_perfect
= 1; /* have frame */
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
;
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
;
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
)
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. */
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. */
930 /* At this point a frame _will_ be drawn - a skip may happen on
933 /* Calculate number of frames to drop/skip - allow brief periods
934 of lateness before producing skips */
936 if (td
.remain_time
> 0 && (uint32_t)offset
> DROP_THRESHOLD
)
938 td
.skip_level
= (offset
- DROP_THRESHOLD
+ td
.frame_period
)
943 td
.state
= TSTATE_RENDER_WAIT
;
945 /* Wait until time catches up */
948 int32_t twait
= td
.goal_time
- td
.stream_time
;
949 /* Watch for messages while waiting for the frame time */
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
;
964 /* Just a little left - spin and be accurate */
966 if (str_have_msg(&video_str
))
970 td
.stream_time
= TICKS_TO_TS(stream_get_time());
974 /* Record last frame time */
975 td
.last_render
= *rb
->current_tick
;
977 vo_draw_frame(td
.info
->display_fbuf
->buf
);
982 if (td
.remain_time
<= DROP_THRESHOLD
)
985 if (td
.remain_time
<= 0)
986 td
.remain_time
= INT32_MIN
;
1002 mpeg2_close(td
.mpeg2dec
);
1005 /* Initializes the video thread */
1006 bool video_thread_init(void)
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
,
1023 if (video_str
.thread
== 0)
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;
1047 void video_thread_get_stats(struct video_output_stats
*s
)
1050 uint32_t now
= stream_get_ticks(&start
);
1051 s
->num_drawn
= video_num_drawn
;
1052 s
->num_skipped
= video_num_skipped
;
1057 s
->fps
= muldiv_uint32(CLOCK_RATE
*100, s
->num_drawn
, now
- start
);