Mercurial > libavcodec.hg
comparison interplayvideo.c @ 10719:cc2f80bbf304 libavcodec
Add missing opcodes for 16-bit Interplay Video decoding and finally enable it
| author | kostya |
|---|---|
| date | Sun, 27 Dec 2009 09:12:50 +0000 |
| parents | 1b91df81bda4 |
| children | bcc62edd9b41 |
comparison
equal
deleted
inserted
replaced
| 10718:1b91df81bda4 | 10719:cc2f80bbf304 |
|---|---|
| 571 | 571 |
| 572 /* report success */ | 572 /* report success */ |
| 573 return 0; | 573 return 0; |
| 574 } | 574 } |
| 575 | 575 |
| 576 static int ipvideo_decode_block_opcode_0x6_16(IpvideoContext *s) | |
| 577 { | |
| 578 signed char x, y; | |
| 579 | |
| 580 /* copy a block from the second last frame using an expanded range */ | |
| 581 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); | |
| 582 | |
| 583 x = *s->stream_ptr++; | |
| 584 y = *s->stream_ptr++; | |
| 585 | |
| 586 debug_interplay (" motion bytes = %d, %d\n", x, y); | |
| 587 return copy_from(s, &s->second_last_frame, x, y); | |
| 588 } | |
| 589 | |
| 590 static int ipvideo_decode_block_opcode_0x7_16(IpvideoContext *s) | |
| 591 { | |
| 592 int x, y; | |
| 593 uint16_t P[2]; | |
| 594 unsigned int flags; | |
| 595 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; | |
| 596 | |
| 597 /* 2-color encoding */ | |
| 598 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); | |
| 599 | |
| 600 P[0] = bytestream_get_le16(&s->stream_ptr); | |
| 601 P[1] = bytestream_get_le16(&s->stream_ptr); | |
| 602 | |
| 603 if (!(P[0] & 0x8000)) { | |
| 604 | |
| 605 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); | |
| 606 | |
| 607 for (y = 0; y < 8; y++) { | |
| 608 flags = *s->stream_ptr++ | 0x100; | |
| 609 for (; flags != 1; flags >>= 1) | |
| 610 *pixel_ptr++ = P[flags & 1]; | |
| 611 pixel_ptr += s->line_inc; | |
| 612 } | |
| 613 | |
| 614 } else { | |
| 615 | |
| 616 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); | |
| 617 | |
| 618 flags = bytestream_get_le16(&s->stream_ptr); | |
| 619 for (y = 0; y < 8; y += 2) { | |
| 620 for (x = 0; x < 8; x += 2, flags >>= 1) { | |
| 621 pixel_ptr[x ] = | |
| 622 pixel_ptr[x + 1 ] = | |
| 623 pixel_ptr[x + s->stride] = | |
| 624 pixel_ptr[x + 1 + s->stride] = P[flags & 1]; | |
| 625 } | |
| 626 pixel_ptr += s->stride * 2; | |
| 627 } | |
| 628 } | |
| 629 | |
| 630 return 0; | |
| 631 } | |
| 632 | |
| 633 static int ipvideo_decode_block_opcode_0x8_16(IpvideoContext *s) | |
| 634 { | |
| 635 int x, y; | |
| 636 uint16_t P[2]; | |
| 637 unsigned int flags = 0; | |
| 638 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; | |
| 639 | |
| 640 /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on | |
| 641 * either top and bottom or left and right halves */ | |
| 642 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); | |
| 643 | |
| 644 P[0] = bytestream_get_le16(&s->stream_ptr); | |
| 645 P[1] = bytestream_get_le16(&s->stream_ptr); | |
| 646 | |
| 647 if (!(P[0] & 0x8000)) { | |
| 648 | |
| 649 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24); | |
| 650 s->stream_ptr -= 4; | |
| 651 | |
| 652 for (y = 0; y < 16; y++) { | |
| 653 // new values for each 4x4 block | |
| 654 if (!(y & 3)) { | |
| 655 P[0] = bytestream_get_le16(&s->stream_ptr); | |
| 656 P[1] = bytestream_get_le16(&s->stream_ptr); | |
| 657 flags = bytestream_get_le16(&s->stream_ptr); | |
| 658 } | |
| 659 | |
| 660 for (x = 0; x < 4; x++, flags >>= 1) | |
| 661 *pixel_ptr++ = P[flags & 1]; | |
| 662 pixel_ptr += s->stride - 4; | |
| 663 // switch to right half | |
| 664 if (y == 7) pixel_ptr -= 8 * s->stride - 4; | |
| 665 } | |
| 666 | |
| 667 } else { | |
| 668 | |
| 669 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 12); | |
| 670 | |
| 671 if (!(AV_RL16(s->stream_ptr + 4) & 0x8000)) { | |
| 672 | |
| 673 flags = bytestream_get_le32(&s->stream_ptr); | |
| 674 | |
| 675 /* vertical split; left & right halves are 2-color encoded */ | |
| 676 | |
| 677 for (y = 0; y < 16; y++) { | |
| 678 for (x = 0; x < 4; x++, flags >>= 1) | |
| 679 *pixel_ptr++ = P[flags & 1]; | |
| 680 pixel_ptr += s->stride - 4; | |
| 681 // switch to right half | |
| 682 if (y == 7) { | |
| 683 pixel_ptr -= 8 * s->stride - 4; | |
| 684 P[0] = bytestream_get_le16(&s->stream_ptr); | |
| 685 P[1] = bytestream_get_le16(&s->stream_ptr); | |
| 686 flags = bytestream_get_le32(&s->stream_ptr); | |
| 687 } | |
| 688 } | |
| 689 | |
| 690 } else { | |
| 691 | |
| 692 /* horizontal split; top & bottom halves are 2-color encoded */ | |
| 693 | |
| 694 for (y = 0; y < 8; y++) { | |
| 695 if (y == 4) { | |
| 696 P[0] = bytestream_get_le16(&s->stream_ptr); | |
| 697 P[1] = bytestream_get_le16(&s->stream_ptr); | |
| 698 } | |
| 699 flags = *s->stream_ptr++ | 0x100; | |
| 700 | |
| 701 for (; flags != 1; flags >>= 1) | |
| 702 *pixel_ptr++ = P[flags & 1]; | |
| 703 pixel_ptr += s->line_inc; | |
| 704 } | |
| 705 } | |
| 706 } | |
| 707 | |
| 708 /* report success */ | |
| 709 return 0; | |
| 710 } | |
| 711 | |
| 712 static int ipvideo_decode_block_opcode_0x9_16(IpvideoContext *s) | |
| 713 { | |
| 714 int x, y; | |
| 715 uint16_t P[4]; | |
| 716 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; | |
| 717 | |
| 718 /* 4-color encoding */ | |
| 719 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); | |
| 720 | |
| 721 for (x = 0; x < 4; x++) | |
| 722 P[x] = bytestream_get_le16(&s->stream_ptr); | |
| 723 | |
| 724 if (!(P[0] & 0x8000)) { | |
| 725 if (!(P[2] & 0x8000)) { | |
| 726 | |
| 727 /* 1 of 4 colors for each pixel */ | |
| 728 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16); | |
| 729 | |
| 730 for (y = 0; y < 8; y++) { | |
| 731 /* get the next set of 8 2-bit flags */ | |
| 732 int flags = bytestream_get_le16(&s->stream_ptr); | |
| 733 for (x = 0; x < 8; x++, flags >>= 2) | |
| 734 *pixel_ptr++ = P[flags & 0x03]; | |
| 735 pixel_ptr += s->line_inc; | |
| 736 } | |
| 737 | |
| 738 } else { | |
| 739 uint32_t flags; | |
| 740 | |
| 741 /* 1 of 4 colors for each 2x2 block */ | |
| 742 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); | |
| 743 | |
| 744 flags = bytestream_get_le32(&s->stream_ptr); | |
| 745 | |
| 746 for (y = 0; y < 8; y += 2) { | |
| 747 for (x = 0; x < 8; x += 2, flags >>= 2) { | |
| 748 pixel_ptr[x ] = | |
| 749 pixel_ptr[x + 1 ] = | |
| 750 pixel_ptr[x + s->stride] = | |
| 751 pixel_ptr[x + 1 + s->stride] = P[flags & 0x03]; | |
| 752 } | |
| 753 pixel_ptr += s->stride * 2; | |
| 754 } | |
| 755 | |
| 756 } | |
| 757 } else { | |
| 758 uint64_t flags; | |
| 759 | |
| 760 /* 1 of 4 colors for each 2x1 or 1x2 block */ | |
| 761 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); | |
| 762 | |
| 763 flags = bytestream_get_le64(&s->stream_ptr); | |
| 764 if (!(P[2] & 0x8000)) { | |
| 765 for (y = 0; y < 8; y++) { | |
| 766 for (x = 0; x < 8; x += 2, flags >>= 2) { | |
| 767 pixel_ptr[x ] = | |
| 768 pixel_ptr[x + 1] = P[flags & 0x03]; | |
| 769 } | |
| 770 pixel_ptr += s->stride; | |
| 771 } | |
| 772 } else { | |
| 773 for (y = 0; y < 8; y += 2) { | |
| 774 for (x = 0; x < 8; x++, flags >>= 2) { | |
| 775 pixel_ptr[x ] = | |
| 776 pixel_ptr[x + s->stride] = P[flags & 0x03]; | |
| 777 } | |
| 778 pixel_ptr += s->stride * 2; | |
| 779 } | |
| 780 } | |
| 781 } | |
| 782 | |
| 783 /* report success */ | |
| 784 return 0; | |
| 785 } | |
| 786 | |
| 787 static int ipvideo_decode_block_opcode_0xA_16(IpvideoContext *s) | |
| 788 { | |
| 789 int x, y; | |
| 790 uint16_t P[4]; | |
| 791 int flags = 0; | |
| 792 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; | |
| 793 | |
| 794 /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on | |
| 795 * either top and bottom or left and right halves */ | |
| 796 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24); | |
| 797 | |
| 798 if (!(AV_RL16(s->stream_ptr) & 0x8000)) { | |
| 799 | |
| 800 /* 4-color encoding for each quadrant */ | |
| 801 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 48); | |
| 802 | |
| 803 for (y = 0; y < 16; y++) { | |
| 804 // new values for each 4x4 block | |
| 805 if (!(y & 3)) { | |
| 806 for (x = 0; x < 4; x++) | |
| 807 P[x] = bytestream_get_le16(&s->stream_ptr); | |
| 808 flags = bytestream_get_le32(&s->stream_ptr); | |
| 809 } | |
| 810 | |
| 811 for (x = 0; x < 4; x++, flags >>= 2) | |
| 812 *pixel_ptr++ = P[flags & 0x03]; | |
| 813 | |
| 814 pixel_ptr += s->stride - 4; | |
| 815 // switch to right half | |
| 816 if (y == 7) pixel_ptr -= 8 * s->stride - 4; | |
| 817 } | |
| 818 | |
| 819 } else { | |
| 820 // vertical split? | |
| 821 int vert = !(AV_RL16(s->stream_ptr + 16) & 0x8000); | |
| 822 uint64_t flags = 0; | |
| 823 | |
| 824 /* 4-color encoding for either left and right or top and bottom | |
| 825 * halves */ | |
| 826 | |
| 827 for (y = 0; y < 16; y++) { | |
| 828 // load values for each half | |
| 829 if (!(y & 7)) { | |
| 830 for (x = 0; x < 4; x++) | |
| 831 P[x] = bytestream_get_le16(&s->stream_ptr); | |
| 832 flags = bytestream_get_le64(&s->stream_ptr); | |
| 833 } | |
| 834 | |
| 835 for (x = 0; x < 4; x++, flags >>= 2) | |
| 836 *pixel_ptr++ = P[flags & 0x03]; | |
| 837 | |
| 838 if (vert) { | |
| 839 pixel_ptr += s->stride - 4; | |
| 840 // switch to right half | |
| 841 if (y == 7) pixel_ptr -= 8 * s->stride - 4; | |
| 842 } else if (y & 1) pixel_ptr += s->line_inc; | |
| 843 } | |
| 844 } | |
| 845 | |
| 846 /* report success */ | |
| 847 return 0; | |
| 848 } | |
| 849 | |
| 850 static int ipvideo_decode_block_opcode_0xB_16(IpvideoContext *s) | |
| 851 { | |
| 852 int x, y; | |
| 853 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; | |
| 854 | |
| 855 /* 64-color encoding (each pixel in block is a different color) */ | |
| 856 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 128); | |
| 857 | |
| 858 for (y = 0; y < 8; y++) { | |
| 859 for (x = 0; x < 8; x++) | |
| 860 pixel_ptr[x] = bytestream_get_le16(&s->stream_ptr); | |
| 861 pixel_ptr += s->stride; | |
| 862 } | |
| 863 | |
| 864 /* report success */ | |
| 865 return 0; | |
| 866 } | |
| 867 | |
| 868 static int ipvideo_decode_block_opcode_0xC_16(IpvideoContext *s) | |
| 869 { | |
| 870 int x, y; | |
| 871 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; | |
| 872 | |
| 873 /* 16-color block encoding: each 2x2 block is a different color */ | |
| 874 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 32); | |
| 875 | |
| 876 for (y = 0; y < 8; y += 2) { | |
| 877 for (x = 0; x < 8; x += 2) { | |
| 878 pixel_ptr[x ] = | |
| 879 pixel_ptr[x + 1 ] = | |
| 880 pixel_ptr[x + s->stride] = | |
| 881 pixel_ptr[x + 1 + s->stride] = bytestream_get_le16(&s->stream_ptr); | |
| 882 } | |
| 883 pixel_ptr += s->stride * 2; | |
| 884 } | |
| 885 | |
| 886 /* report success */ | |
| 887 return 0; | |
| 888 } | |
| 889 | |
| 890 static int ipvideo_decode_block_opcode_0xD_16(IpvideoContext *s) | |
| 891 { | |
| 892 int x, y; | |
| 893 uint16_t P[2]; | |
| 894 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; | |
| 895 | |
| 896 /* 4-color block encoding: each 4x4 block is a different color */ | |
| 897 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); | |
| 898 | |
| 899 for (y = 0; y < 8; y++) { | |
| 900 if (!(y & 3)) { | |
| 901 P[0] = bytestream_get_le16(&s->stream_ptr); | |
| 902 P[1] = bytestream_get_le16(&s->stream_ptr); | |
| 903 } | |
| 904 for (x = 0; x < 8; x++) | |
| 905 pixel_ptr[x] = P[x >> 2]; | |
| 906 pixel_ptr += s->stride; | |
| 907 } | |
| 908 | |
| 909 /* report success */ | |
| 910 return 0; | |
| 911 } | |
| 912 | |
| 913 static int ipvideo_decode_block_opcode_0xE_16(IpvideoContext *s) | |
| 914 { | |
| 915 int x, y; | |
| 916 uint16_t pix; | |
| 917 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; | |
| 918 | |
| 919 /* 1-color encoding: the whole block is 1 solid color */ | |
| 920 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); | |
| 921 pix = bytestream_get_le16(&s->stream_ptr); | |
| 922 | |
| 923 for (y = 0; y < 8; y++) { | |
| 924 for (x = 0; x < 8; x++) | |
| 925 pixel_ptr[x] = pix; | |
| 926 pixel_ptr += s->stride; | |
| 927 } | |
| 928 | |
| 929 /* report success */ | |
| 930 return 0; | |
| 931 } | |
| 932 | |
| 576 static int (* const ipvideo_decode_block[])(IpvideoContext *s) = { | 933 static int (* const ipvideo_decode_block[])(IpvideoContext *s) = { |
| 577 ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1, | 934 ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1, |
| 578 ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3, | 935 ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3, |
| 579 ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5, | 936 ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5, |
| 580 ipvideo_decode_block_opcode_0x6, ipvideo_decode_block_opcode_0x7, | 937 ipvideo_decode_block_opcode_0x6, ipvideo_decode_block_opcode_0x7, |
| 582 ipvideo_decode_block_opcode_0xA, ipvideo_decode_block_opcode_0xB, | 939 ipvideo_decode_block_opcode_0xA, ipvideo_decode_block_opcode_0xB, |
| 583 ipvideo_decode_block_opcode_0xC, ipvideo_decode_block_opcode_0xD, | 940 ipvideo_decode_block_opcode_0xC, ipvideo_decode_block_opcode_0xD, |
| 584 ipvideo_decode_block_opcode_0xE, ipvideo_decode_block_opcode_0xF, | 941 ipvideo_decode_block_opcode_0xE, ipvideo_decode_block_opcode_0xF, |
| 585 }; | 942 }; |
| 586 | 943 |
| 944 static int (* const ipvideo_decode_block16[])(IpvideoContext *s) = { | |
| 945 ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1, | |
| 946 ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3, | |
| 947 ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5, | |
| 948 ipvideo_decode_block_opcode_0x6_16, ipvideo_decode_block_opcode_0x7_16, | |
| 949 ipvideo_decode_block_opcode_0x8_16, ipvideo_decode_block_opcode_0x9_16, | |
| 950 ipvideo_decode_block_opcode_0xA_16, ipvideo_decode_block_opcode_0xB_16, | |
| 951 ipvideo_decode_block_opcode_0xC_16, ipvideo_decode_block_opcode_0xD_16, | |
| 952 ipvideo_decode_block_opcode_0xE_16, ipvideo_decode_block_opcode_0x1, | |
| 953 }; | |
| 954 | |
| 587 static void ipvideo_decode_opcodes(IpvideoContext *s) | 955 static void ipvideo_decode_opcodes(IpvideoContext *s) |
| 588 { | 956 { |
| 589 int x, y; | 957 int x, y; |
| 590 unsigned char opcode; | 958 unsigned char opcode; |
| 591 int ret; | 959 int ret; |
| 626 + y*s->current_frame.linesize[0]; | 994 + y*s->current_frame.linesize[0]; |
| 627 ret = ipvideo_decode_block[opcode](s); | 995 ret = ipvideo_decode_block[opcode](s); |
| 628 } else { | 996 } else { |
| 629 s->pixel_ptr = s->current_frame.data[0] + x*2 | 997 s->pixel_ptr = s->current_frame.data[0] + x*2 |
| 630 + y*s->current_frame.linesize[0]; | 998 + y*s->current_frame.linesize[0]; |
| 999 ret = ipvideo_decode_block16[opcode](s); | |
| 631 } | 1000 } |
| 632 if (ret != 0) { | 1001 if (ret != 0) { |
| 633 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode problem on frame %d, @ block (%d, %d)\n", | 1002 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode problem on frame %d, @ block (%d, %d)\n", |
| 634 frame, x, y); | 1003 frame, x, y); |
| 635 return; | 1004 return; |
| 653 return -1; | 1022 return -1; |
| 654 } | 1023 } |
| 655 | 1024 |
| 656 s->is_16bpp = avctx->bits_per_coded_sample == 16; | 1025 s->is_16bpp = avctx->bits_per_coded_sample == 16; |
| 657 avctx->pix_fmt = s->is_16bpp ? PIX_FMT_RGB555 : PIX_FMT_PAL8; | 1026 avctx->pix_fmt = s->is_16bpp ? PIX_FMT_RGB555 : PIX_FMT_PAL8; |
| 658 if (s->is_16bpp) { | |
| 659 av_log(avctx, AV_LOG_ERROR, "16-bit Interplay video is not supported yet.\n"); | |
| 660 return -1; | |
| 661 } | |
| 662 dsputil_init(&s->dsp, avctx); | 1027 dsputil_init(&s->dsp, avctx); |
| 663 | 1028 |
| 664 /* decoding map contains 4 bits of information per 8x8 block */ | 1029 /* decoding map contains 4 bits of information per 8x8 block */ |
| 665 s->decoding_map_size = avctx->width * avctx->height / (8 * 8 * 2); | 1030 s->decoding_map_size = avctx->width * avctx->height / (8 * 8 * 2); |
| 666 | 1031 |
