| 425 | void DVDRingBufferPriv::SkipStillFrame(void) |
| 426 | { |
| 427 | dvdnav_still_skip(dvdnav); |
| 428 | cellHasStillFrame = false; |
| 429 | } |
| 430 | |
| 431 | void DVDRingBufferPriv::DVDWaitSkip(void) |
| 432 | { |
| 433 | dvdnav_wait_skip(dvdnav); |
| 434 | dvdWaiting = false; |
| 435 | } |
| 436 | |
| 437 | void DVDRingBufferPriv::GoToRootMenu(void) |
| 438 | { |
| 439 | dvdnav_menu_call(dvdnav,DVD_MENU_Root); |
| 440 | } |
| 441 | |
| 442 | void DVDRingBufferPriv::GoToNextProgram(void) |
| 443 | { |
| 444 | // if not in the menu feature, okay to skip allow to skip it. |
| 445 | // if (!dvdnav_is_domain_vts(dvdnav)) |
| 446 | dvdnav_next_pg_search(dvdnav); |
| 447 | } |
| 448 | |
| 449 | void DVDRingBufferPriv::GoToPreviousProgram(void) |
| 450 | { |
| 451 | // if (!dvdnav_is_domain_vts(dvdnav)) |
| 452 | dvdnav_prev_pg_search(dvdnav); |
| 453 | } |
| 454 | |
| 455 | void DVDRingBufferPriv::MoveDVDButtonLeft(void) |
| 456 | { |
| 457 | if (IsInMenu() && (NumMenuButtons() > 0)) |
| 458 | { |
| 459 | pci_t *pci = dvdnav_get_current_nav_pci(dvdnav); |
| 460 | dvdnav_left_button_select(dvdnav, pci); |
| 461 | } |
| 462 | } |
| 463 | |
| 464 | void DVDRingBufferPriv::MoveDVDButtonRight(void) |
| 465 | { |
| 466 | if (IsInMenu() &&(NumMenuButtons() > 0) ) |
| 467 | { |
| 468 | pci_t *pci = dvdnav_get_current_nav_pci(dvdnav); |
| 469 | dvdnav_right_button_select(dvdnav, pci); |
| 470 | } |
| 471 | } |
| 472 | |
| 473 | void DVDRingBufferPriv::MoveDVDButtonUp(void) |
| 474 | { |
| 475 | if (IsInMenu() && (NumMenuButtons() > 0)) |
| 476 | { |
| 477 | pci_t *pci = dvdnav_get_current_nav_pci(dvdnav); |
| 478 | dvdnav_upper_button_select(dvdnav, pci); |
| 479 | } |
| 480 | } |
| 481 | |
| 482 | void DVDRingBufferPriv::MoveDVDButtonDown(void) |
| 483 | { |
| 484 | if (IsInMenu() && (NumMenuButtons() > 0)) |
| 485 | { |
| 486 | pci_t *pci = dvdnav_get_current_nav_pci(dvdnav); |
| 487 | dvdnav_lower_button_select(dvdnav, pci); |
| 488 | } |
| 489 | } |
| 490 | |
| 491 | void DVDRingBufferPriv::ActivateDVDButton(void) |
| 492 | { |
| 493 | if (IsInMenu() && (NumMenuButtons() > 0)) |
| 494 | { |
| 495 | pci_t *pci = dvdnav_get_current_nav_pci(dvdnav); |
| 496 | dvdnav_button_activate(dvdnav, pci); |
| 497 | } |
| 498 | } |
| 499 | |
| 500 | void DVDRingBufferPriv::GetMenuSPUPkt(uint8_t *buf, int buf_size) |
| 501 | { |
| 502 | if (buf_size < 4) |
| 503 | return; |
| 504 | |
| 505 | if (buf_size == menuBuflength) |
| 506 | return; |
| 507 | else if (spuStreamLetterbox) |
| 508 | { |
| 509 | if ((buf_size < menuBuflength) && menuBuflength > 0) |
| 510 | return; |
| 511 | } |
| 512 | else |
| 513 | { |
| 514 | if ((buf_size > menuBuflength) && (menuBuflength > 0)) |
| 515 | return; |
| 516 | } |
| 517 | ClearMenuSPUParameters(); |
| 518 | |
| 519 | uint8_t *spu_pkt; |
| 520 | spu_pkt = (uint8_t*)av_malloc(buf_size); |
| 521 | memcpy(spu_pkt, buf, buf_size); |
| 522 | menuSpuPkt = spu_pkt; |
| 523 | menuBuflength = buf_size; |
| 524 | buttonCoords = 0; |
| 525 | |
| 526 | if (DVDButtonUpdate(false)) |
| 527 | buttonExists = DrawMenuButton(menuSpuPkt,menuBuflength); |
| 528 | } |
| 529 | |
| 530 | AVSubtitleRect *DVDRingBufferPriv::GetMenuButton(void) |
| 531 | { |
| 532 | if (MenuButtonChanged() && buttonExists) |
| 533 | return dvdMenuButton; |
| 534 | |
| 535 | return NULL; |
| 536 | } |
| 537 | |
| 538 | |
| 539 | bool DVDRingBufferPriv::DrawMenuButton(uint8_t *spu_pkt, int buf_size) |
| 540 | { |
| 541 | #define GETBE16(p) (((p)[0] << 8) | (p)[1]) |
| 542 | |
| 543 | int cmd_pos, pos,cmd,next_cmd_pos,offset1,offset2; |
| 544 | int x1,x2,y1,y2; |
| 545 | uint8_t alpha[4],palette[4]; |
| 546 | |
| 547 | x1 = x2 = y1 = y2 = 0; |
| 548 | |
| 549 | if (!spu_pkt) |
| 550 | return false; |
| 551 | |
| 552 | for (int i = 0; i < 4 ; i++) |
| 553 | { |
| 554 | alpha[i] = button_alpha[i]; |
| 555 | palette[i] = button_color[i]; |
| 556 | } |
| 557 | |
| 558 | if (buf_size < 4) |
| 559 | return false; |
| 560 | |
| 561 | cmd_pos = GETBE16(spu_pkt + 2); |
| 562 | while ((cmd_pos + 4) < buf_size) |
| 563 | { |
| 564 | offset1 = -1; |
| 565 | offset2 = -1; |
| 566 | next_cmd_pos = GETBE16(spu_pkt + cmd_pos + 2); |
| 567 | pos = cmd_pos + 4; |
| 568 | while (pos < buf_size) |
| 569 | { |
| 570 | cmd = spu_pkt[pos++]; |
| 571 | switch(cmd) |
| 572 | { |
| 573 | case 0x00: |
| 574 | break; |
| 575 | case 0x01: |
| 576 | break; |
| 577 | case 0x02: |
| 578 | break; |
| 579 | case 0x03: |
| 580 | { |
| 581 | if ((buf_size - pos) < 2) |
| 582 | goto fail; |
| 583 | pos +=2; |
| 584 | } |
| 585 | break; |
| 586 | case 0x04: |
| 587 | { |
| 588 | if ((buf_size - pos) < 2) |
| 589 | goto fail; |
| 590 | pos +=2; |
| 591 | } |
| 592 | break; |
| 593 | case 0x05: |
| 594 | { |
| 595 | if ((buf_size - pos) < 6) |
| 596 | goto fail; |
| 597 | x1 = (spu_pkt[pos] << 4) | (spu_pkt[pos + 1] >> 4); |
| 598 | x2 = ((spu_pkt[pos + 1] & 0x0f) << 8) | spu_pkt[pos + 2]; |
| 599 | y1 = (spu_pkt[pos + 3] << 4) | (spu_pkt[pos + 4] >> 4); |
| 600 | y2 = ((spu_pkt[pos + 4] & 0x0f) << 8) | spu_pkt[pos + 5]; |
| 601 | pos +=6; |
| 602 | } |
| 603 | break; |
| 604 | case 0x06: |
| 605 | { |
| 606 | if ((buf_size - pos) < 4) |
| 607 | goto fail; |
| 608 | offset1 = GETBE16(spu_pkt + pos); |
| 609 | offset2 = GETBE16(spu_pkt + pos + 2); |
| 610 | pos +=4; |
| 611 | } |
| 612 | break; |
| 613 | case 0xff: |
| 614 | default: |
| 615 | goto the_end; |
| 616 | } |
| 617 | } |
| 618 | the_end: |
| 619 | if (offset1 >= 0) |
| 620 | { |
| 621 | int w, h; |
| 622 | uint8_t *bitmap; |
| 623 | w = x2 - x1 + 1; |
| 624 | if (w < 0) |
| 625 | w = 0; |
| 626 | h = y2 - y1; |
| 627 | if (h < 0) |
| 628 | h = 0; |
| 629 | if (w > 0 && h > 0) |
| 630 | { |
| 631 | bitmap = (uint8_t*) av_malloc(w * h); |
| 632 | dvdMenuButton->rgba_palette = (uint32_t*)av_malloc(4 *4); |
| 633 | decode_rle(bitmap, w * 2, w, h / 2, |
| 634 | spu_pkt, offset1 * 2, buf_size); |
| 635 | decode_rle(bitmap + w, w * 2, w, h / 2, |
| 636 | spu_pkt, offset2 * 2, buf_size); |
| 637 | guess_palette(dvdMenuButton->rgba_palette, palette, alpha); |
| 638 | dvdMenuButton->bitmap = bitmap; |
| 639 | dvdMenuButton->x = hl_startx - x1; |
| 640 | dvdMenuButton->y = hl_starty - y1; |
| 641 | dvdMenuButton->w = hl_width; |
| 642 | dvdMenuButton->h = hl_height; |
| 643 | dvdMenuButton->nb_colors = 4; |
| 644 | dvdMenuButton->linesize = w; |
| 645 | return true; |
| 646 | } |
| 647 | } |
| 648 | if (next_cmd_pos == cmd_pos) |
| 649 | break; |
| 650 | cmd_pos = next_cmd_pos; |
| 651 | } |
| 652 | fail: |
| 653 | return false; |
| 654 | } |
| 655 | |
| 656 | bool DVDRingBufferPriv::DVDButtonUpdate(bool b_mode) |
| 657 | { |
| 658 | int32_t button; |
| 659 | pci_t *pci; |
| 660 | dvdnav_highlight_area_t hl; |
| 661 | dvdnav_get_current_highlight(dvdnav, &button); |
| 662 | |
| 663 | pci = dvdnav_get_current_nav_pci(dvdnav); |
| 664 | dvdnav_get_highlight_area(pci,button, b_mode, &hl); |
| 665 | |
| 666 | for (int i = 0 ; i < 4 ; i++) |
| 667 | { |
| 668 | button_alpha[i] = 0xf & (hl.palette >> (4 * i )); |
| 669 | button_color[i] = 0xf & (hl.palette >> (16+4 *i )); |
| 670 | } |
| 671 | |
| 672 | hl_startx = hl.sx; |
| 673 | hl_width = hl.ex - hl.sx; |
| 674 | hl_starty = hl.sy; |
| 675 | hl_height = hl.ey - hl.sy; |
| 676 | |
| 677 | int total_start_pos = hl.sx + hl.sy; |
| 678 | if ( total_start_pos == 0 || total_start_pos > (720 + 480 )) |
| 679 | return false; |
| 680 | |
| 681 | return true; |
| 682 | } |
| 683 | |
| 684 | void DVDRingBufferPriv::ClearMenuSPUParameters(void) |
| 685 | { |
| 686 | if (menuBuflength == 0) |
| 687 | return; |
| 688 | |
| 689 | VERBOSE(VB_PLAYBACK,"Clearing Menu SPU Packet" ); |
| 690 | if (buttonExists) |
| 691 | { |
| 692 | av_free(dvdMenuButton->rgba_palette); |
| 693 | av_free(dvdMenuButton->bitmap); |
| 694 | buttonExists = false; |
| 695 | } |
| 696 | av_free(menuSpuPkt); |
| 697 | menuBuflength = 0; |
| 698 | dvdMenuButton->x = 0; |
| 699 | dvdMenuButton->y = 0; |
| 700 | hl_startx = hl_starty = 0; |
| 701 | hl_width = hl_height = 0; |
| 702 | buttonCoords = (720+480+100); |
| 703 | } |
| 704 | |
| 705 | bool DVDRingBufferPriv::MenuButtonChanged(void) |
| 706 | { |
| 707 | if (menuBuflength < 4 || buttonCoords > (720+576)) |
| 708 | return false; |
| 709 | |
| 710 | int x = dvdMenuButton->x; |
| 711 | int y = dvdMenuButton->y; |
| 712 | if (buttonCoords != (x+y)) |
| 713 | { |
| 714 | buttonCoords = (x+y); |
| 715 | return true; |
| 716 | } |
| 717 | return false; |
| 718 | } |
| 719 | |
| 720 | int DVDRingBufferPriv::NumMenuButtons(void) |
| 721 | { |
| 722 | pci_t *pci = dvdnav_get_current_nav_pci(dvdnav); |
| 723 | int numButtons = pci->hli.hl_gi.btn_ns; |
| 724 | if (numButtons > 0 && numButtons < 36) |
| 725 | return numButtons; |
| 726 | else |
| 727 | return 0; |
| 728 | } |
| 729 | |
| 730 | void DVDRingBufferPriv::HideMenuButton(bool hide) |
| 731 | { |
| 732 | if (hide) |
| 733 | buttonCoords = (720+480+100); |
| 734 | else |
| 735 | buttonCoords = 0; |
| 736 | } |
| 737 | |
| 738 | uint DVDRingBufferPriv::GetCurrentTime(void) |
| 739 | { |
| 740 | // Macro to convert Binary Coded Decimal to Decimal |
| 741 | // Obtained from VLC Code. |
| 742 | #define BCD2D(__x__) (((__x__ & 0xf0) >> 4) * 10 + (__x__ & 0x0f)) |
| 743 | |
| 744 | dsi_t *dvdnavDsi = dvdnav_get_current_nav_dsi(dvdnav); |
| 745 | dvd_time_t timeFromCellStart = dvdnavDsi->dsi_gi.c_eltm; |
| 746 | uint8_t hours = BCD2D(timeFromCellStart.hour); |
| 747 | uint8_t minutes = BCD2D(timeFromCellStart.minute); |
| 748 | uint8_t seconds = BCD2D(timeFromCellStart.second); |
| 749 | uint currentTime = GetCellStart() + (hours * 3600) + (minutes * 60) + seconds; |
| 750 | VERBOSE(VB_PLAYBACK,QString("cellStartTime == %1 current time: hours %2 minutes" |
| 751 | "%3 seconds %4 currenttime %5").arg(GetCellStart()).arg(hours). |
| 752 | arg(minutes).arg(seconds).arg(currentTime)); |
| 753 | return currentTime; |
| 754 | } |
| 755 | |
| 756 | uint DVDRingBufferPriv::GetAudioLanguage(int id) |
| 757 | { |
| 758 | int8_t channel = dvdnav_get_audio_logical_stream(dvdnav,id); |
| 759 | uint16_t lang = 0; |
| 760 | if (channel != -1) |
| 761 | lang = dvdnav_audio_stream_to_lang(dvdnav,channel); |
| 762 | return ConvertLangCode(lang); |
| 763 | } |
| 764 | |
| 765 | uint DVDRingBufferPriv::GetSubtitleLanguage(int id) |
| 766 | { |
| 767 | int8_t channel = dvdnav_get_spu_logical_stream(dvdnav,id); |
| 768 | uint16_t lang = 0; |
| 769 | if (channel != -1) |
| 770 | lang = dvdnav_spu_stream_to_lang(dvdnav,channel); |
| 771 | return ConvertLangCode(lang); |
| 772 | } |
| 773 | |
| 774 | uint DVDRingBufferPriv::ConvertLangCode(uint16_t code) |
| 775 | { |
| 776 | if (code == 0) |
| 777 | return 0; |
| 778 | |
| 779 | QChar str2[2]; |
| 780 | str2[0] = QChar(code >> 8); |
| 781 | str2[1] = QChar(code & 0xff); |
| 782 | QString str3 = iso639_str2_to_str3(QString(str2,2)); |
| 783 | if (str3) |
| 784 | return iso639_str3_to_key(str3); |
| 785 | return 0; |
| 786 | } |
| 787 | |
| 788 | void DVDRingBufferPriv::guess_palette(uint32_t *rgba_palette,uint8_t *palette, |
| 789 | uint8_t *alpha) |
| 790 | { |
| 791 | int i,r,g,b,y,cr,cb; |
| 792 | uint32_t yuv; |
| 793 | |
| 794 | for(i = 0; i < 4; i++) |
| 795 | rgba_palette[i] = 0; |
| 796 | |
| 797 | for ( i=0 ; i < 4 ; i++) |
| 798 | { |
| 799 | yuv = clut[palette[i]]; |
| 800 | y = ((yuv >> 16) & 0xff); |
| 801 | cr = ((yuv >> 8) & 0xff); |
| 802 | cb = ((yuv >> 0) & 0xff); |
| 803 | r = int(y + 1.4022 * (cr - 128)); |
| 804 | b = int(y + 1.7710 * (cb - 128)); |
| 805 | g = int(1.7047 * y - (0.1952 * b) - (0.5647 * r)) ; |
| 806 | if (r < 0) r = 0; |
| 807 | if (g < 0) g = 0; |
| 808 | if (b < 0) b = 0; |
| 809 | if (r > 0xff) r = 0xff; |
| 810 | if (g > 0xff) g = 0xff; |
| 811 | if (b > 0xff) b = 0xff; |
| 812 | rgba_palette[i] = ((alpha[i] * 17) << 24) | (r << 16 )| (g << 8) | b; |
| 813 | } |
| 814 | } |
| 815 | |
| 816 | int DVDRingBufferPriv::decode_rle(uint8_t *bitmap, int linesize, int w, int h, |
| 817 | const uint8_t *buf, int nibble_offset, int buf_size) |
| 818 | { |
| 819 | unsigned int v; |
| 820 | int x, y, len, color, nibble_end; |
| 821 | uint8_t *d; |
| 822 | |
| 823 | nibble_end = buf_size * 2; |
| 824 | x = 0; |
| 825 | y = 0; |
| 826 | d = bitmap; |
| 827 | for(;;) { |
| 828 | if (nibble_offset >= nibble_end) |
| 829 | return -1; |
| 830 | v = get_nibble(buf, nibble_offset++); |
| 831 | if (v < 0x4) { |
| 832 | v = (v << 4) | get_nibble(buf, nibble_offset++); |
| 833 | if (v < 0x10) { |
| 834 | v = (v << 4) | get_nibble(buf, nibble_offset++); |
| 835 | if (v < 0x040) { |
| 836 | v = (v << 4) | get_nibble(buf, nibble_offset++); |
| 837 | if (v < 4) { |
| 838 | v |= (w - x) << 2; |
| 839 | } |
| 840 | } |
| 841 | } |
| 842 | } |
| 843 | len = v >> 2; |
| 844 | if (len > (w - x)) |
| 845 | len = (w - x); |
| 846 | color = v & 0x03; |
| 847 | memset(d + x, color, len); |
| 848 | x += len; |
| 849 | if (x >= w) { |
| 850 | y++; |
| 851 | if (y >= h) |
| 852 | break; |
| 853 | d += linesize; |
| 854 | x = 0; |
| 855 | /* byte align */ |
| 856 | nibble_offset += (nibble_offset & 1); |
| 857 | } |
| 858 | } |
| 859 | return 0; |
| 860 | } |
| 861 | |
| 862 | int DVDRingBufferPriv::get_nibble(const uint8_t *buf, int nibble_offset) |
| 863 | { |
| 864 | return (buf[nibble_offset >> 1] >> ((1 - (nibble_offset & 1)) << 2)) & 0xf; |
| 865 | } |
| 866 | |
| 867 | |