A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1059 lines 33 kB view raw
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