1 |
/************************************************************************** |
/***************************************************************************** |
2 |
* |
* |
3 |
* XVID MPEG-4 VIDEO CODEC |
* XVID MPEG-4 VIDEO CODEC |
4 |
* colorspace conversions |
* - colorspace conversion module - |
5 |
|
* |
6 |
|
* Copyright(C) 2002 Peter Ross <pross@xvid.org> |
7 |
|
* |
8 |
|
* This program is an implementation of a part of one or more MPEG-4 |
9 |
|
* Video tools as specified in ISO/IEC 14496-2 standard. Those intending |
10 |
|
* to use this software module in hardware or software products are |
11 |
|
* advised that its use may infringe existing patents or copyrights, and |
12 |
|
* any such use would be at such party's own risk. The original |
13 |
|
* developer of this software module and his/her company, and subsequent |
14 |
|
* editors and their companies, will have no liability for use of this |
15 |
|
* software or modifications or derivatives thereof. |
16 |
* |
* |
17 |
* This program is free software; you can redistribute it and/or modify |
* This program is free software; you can redistribute it and/or modify |
18 |
* it under the terms of the GNU General Public License as published by |
* it under the terms of the GNU General Public License as published by |
26 |
* |
* |
27 |
* You should have received a copy of the GNU General Public License |
* You should have received a copy of the GNU General Public License |
28 |
* along with this program; if not, write to the Free Software |
* along with this program; if not, write to the Free Software |
29 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
30 |
* |
* |
31 |
*************************************************************************/ |
****************************************************************************/ |
|
|
|
|
/************************************************************************** |
|
|
* |
|
|
* History: |
|
|
* |
|
|
* 14.04.2002 added user_to_yuv_c() |
|
|
* 30.02.2002 out_yuv dst_stride2 fix |
|
|
* 26.02.2002 rgb555, rgb565 |
|
|
* 24.11.2001 accuracy improvement to yuyv/vyuy conversion |
|
|
* 28.10.2001 total rewrite <pross@cs.rmit.edu.au> |
|
|
* |
|
|
**************************************************************************/ |
|
32 |
|
|
33 |
#include <string.h> // memcpy |
#include <string.h> // memcpy |
34 |
|
|
51 |
color_outputFuncPtr yv12_to_rgb565; |
color_outputFuncPtr yv12_to_rgb565; |
52 |
color_outputFuncPtr yv12_to_rgb24; |
color_outputFuncPtr yv12_to_rgb24; |
53 |
color_outputFuncPtr yv12_to_rgb32; |
color_outputFuncPtr yv12_to_rgb32; |
|
color_outputFuncPtr yv12_to_abgr; |
|
|
color_outputFuncPtr yv12_to_rgba; |
|
54 |
color_outputFuncPtr yv12_to_yuv; |
color_outputFuncPtr yv12_to_yuv; |
55 |
color_outputFuncPtr yv12_to_yuyv; |
color_outputFuncPtr yv12_to_yuyv; |
56 |
color_outputFuncPtr yv12_to_uyvy; |
color_outputFuncPtr yv12_to_uyvy; |
603 |
int width, |
int width, |
604 |
int height) |
int height) |
605 |
{ |
{ |
606 |
const uint32_t dst_dif = 2 * dst_stride - 2 * width; |
const uint32_t dst_dif = 4 * dst_stride - 2 * width; |
607 |
int32_t y_dif = 2 * y_stride - width; |
int32_t y_dif = 2 * y_stride - width; |
608 |
|
|
609 |
uint8_t *dst2 = dst + dst_stride; |
uint8_t *dst2 = dst + 2 * dst_stride; |
610 |
uint8_t *y_src2 = y_src + y_stride; |
uint8_t *y_src2 = y_src + y_stride; |
611 |
uint32_t x, y; |
uint32_t x, y; |
612 |
|
|
702 |
int width, |
int width, |
703 |
int height) |
int height) |
704 |
{ |
{ |
705 |
const uint32_t dst_dif = 2 * dst_stride - 2 * width; |
const uint32_t dst_dif = 4 * dst_stride - 2 * width; |
706 |
int32_t y_dif = 2 * y_stride - width; |
int32_t y_dif = 2 * y_stride - width; |
707 |
|
|
708 |
uint8_t *dst2 = dst + dst_stride; |
uint8_t *dst2 = dst + 2 * dst_stride; |
709 |
uint8_t *y_src2 = y_src + y_stride; |
uint8_t *y_src2 = y_src + y_stride; |
710 |
uint32_t x, y; |
uint32_t x, y; |
711 |
|
|
782 |
} |
} |
783 |
|
|
784 |
|
|
785 |
#define MAKE_YV12_TO_RGB_C(NAME,SIZE,C1,C2,C3,C4) \ |
|
786 |
void yv12_to_##NAME##_c(uint8_t * dst, \ |
/* yuv 4:2:0 planar -> rgb24 */ |
787 |
int dst_stride, \ |
|
788 |
uint8_t * y_src, \ |
void |
789 |
uint8_t * u_src, \ |
yv12_to_rgb24_c(uint8_t * dst, |
790 |
uint8_t * v_src, \ |
int dst_stride, |
791 |
int y_stride, \ |
uint8_t * y_src, |
792 |
int uv_stride, \ |
uint8_t * u_src, |
793 |
int width, \ |
uint8_t * v_src, |
794 |
int height) \ |
int y_stride, |
795 |
{ \ |
int uv_stride, |
796 |
const uint8_t a = 0; /* alpha = 0 */ \ |
int width, |
797 |
const uint32_t dst_dif = 2 * dst_stride - (SIZE) * width; \ |
int height) |
798 |
int32_t y_dif = 2 * y_stride - width; \ |
{ |
799 |
uint8_t *dst2 = dst + dst_stride; \ |
const uint32_t dst_dif = 6 * dst_stride - 3 * width; |
800 |
uint8_t *y_src2 = y_src + y_stride; \ |
int32_t y_dif = 2 * y_stride - width; |
801 |
uint32_t x, y; \ |
|
802 |
\ |
uint8_t *dst2 = dst + 3 * dst_stride; |
803 |
if (height < 0) { /* flip image? */ \ |
uint8_t *y_src2 = y_src + y_stride; |
804 |
height = -height; \ |
uint32_t x, y; |
805 |
y_src += (height - 1) * y_stride; \ |
|
806 |
y_src2 = y_src - y_stride; \ |
if (height < 0) { // flip image? |
807 |
u_src += (height / 2 - 1) * uv_stride; \ |
height = -height; |
808 |
v_src += (height / 2 - 1) * uv_stride; \ |
y_src += (height - 1) * y_stride; |
809 |
y_dif = -width - 2 * y_stride; \ |
y_src2 = y_src - y_stride; |
810 |
uv_stride = -uv_stride; \ |
u_src += (height / 2 - 1) * uv_stride; |
811 |
} \ |
v_src += (height / 2 - 1) * uv_stride; |
812 |
/* process one 2x2 block per iteration */ \ |
y_dif = -width - 2 * y_stride; |
813 |
for (y = height/2; y; y--) { \ |
uv_stride = -uv_stride; |
814 |
\ |
} |
815 |
for (x = 0; x < (uint32_t)width/2; x++) { \ |
|
816 |
int u, v; \ |
for (y = height / 2; y; y--) { |
817 |
int b_u, g_uv, r_v, rgb_y; \ |
// process one 2x2 block per iteration |
818 |
int r, g, b; \ |
for (x = 0; x < (uint32_t) width / 2; x++) { |
819 |
\ |
int u, v; |
820 |
u = u_src[x]; \ |
int b_u, g_uv, r_v, rgb_y; |
821 |
v = v_src[x]; \ |
int r, g, b; |
822 |
b_u = B_U_tab[u]; \ |
|
823 |
g_uv = G_U_tab[u] + G_V_tab[v]; \ |
u = u_src[x]; |
824 |
r_v = R_V_tab[v]; \ |
v = v_src[x]; |
825 |
\ |
|
826 |
rgb_y = RGB_Y_tab[*y_src]; \ |
b_u = B_U_tab[u]; |
827 |
b = MAX(0, MIN(255, (rgb_y + b_u) >> SCALEBITS_OUT)); \ |
g_uv = G_U_tab[u] + G_V_tab[v]; |
828 |
g = MAX(0, MIN(255, (rgb_y - g_uv) >> SCALEBITS_OUT)); \ |
r_v = R_V_tab[v]; |
829 |
r = MAX(0, MIN(255, (rgb_y + r_v) >> SCALEBITS_OUT)); \ |
|
830 |
dst[0] = (C1); \ |
rgb_y = RGB_Y_tab[*y_src]; |
831 |
dst[1] = (C2); \ |
b = (rgb_y + b_u) >> SCALEBITS_OUT; |
832 |
dst[2] = (C3); \ |
g = (rgb_y - g_uv) >> SCALEBITS_OUT; |
833 |
if ((SIZE)>3) dst[3] = (C4); \ |
r = (rgb_y + r_v) >> SCALEBITS_OUT; |
834 |
y_src++; \ |
dst[0] = MAX(0, MIN(255, b)); |
835 |
\ |
dst[1] = MAX(0, MIN(255, g)); |
836 |
rgb_y = RGB_Y_tab[*y_src]; \ |
dst[2] = MAX(0, MIN(255, r)); |
837 |
b = MAX(0, MIN(255, (rgb_y + b_u) >> SCALEBITS_OUT)); \ |
|
838 |
g = MAX(0, MIN(255, (rgb_y - g_uv) >> SCALEBITS_OUT)); \ |
y_src++; |
839 |
r = MAX(0, MIN(255, (rgb_y + r_v) >> SCALEBITS_OUT)); \ |
rgb_y = RGB_Y_tab[*y_src]; |
840 |
dst[(SIZE)+0] = (C1); \ |
b = (rgb_y + b_u) >> SCALEBITS_OUT; |
841 |
dst[(SIZE)+1] = (C2); \ |
g = (rgb_y - g_uv) >> SCALEBITS_OUT; |
842 |
dst[(SIZE)+2] = (C3); \ |
r = (rgb_y + r_v) >> SCALEBITS_OUT; |
843 |
if ((SIZE)>3) dst[(SIZE)+3] = (C4); \ |
dst[3] = MAX(0, MIN(255, b)); |
844 |
y_src++; \ |
dst[4] = MAX(0, MIN(255, g)); |
845 |
\ |
dst[5] = MAX(0, MIN(255, r)); |
846 |
rgb_y = RGB_Y_tab[*y_src2]; \ |
y_src++; |
847 |
b = MAX(0, MIN(255, (rgb_y + b_u) >> SCALEBITS_OUT)); \ |
|
848 |
g = MAX(0, MIN(255, (rgb_y - g_uv) >> SCALEBITS_OUT)); \ |
rgb_y = RGB_Y_tab[*y_src2]; |
849 |
r = MAX(0, MIN(255, (rgb_y + r_v) >> SCALEBITS_OUT)); \ |
b = (rgb_y + b_u) >> SCALEBITS_OUT; |
850 |
dst2[0] = (C1); \ |
g = (rgb_y - g_uv) >> SCALEBITS_OUT; |
851 |
dst2[1] = (C2); \ |
r = (rgb_y + r_v) >> SCALEBITS_OUT; |
852 |
dst2[2] = (C3); \ |
dst2[0] = MAX(0, MIN(255, b)); |
853 |
if ((SIZE)>3) dst2[3] = (C4); \ |
dst2[1] = MAX(0, MIN(255, g)); |
854 |
y_src2++; \ |
dst2[2] = MAX(0, MIN(255, r)); |
855 |
\ |
y_src2++; |
856 |
rgb_y = RGB_Y_tab[*y_src2]; \ |
|
857 |
b = MAX(0, MIN(255, (rgb_y + b_u) >> SCALEBITS_OUT)); \ |
rgb_y = RGB_Y_tab[*y_src2]; |
858 |
g = MAX(0, MIN(255, (rgb_y - g_uv) >> SCALEBITS_OUT)); \ |
b = (rgb_y + b_u) >> SCALEBITS_OUT; |
859 |
r = MAX(0, MIN(255, (rgb_y + r_v) >> SCALEBITS_OUT)); \ |
g = (rgb_y - g_uv) >> SCALEBITS_OUT; |
860 |
dst2[(SIZE)+0] = (C1); \ |
r = (rgb_y + r_v) >> SCALEBITS_OUT; |
861 |
dst2[(SIZE)+1] = (C2); \ |
dst2[3] = MAX(0, MIN(255, b)); |
862 |
dst2[(SIZE)+2] = (C3); \ |
dst2[4] = MAX(0, MIN(255, g)); |
863 |
if ((SIZE)>3) dst2[(SIZE)+3] = (C4); \ |
dst2[5] = MAX(0, MIN(255, r)); |
864 |
y_src2++; \ |
y_src2++; |
865 |
\ |
|
866 |
dst += 2*(SIZE); \ |
dst += 6; |
867 |
dst2 += 2*(SIZE); \ |
dst2 += 6; |
868 |
} \ |
} |
869 |
dst += dst_dif; \ |
|
870 |
dst2 += dst_dif; \ |
dst += dst_dif; |
871 |
y_src += y_dif; \ |
dst2 += dst_dif; |
872 |
y_src2 += y_dif; \ |
|
873 |
u_src += uv_stride; \ |
y_src += y_dif; |
874 |
v_src += uv_stride; \ |
y_src2 += y_dif; |
875 |
} \ |
|
876 |
} |
u_src += uv_stride; |
877 |
|
v_src += uv_stride; |
878 |
MAKE_YV12_TO_RGB_C(rgb24,3, b,g,r,0) /* yuv420 -> bgr */ |
} |
879 |
MAKE_YV12_TO_RGB_C(rgb32,4, b,g,r,a) /* yuv420 -> bgra */ |
} |
880 |
MAKE_YV12_TO_RGB_C(abgr, 4, a,b,g,r) /* yuv420 -> abgr */ |
|
881 |
MAKE_YV12_TO_RGB_C(rgba, 4, r,g,b,a) /* yuv420 -> rgba */ |
|
882 |
|
|
883 |
|
/* yuv 4:2:0 planar -> rgb32 */ |
884 |
|
|
885 |
|
void |
886 |
|
yv12_to_rgb32_c(uint8_t * dst, |
887 |
|
int dst_stride, |
888 |
|
uint8_t * y_src, |
889 |
|
uint8_t * v_src, |
890 |
|
uint8_t * u_src, |
891 |
|
int y_stride, |
892 |
|
int uv_stride, |
893 |
|
int width, |
894 |
|
int height) |
895 |
|
{ |
896 |
|
const uint32_t dst_dif = 8 * dst_stride - 4 * width; |
897 |
|
int32_t y_dif = 2 * y_stride - width; |
898 |
|
|
899 |
|
uint8_t *dst2 = dst + 4 * dst_stride; |
900 |
|
uint8_t *y_src2 = y_src + y_stride; |
901 |
|
uint32_t x, y; |
902 |
|
|
903 |
|
if (height < 0) { // flip image? |
904 |
|
height = -height; |
905 |
|
y_src += (height - 1) * y_stride; |
906 |
|
y_src2 = y_src - y_stride; |
907 |
|
u_src += (height / 2 - 1) * uv_stride; |
908 |
|
v_src += (height / 2 - 1) * uv_stride; |
909 |
|
y_dif = -width - 2 * y_stride; |
910 |
|
uv_stride = -uv_stride; |
911 |
|
} |
912 |
|
|
913 |
|
for (y = height / 2; y; y--) { |
914 |
|
// process one 2x2 block per iteration |
915 |
|
for (x = 0; x < (uint32_t) width / 2; x++) { |
916 |
|
int u, v; |
917 |
|
int b_u, g_uv, r_v, rgb_y; |
918 |
|
int r, g, b; |
919 |
|
|
920 |
|
u = u_src[x]; |
921 |
|
v = v_src[x]; |
922 |
|
|
923 |
|
b_u = B_U_tab[u]; |
924 |
|
g_uv = G_U_tab[u] + G_V_tab[v]; |
925 |
|
r_v = R_V_tab[v]; |
926 |
|
|
927 |
|
rgb_y = RGB_Y_tab[*y_src]; |
928 |
|
b = (rgb_y + b_u) >> SCALEBITS_OUT; |
929 |
|
g = (rgb_y - g_uv) >> SCALEBITS_OUT; |
930 |
|
r = (rgb_y + r_v) >> SCALEBITS_OUT; |
931 |
|
dst[0] = MAX(0, MIN(255, r)); |
932 |
|
dst[1] = MAX(0, MIN(255, g)); |
933 |
|
dst[2] = MAX(0, MIN(255, b)); |
934 |
|
dst[3] = 0; |
935 |
|
|
936 |
|
y_src++; |
937 |
|
rgb_y = RGB_Y_tab[*y_src]; |
938 |
|
b = (rgb_y + b_u) >> SCALEBITS_OUT; |
939 |
|
g = (rgb_y - g_uv) >> SCALEBITS_OUT; |
940 |
|
r = (rgb_y + r_v) >> SCALEBITS_OUT; |
941 |
|
dst[4] = MAX(0, MIN(255, r)); |
942 |
|
dst[5] = MAX(0, MIN(255, g)); |
943 |
|
dst[6] = MAX(0, MIN(255, b)); |
944 |
|
dst[7] = 0; |
945 |
|
y_src++; |
946 |
|
|
947 |
|
rgb_y = RGB_Y_tab[*y_src2]; |
948 |
|
b = (rgb_y + b_u) >> SCALEBITS_OUT; |
949 |
|
g = (rgb_y - g_uv) >> SCALEBITS_OUT; |
950 |
|
r = (rgb_y + r_v) >> SCALEBITS_OUT; |
951 |
|
dst2[0] = MAX(0, MIN(255, r)); |
952 |
|
dst2[1] = MAX(0, MIN(255, g)); |
953 |
|
dst2[2] = MAX(0, MIN(255, b)); |
954 |
|
dst2[3] = 0; |
955 |
|
y_src2++; |
956 |
|
|
957 |
|
rgb_y = RGB_Y_tab[*y_src2]; |
958 |
|
b = (rgb_y + b_u) >> SCALEBITS_OUT; |
959 |
|
g = (rgb_y - g_uv) >> SCALEBITS_OUT; |
960 |
|
r = (rgb_y + r_v) >> SCALEBITS_OUT; |
961 |
|
dst2[4] = MAX(0, MIN(255, r)); |
962 |
|
dst2[5] = MAX(0, MIN(255, g)); |
963 |
|
dst2[6] = MAX(0, MIN(255, b)); |
964 |
|
dst2[7] = 0; |
965 |
|
y_src2++; |
966 |
|
|
967 |
|
dst += 8; |
968 |
|
dst2 += 8; |
969 |
|
} |
970 |
|
|
971 |
|
dst += dst_dif; |
972 |
|
dst2 += dst_dif; |
973 |
|
|
974 |
|
y_src += y_dif; |
975 |
|
y_src2 += y_dif; |
976 |
|
|
977 |
|
u_src += uv_stride; |
978 |
|
v_src += uv_stride; |
979 |
|
} |
980 |
|
} |
981 |
|
|
982 |
|
|
983 |
|
|
1042 |
int width, |
int width, |
1043 |
int height) |
int height) |
1044 |
{ |
{ |
1045 |
const uint32_t dst_dif = dst_stride - (2 * width); |
const uint32_t dst_dif = 2 * (dst_stride - width); |
1046 |
uint32_t x, y; |
uint32_t x, y; |
1047 |
|
|
1048 |
if (height < 0) { |
if (height < 0) { |
1086 |
int width, |
int width, |
1087 |
int height) |
int height) |
1088 |
{ |
{ |
1089 |
const uint32_t dst_dif = dst_stride - (2 * width); |
const uint32_t dst_dif = 2 * (dst_stride - width); |
1090 |
uint32_t x, y; |
uint32_t x, y; |
1091 |
|
|
1092 |
if (height < 0) { |
if (height < 0) { |