summaryrefslogtreecommitdiff
path: root/apps/plugins/mpegplayer/video_thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mpegplayer/video_thread.c')
-rw-r--r--apps/plugins/mpegplayer/video_thread.c1059
1 files changed, 1059 insertions, 0 deletions
diff --git a/apps/plugins/mpegplayer/video_thread.c b/apps/plugins/mpegplayer/video_thread.c
new file mode 100644
index 0000000000..392cc6179f
--- /dev/null
+++ b/apps/plugins/mpegplayer/video_thread.c
@@ -0,0 +1,1059 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * mpegplayer video thread implementation
11 *
12 * Copyright (c) 2007 Michael Sevakis
13 *
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.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
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"
29
30/** Video stream and thread **/
31
32/* Video thread data passed around to its various functions */
33struct video_thread_data
34{
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 */
56};
57
58/* Number drawn since reset */
59static int video_num_drawn SHAREDBSS_ATTR;
60/* Number skipped since reset */
61static int video_num_skipped SHAREDBSS_ATTR;
62
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)
66static uint32_t video_stack[VIDEO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR;
67static struct event_queue video_str_queue SHAREDBSS_ATTR;
68static struct queue_sender_list video_str_queue_send SHAREDBSS_ATTR;
69struct stream video_str IBSS_ATTR;
70
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)
74
75#if defined(DEBUG) || defined(SIMULATOR)
76static unsigned char pic_coding_type_char(unsigned type)
77{
78 switch (type)
79 {
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? */
90 }
91}
92#endif /* defined(DEBUG) || defined(SIMULATOR) */
93
94/* Multi-use:
95 * 1) Find the sequence header and initialize video out
96 * 2) Find the end of the final frame
97 */
98static int video_str_scan(struct video_thread_data *td,
99 struct str_sync_data *sd)
100{
101 int retval = STREAM_ERROR;
102 uint32_t time = INVALID_TIMESTAMP;
103 uint32_t period = 0;
104 struct stream tmp_str;
105
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;
109
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);
113
114 while (1)
115 {
116 mpeg2_state_t mp2state = mpeg2_parse(td->mpeg2dec);
117 rb->yield();
118
119 switch (mp2state)
120 {
121 case STATE_BUFFER:
122 switch (parser_get_next_data(&tmp_str, STREAM_PM_RANDOM_ACCESS))
123 {
124 case STREAM_DATA_END:
125 DEBUGF("video_stream_scan:STREAM_DATA_END\n");
126 goto scan_finished;
127
128 case STREAM_OK:
129 if (tmp_str.pkt_flags & PKT_HAS_TS)
130 mpeg2_tag_picture(td->mpeg2dec, tmp_str.pts, 0);
131
132 mpeg2_buffer(td->mpeg2dec, tmp_str.curr_packet,
133 tmp_str.curr_packet_end);
134 td->info = mpeg2_info(td->mpeg2dec);
135 break;
136 }
137 break;
138
139 case STATE_SEQUENCE:
140 DEBUGF("video_stream_scan:STATE_SEQUENCE\n");
141 vo_setup(td->info->sequence);
142
143 if (td->ev.id == VIDEO_GET_SIZE)
144 {
145 retval = STREAM_OK;
146 goto scan_finished;
147 }
148 break;
149
150 case STATE_SLICE:
151 case STATE_END:
152 case STATE_INVALID_END:
153 {
154 if (td->info->display_picture == NULL)
155 break;
156
157 switch (td->ev.id)
158 {
159 case STREAM_SYNC:
160 retval = STREAM_OK;
161 goto scan_finished;
162
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;
168
169 period = TC_TO_TS(td->info->sequence->frame_period);
170 break;
171 }
172
173 break;
174 }
175
176 default:
177 break;
178 }
179 }
180
181scan_finished:
182
183 if (td->ev.id == STREAM_FIND_END_TIME)
184 {
185 if (time != INVALID_TIMESTAMP)
186 {
187 sd->time = time + period;
188 retval = STREAM_PERFECT_MATCH;
189 }
190 else
191 {
192 retval = STREAM_NOT_FOUND;
193 }
194 }
195
196 mpeg2_skip(td->mpeg2dec, 0);
197 return retval;
198}
199
200static bool init_sequence(struct video_thread_data *td)
201{
202 struct str_sync_data sd;
203
204 sd.time = 0; /* Ignored */
205 sd.sk.pos = 0;
206 sd.sk.len = 1024*1024;
207 sd.sk.dir = SSCAN_FORWARD;
208
209 return video_str_scan(td, &sd) == STREAM_OK;
210}
211
212static bool check_needs_sync(struct video_thread_data *td, uint32_t time)
213{
214 uint32_t end_time;
215
216 DEBUGF("check_needs_sync:\n");
217 if (td->info == NULL || td->info->display_fbuf == NULL)
218 {
219 DEBUGF(" no fbuf\n");
220 return true;
221 }
222
223 if (td->syncf_perfect == 0)
224 {
225 DEBUGF(" no frame\n");
226 return true;
227 }
228
229 time = clip_time(&video_str, time);
230 end_time = td->frame_time + td->frame_period;
231
232 DEBUGF(" sft:%u t:%u sfte:%u\n", (unsigned)td->frame_time,
233 (unsigned)time, (unsigned)end_time);
234
235 if (time < td->frame_time)
236 return true;
237
238 if (time >= end_time)
239 return time < video_str.end_pts || end_time < video_str.end_pts;
240
241 return false;
242}
243
244/* Do any needed decoding/slide up to the specified time */
245static int sync_decoder(struct video_thread_data *td,
246 struct str_sync_data *sd)
247{
248 int retval = STREAM_ERROR;
249 uint32_t time = clip_time(&video_str, sd->time);
250
251 td->syncf_perfect = 0;
252 td->frame_time = 0;
253 td->frame_period = 0;
254 td->num_ref_pics = 0;
255
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))
259 {
260 DEBUGF("sync_decoder=>init_sequence failed\n");
261 goto sync_finished;
262 }
263
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);
268
269 while (1)
270 {
271 mpeg2_state_t mp2state = mpeg2_parse(td->mpeg2dec);
272
273 switch (mp2state)
274 {
275 case STATE_BUFFER:
276 switch (parser_get_next_data(&video_str, STREAM_PM_RANDOM_ACCESS))
277 {
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))
282 {
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;
288 }
289 goto sync_finished;
290
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;
298 }
299 break;
300
301 case STATE_SEQUENCE:
302 DEBUGF(" STATE_SEQUENCE\n");
303 vo_setup(td->info->sequence);
304 break;
305
306 case STATE_GOP:
307 DEBUGF(" STATE_GOP: (%s)\n",
308 (td->info->gop->flags & GOP_FLAG_CLOSED_GOP) ?
309 "closed" : "open");
310 break;
311
312 case STATE_PICTURE:
313 {
314 int type = td->info->current_picture->flags
315 & PIC_MASK_CODING_TYPE;
316
317 switch (type)
318 {
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;
324
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;
330 }
331
332 if (td->info->current_picture->flags & PIC_FLAG_TAGS)
333 {
334 DEBUGF(" STATE_PICTURE (%c): %u\n", pic_coding_type_char(type),
335 (unsigned)td->info->current_picture->tag);
336 }
337 else
338 {
339 DEBUGF(" STATE_PICTURE (%c): -\n", pic_coding_type_char(type));
340 }
341
342 break;
343 }
344
345 case STATE_SLICE:
346 case STATE_END:
347 case STATE_INVALID_END:
348 {
349 uint32_t end_time;
350
351 if (td->info->display_picture == NULL)
352 {
353 DEBUGF(" td->info->display_picture == NULL\n");
354 break; /* No picture */
355 }
356
357 int type = td->info->display_picture->flags
358 & PIC_MASK_CODING_TYPE;
359
360 if (td->info->display_picture->flags & PIC_FLAG_TAGS)
361 {
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" : "");
367 }
368 else
369 {
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" : "");
375 }
376
377 td->frame_period = TC_TO_TS(td->info->sequence->frame_period);
378 end_time = td->frame_time + td->frame_period;
379
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" : "");
387
388 if (end_time <= time && end_time < video_str.end_pts)
389 {
390 /* Still too early and have not hit at EOS */
391 DEBUGF(" too early\n");
392 break;
393 }
394 else if (!(td->info->display_picture->flags & PIC_FLAG_SKIP))
395 {
396 /* One perfect point if dependent frames were decoded */
397 switch (type)
398 {
399 case PIC_FLAG_CODING_TYPE_B:
400 if (td->num_ref_pics > 1)
401 {
402 case PIC_FLAG_CODING_TYPE_P:
403 if (td->num_ref_pics > 0)
404 {
405 case PIC_FLAG_CODING_TYPE_I:
406 td->syncf_perfect = 1;
407 break;
408 }
409 }
410 }
411
412 if ((td->frame_time <= time && time < end_time) ||
413 end_time >= video_str.end_pts)
414 {
415 /* One perfect point for matching time goal */
416 DEBUGF(" ft<=t<fe\n");
417 td->syncf_perfect++;
418 }
419 else
420 {
421 DEBUGF(" ft>t\n");
422 }
423
424 /* Two or more perfect points = perfect match - yay! */
425 retval = (td->syncf_perfect >= 2) ?
426 STREAM_PERFECT_MATCH : STREAM_MATCH;
427 }
428 else
429 {
430 /* Too late, no I-Frame yet */
431 DEBUGF("\n");
432 }
433
434 goto sync_finished;
435 }
436
437 default:
438 break;
439 }
440
441 rb->yield();
442 } /* end while */
443
444sync_finished:
445 mpeg2_skip(td->mpeg2dec, 0);
446 return retval;
447}
448
449static bool frame_print_handler(struct video_thread_data *td)
450{
451 bool retval;
452 uint8_t * const * buf = NULL;
453
454 if (td->info != NULL && td->info->display_fbuf != NULL &&
455 td->syncf_perfect > 0)
456 buf = td->info->display_fbuf->buf;
457
458 if (td->ev.id == VIDEO_PRINT_THUMBNAIL)
459 {
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);
463 }
464 else
465 {
466 /* Print the last frame decoded */
467 vo_draw_frame(buf);
468 retval = buf != NULL;
469 }
470
471 return retval;
472}
473
474/* This only returns to play or quit */
475static void video_thread_msg(struct video_thread_data *td)
476{
477 while (1)
478 {
479 intptr_t reply = 0;
480
481 switch (td->ev.id)
482 {
483 case STREAM_PLAY:
484 td->status = STREAM_PLAYING;
485
486 switch (td->state)
487 {
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;
508
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;
514 }
515
516 reply = td->state != TSTATE_EOS;
517 break;
518
519 case STREAM_PAUSE:
520 td->status = STREAM_PAUSED;
521 reply = td->state != TSTATE_EOS;
522 break;
523
524 case STREAM_STOP:
525 if (td->state == TSTATE_DATA)
526 stream_clear_notify(&video_str, DISK_BUF_DATA_NOTIFY);
527
528 td->status = STREAM_STOPPED;
529 td->state = TSTATE_EOS;
530 reply = true;
531 break;
532
533 case VIDEO_DISPLAY_IS_VISIBLE:
534 reply = vo_is_visible();
535 break;
536
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);
541
542#ifdef HAVE_LCD_COLOR
543 /* Match graylib behavior as much as possible */
544 if (!td->ev.data == !reply)
545 break;
546
547 if (td->ev.data)
548 {
549 frame_print_handler(td);
550 }
551 else
552 {
553 IF_COP(rb->commit_discard_dcache());
554 vo_lock();
555 rb->lcd_update();
556 vo_unlock();
557 }
558#endif
559 break;
560
561 case STREAM_RESET:
562 if (td->state == TSTATE_DATA)
563 stream_clear_notify(&video_str, DISK_BUF_DATA_NOTIFY);
564
565 td->state = TSTATE_INIT;
566 td->status = STREAM_STOPPED;
567
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;
580
581 reply = true;
582 break;
583
584 case STREAM_NEEDS_SYNC:
585 reply = check_needs_sync(td, td->ev.data);
586 break;
587
588 case STREAM_SYNC:
589 if (td->state == TSTATE_INIT)
590 reply = sync_decoder(td, (struct str_sync_data *)td->ev.data);
591 break;
592
593 case DISK_BUF_DATA_NOTIFY:
594 /* Our bun is done */
595 if (td->state != TSTATE_DATA)
596 break;
597
598 td->state = TSTATE_DECODE;
599 str_data_notify_received(&video_str);
600 break;
601
602 case VIDEO_PRINT_FRAME:
603 case VIDEO_PRINT_THUMBNAIL:
604 reply = frame_print_handler(td);
605 break;
606
607 case VIDEO_SET_CLIP_RECT:
608 vo_set_clip_rect((const struct vo_rect *)td->ev.data);
609 break;
610
611 case VIDEO_GET_CLIP_RECT:
612 reply = vo_get_clip_rect((struct vo_rect *)td->ev.data);
613 break;
614
615 case VIDEO_GET_SIZE:
616 {
617 if (td->state != TSTATE_INIT)
618 break; /* Can only use after a reset was issued */
619
620 /* This will reset the decoder in full for this particular event */
621 if (init_sequence(td))
622 {
623 reply = true;
624 vo_dimensions((struct vo_ext *)td->ev.data);
625 }
626 break;
627 }
628
629 case STREAM_FIND_END_TIME:
630 if (td->state != TSTATE_INIT)
631 {
632 reply = STREAM_ERROR;
633 break;
634 }
635
636 reply = video_str_scan(td, (struct str_sync_data *)td->ev.data);
637 break;
638
639 case VIDEO_SET_POST_FRAME_CALLBACK:
640 vo_set_post_draw_callback((void (*)(void))td->ev.data);
641 reply = true;
642 break;
643
644 case STREAM_QUIT:
645 /* Time to go - make thread exit */
646 td->state = TSTATE_EOS;
647 return;
648 }
649
650 str_reply_msg(&video_str, reply);
651
652 if (td->status == STREAM_PLAYING)
653 {
654 switch (td->state)
655 {
656 case TSTATE_DECODE:
657 case TSTATE_RENDER:
658 case TSTATE_RENDER_WAIT:
659 /* These return when in playing state */
660 return;
661 }
662 }
663
664 str_get_msg(&video_str, &td->ev);
665 }
666}
667
668static void video_thread(void)
669{
670 struct video_thread_data td;
671
672 memset(&td, 0, sizeof (td));
673 td.mpeg2dec = mpeg2_init();
674 td.status = STREAM_STOPPED;
675 td.state = TSTATE_EOS;
676
677 if (td.mpeg2dec == NULL)
678 {
679 td.status = STREAM_ERROR;
680 /* Loop and wait for quit message */
681 while (1)
682 {
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);
687 }
688 }
689
690 vo_init();
691
692 goto message_wait;
693
694 while (1)
695 {
696 mpeg2_state_t mp2state;
697 td.state = TSTATE_DECODE;
698
699 /* Check for any pending messages and process them */
700 if (str_have_msg(&video_str))
701 {
702 message_wait:
703 /* Wait for a message to be queued */
704 str_get_msg(&video_str, &td.ev);
705
706 message_process:
707 /* Process a message already dequeued */
708 video_thread_msg(&td);
709
710 switch (td.state)
711 {
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;
718 }
719 }
720
721 picture_decode:
722 mp2state = mpeg2_parse (td.mpeg2dec);
723
724 switch (mp2state)
725 {
726 case STATE_BUFFER:
727 /* Request next packet data */
728 switch (parser_get_next_data(&video_str, STREAM_PM_STREAMING))
729 {
730 case STREAM_DATA_NOT_READY:
731 /* Wait for data to be buffered */
732 td.state = TSTATE_DATA;
733 goto message_wait;
734
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;
741
742 case STREAM_OK:
743 if (video_str.pkt_flags & PKT_HAS_TS)
744 mpeg2_tag_picture(td.mpeg2dec, video_str.pts, 0);
745
746 mpeg2_buffer(td.mpeg2dec, video_str.curr_packet,
747 video_str.curr_packet_end);
748 td.info = mpeg2_info(td.mpeg2dec);
749 break;
750 }
751 break;
752
753 case STATE_SEQUENCE:
754 /* New video sequence, inform output of any changes */
755 vo_setup(td.info->sequence);
756 break;
757
758 case STATE_PICTURE:
759 {
760 /* This is not in presentation order - do our best anyway */
761 int skip = td.skip_ref_pics;
762
763 /* Frame type: I/P/B/D */
764 switch (td.info->current_picture->flags & PIC_MASK_CODING_TYPE)
765 {
766 case PIC_FLAG_CODING_TYPE_I:
767 if (++td.num_intra >= 2)
768 td.group_est = td.num_picture / (td.num_intra - 1);
769
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)
773 {
774 td.skip_level--; /* skip frame */
775 skip = td.skip_ref_pics = 1; /* wait for I-frame */
776 td.num_ref_pics = 0;
777 }
778 else if (skip != 0)
779 {
780 skip = td.skip_ref_pics = 0; /* now, decode */
781 td.num_ref_pics = 1;
782 }
783 break;
784
785 case PIC_FLAG_CODING_TYPE_P:
786 if (skip == 0)
787 {
788 td.num_ref_pics++;
789
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)
793 {
794 skip = td.skip_ref_pics = 1; /* wait for I-frame */
795 td.num_ref_pics = 0;
796 }
797 }
798
799 if (skip != 0)
800 td.skip_level--;
801 break;
802
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)
810 {
811 skip = 1;
812 td.skip_level--;
813 }
814 break;
815
816 default:
817 skip = 1;
818 break;
819 }
820
821 if (td.num_intra > 0)
822 td.num_picture++;
823
824 td.group_est--;
825
826 mpeg2_skip(td.mpeg2dec, skip);
827 break;
828 }
829
830 case STATE_SLICE:
831 case STATE_END:
832 case STATE_INVALID_END:
833 {
834 int32_t offset; /* Tick adjustment to keep sync */
835
836 if (td.info->display_fbuf == NULL)
837 break; /* No picture */
838
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;
845
846 td.frame_period = TC_TO_TS(td.info->sequence->frame_period);
847
848 if (!settings.limitfps)
849 {
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;
855 }
856
857 td.goal_time = td.frame_time;
858 td.stream_time = TICKS_TO_TS(stream_get_time());
859
860 /* How early/late are we? > 0 = late, < 0 early */
861 offset = td.stream_time - td.goal_time;
862
863 if (offset >= 0)
864 {
865 /* Late or on-time */
866 if (td.remain_time < 0)
867 td.remain_time = 0; /* now, late */
868
869 offset = AVERAGE(td.remain_time, offset, 4);
870 td.remain_time = offset;
871 }
872 else
873 {
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 */
882
883 offset = -td.remain_time;
884 }
885
886 /* Skip anything not decoded */
887 if (td.info->display_picture->flags & PIC_FLAG_SKIP)
888 goto picture_skip;
889
890 td.syncf_perfect = 1; /* have frame (assume so from now on) */
891
892 /* Keep goal_time >= 0 */
893 if ((uint32_t)offset > td.goal_time)
894 offset = td.goal_time;
895
896 td.goal_time -= offset;
897
898 if (!settings.skipframes)
899 {
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;
904 }
905
906 /** Possibly skip this frame **/
907
908 /* Frameskipping has the following order of preference:
909 *
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
915 *
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.
919 */
920 if (td.skip_level > 0 &&
921 TIME_BEFORE(*rb->current_tick, td.last_render + HZ/2))
922 {
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;
928 }
929
930 /* At this point a frame _will_ be drawn - a skip may happen on
931 the next however */
932
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)
937 {
938 td.skip_level = (offset - DROP_THRESHOLD + td.frame_period)
939 / td.frame_period;
940 }
941
942 picture_wait:
943 td.state = TSTATE_RENDER_WAIT;
944
945 /* Wait until time catches up */
946 while (1)
947 {
948 int32_t twait = td.goal_time - td.stream_time;
949 /* Watch for messages while waiting for the frame time */
950
951 if (twait <= 0)
952 break;
953
954 if (twait > TS_SECOND/HZ)
955 {
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;
961 }
962 else
963 {
964 /* Just a little left - spin and be accurate */
965 rb->yield();
966 if (str_have_msg(&video_str))
967 goto message_wait;
968 }
969
970 td.stream_time = TICKS_TO_TS(stream_get_time());
971 }
972
973 picture_draw:
974 /* Record last frame time */
975 td.last_render = *rb->current_tick;
976
977 vo_draw_frame(td.info->display_fbuf->buf);
978 video_num_drawn++;
979 break;
980
981 picture_skip:
982 if (td.remain_time <= DROP_THRESHOLD)
983 {
984 td.skip_level = 0;
985 if (td.remain_time <= 0)
986 td.remain_time = INT32_MIN;
987 }
988
989 video_num_skipped++;
990 break;
991 }
992
993 default:
994 break;
995 }
996
997 rb->yield();
998 } /* end while */
999
1000video_exit:
1001 vo_cleanup();
1002 mpeg2_close(td.mpeg2dec);
1003}
1004
1005/* Initializes the video thread */
1006bool video_thread_init(void)
1007{
1008 intptr_t rep;
1009
1010 IF_COP(rb->commit_dcache());
1011
1012 video_str.hdr.q = &video_str_queue;
1013 rb->queue_init(video_str.hdr.q, false);
1014
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));
1019
1020 rb->queue_enable_queue_send(video_str.hdr.q, &video_str_queue_send,
1021 video_str.thread);
1022
1023 if (video_str.thread == 0)
1024 return false;
1025
1026 /* Wait for thread to initialize */
1027 rep = str_send_msg(&video_str, STREAM_NULL, 0);
1028 IF_COP(rb->commit_discard_dcache());
1029
1030 return rep == 0; /* Normally STREAM_NULL should be ignored */
1031}
1032
1033/* Terminates the video thread */
1034void video_thread_exit(void)
1035{
1036 if (video_str.thread != 0)
1037 {
1038 str_post_msg(&video_str, STREAM_QUIT, 0);
1039 rb->thread_wait(video_str.thread);
1040 IF_COP(rb->commit_discard_dcache());
1041 video_str.thread = 0;
1042 }
1043}
1044
1045
1046/** Misc **/
1047void video_thread_get_stats(struct video_output_stats *s)
1048{
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;
1053
1054 s->fps = 0;
1055
1056 if (now > start)
1057 s->fps = muldiv_uint32(CLOCK_RATE*100, s->num_drawn, now - start);
1058}
1059