1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
22 #include "mpegplayer.h"
23 #include "mpeg2dec_config.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
)
64 uint32_t clock_ticks
= stream_get_ticks(&start
);
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
);
84 lcd_(update_rect
)(0, 0, LCD_WIDTH
, 8);
87 td
->last_showfps
= *rb
->current_tick
;
90 #if defined(DEBUG) || defined(SIMULATOR)
91 static unsigned char pic_coding_type_char(unsigned 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 */
104 return '?'; /* Say what? */
107 #endif /* defined(DEBUG) || defined(SIMULATOR) */
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
;
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);
130 mpeg2_state_t mp2state
= mpeg2_parse(td
->mpeg2dec
);
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");
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
);
154 DEBUGF("video_stream_scan:STATE_SEQUENCE\n");
155 vo_setup(td
->info
->sequence
);
157 if (td
->ev
.id
== VIDEO_GET_SIZE
)
166 case STATE_INVALID_END
:
168 if (td
->info
->display_picture
== NULL
)
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
)
183 period
= TC_TO_TS(td
->info
->sequence
->frame_period
);
197 if (td
->ev
.id
== STREAM_FIND_END_TIME
)
199 if (time
!= INVALID_TIMESTAMP
)
201 sd
->time
= time
+ period
;
202 retval
= STREAM_PERFECT_MATCH
;
206 retval
= STREAM_NOT_FOUND
;
210 mpeg2_skip(td
->mpeg2dec
, 0);
214 static bool init_sequence(struct video_thread_data
*td
)
216 struct str_sync_data sd
;
218 sd
.time
= 0; /* Ignored */
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
)
230 DEBUGF("check_needs_sync:\n");
231 if (td
->info
== NULL
|| td
->info
->display_fbuf
== NULL
)
233 DEBUGF(" no fbuf\n");
237 if (td
->syncf_perfect
== 0)
239 DEBUGF(" no frame\n");
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
)
252 if (time
>= end_time
)
253 return time
< video_str
.end_pts
|| end_time
< video_str
.end_pts
;
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;
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");
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);
285 mpeg2_state_t mp2state
= mpeg2_parse(td
->mpeg2dec
);
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
300 retval
= STREAM_PERFECT_MATCH
;
301 td
->syncf_perfect
= 1;
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
);
317 DEBUGF(" STATE_SEQUENCE\n");
318 vo_setup(td
->info
->sequence
);
322 DEBUGF(" STATE_GOP: (%s)\n",
323 (td
->info
->gop
->flags
& GOP_FLAG_CLOSED_GOP
) ?
329 int type
= td
->info
->current_picture
->flags
330 & PIC_MASK_CODING_TYPE
;
334 case PIC_FLAG_CODING_TYPE_I
:
335 /* I-frame; start decoding */
336 mpeg2_skip(td
->mpeg2dec
, 0);
339 case PIC_FLAG_CODING_TYPE_P
:
340 /* P-frames don't count without I-frames */
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
);
352 DEBUGF(" STATE_PICTURE (%c): -\n", pic_coding_type_char(type
));
360 case STATE_INVALID_END
:
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
) ?
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
) ?
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
,
397 pic_coding_type_char(type
),
398 (td
->info
->display_picture
->flags
& PIC_FLAG_SKIP
) ?
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");
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");
427 /* Two or more perfect points = perfect match - yay! */
428 retval
= (td
->syncf_perfect
>= 2) ?
429 STREAM_PERFECT_MATCH
: STREAM_MATCH
;
433 /* Too late, no I-Frame yet */
448 mpeg2_skip(td
->mpeg2dec
, 0);
452 /* This only returns to play or quit */
453 static void video_thread_msg(struct video_thread_data
*td
)
462 td
->status
= STREAM_PLAYING
;
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
;
476 /* Begin decoding state */
477 td
->state
= TSTATE_DECODE
;
481 /* At end of stream - no playback possible so fire the
482 * completion event */
483 stream_generate_event(&video_str
, STREAM_EV_COMPLETE
, 0);
487 reply
= td
->state
!= TSTATE_EOS
;
491 td
->status
= STREAM_PAUSED
;
492 reply
= td
->state
!= TSTATE_EOS
;
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
;
504 case VIDEO_DISPLAY_IS_VISIBLE
:
505 reply
= vo_is_visible();
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
)
520 if (td
->info
!= NULL
&& td
->info
->display_fbuf
!= NULL
)
521 vo_draw_frame(td
->info
->display_fbuf
->buf
);
525 IF_COP(invalidate_icache());
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
;
545 td
->frame_drop_level
= 0;
549 td
->last_showfps
= *rb
->current_tick
- HZ
;
550 td
->last_render
= td
->last_showfps
;
555 case STREAM_NEEDS_SYNC
:
556 reply
= check_needs_sync(td
, td
->ev
.data
);
560 if (td
->state
== TSTATE_INIT
)
561 reply
= sync_decoder(td
, (struct str_sync_data
*)td
->ev
.data
);
564 case DISK_BUF_DATA_NOTIFY
:
565 /* Our bun is done */
566 if (td
->state
!= TSTATE_DATA
)
569 td
->state
= TSTATE_DECODE
;
570 str_data_notify_received(&video_str
);
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
);
584 case VIDEO_SET_CLIP_RECT
:
585 vo_set_clip_rect((const struct vo_rect
*)td
->ev
.data
);
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
);
599 if (td
->state
!= TSTATE_INIT
)
602 if (init_sequence(td
))
605 vo_dimensions((struct vo_ext
*)td
->ev
.data
);
610 case STREAM_FIND_END_TIME
:
611 if (td
->state
!= TSTATE_INIT
)
613 reply
= STREAM_ERROR
;
617 reply
= video_str_scan(td
, (struct str_sync_data
*)td
->ev
.data
);
621 /* Time to go - make thread exit */
622 td
->state
= TSTATE_EOS
;
626 str_reply_msg(&video_str
, reply
);
628 if (td
->status
== STREAM_PLAYING
)
634 case TSTATE_RENDER_WAIT
:
635 /* These return when in playing state */
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();
652 td
.syncf_perfect
= 0;
656 if (td
.mpeg2dec
== NULL
)
658 td
.status
= STREAM_ERROR
;
659 /* Loop and wait for quit message */
662 str_get_msg(&video_str
, &td
.ev
);
663 if (td
.ev
.id
== STREAM_QUIT
)
665 str_reply_msg(&video_str
, STREAM_ERROR
);
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
))
682 /* Wait for a message to be queued */
683 str_get_msg(&video_str
, &td
.ev
);
686 /* Process a message already dequeued */
687 video_thread_msg(&td
);
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 */
698 mpeg2_close(td
.mpeg2dec
);
704 mp2state
= mpeg2_parse (td
.mpeg2dec
);
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
;
717 case STREAM_DATA_END
:
719 td
.state
= TSTATE_EOS
;
720 if (td
.status
== STREAM_PLAYING
)
721 stream_generate_event(&video_str
, STREAM_EV_COMPLETE
, 0);
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
);
736 /* New video sequence, inform output of any changes */
737 vo_setup(td
.info
->sequence
);
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
;
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 */
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 */
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. */
780 if (td
.skip_level
> 0)
784 skip
|= td
.frame_drop_level
;
787 mpeg2_skip(td
.mpeg2dec
, skip
);
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
)
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. */
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
;
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
;
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
;
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 */
902 td
.eta_early
= INT32_MIN
;
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. */
913 td
.eta_early
= INT32_MIN
;
917 /* At this point a frame _will_ be drawn - a skip may happen on
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 */
936 td
.skip_level
= 1; /* Decoder skip: B */
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
;
957 /* Just a little left - spin and be accurate */
958 rb
->priority_yield();
959 if (str_have_msg(&video_str
))
963 td
.eta_stream
= TICKS_TO_TS(stream_get_time());
967 /* Record last frame time */
968 td
.last_render
= *rb
->current_tick
;
969 vo_draw_frame(td
.info
->display_fbuf
->buf
);
973 if (!settings
.showfps
)
976 if (TIME_BEFORE(*rb
->current_tick
, td
.last_showfps
+ HZ
))
979 /* Calculate and display fps */
992 /* Initializes the video thread */
993 bool video_thread_init(void)
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
)
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
;