summaryrefslogtreecommitdiffstats
path: root/cyuv.c
blob: 3a14ca01d70840dd9edb2012645b54a47ec3770f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* ------------------------------------------------------------------------
 * Creative YUV Video Decoder
 *
 * Dr. Tim Ferguson, 2001.
 * For more details on the algorithm:
 *         http://www.csse.monash.edu.au/~timf/videocodec.html
 *
 * This is a very simple predictive coder.  A video frame is coded in YUV411
 * format.  The first pixel of each scanline is coded using the upper four
 * bits of its absolute value.  Subsequent pixels for the scanline are coded
 * using the difference between the last pixel and the current pixel (DPCM).
 * The DPCM values are coded using a 16 entry table found at the start of the
 * frame.  Thus four bits per component are used and are as follows:
 *     UY VY YY UY VY YY UY VY...
 * This code assumes the frame width will be a multiple of four pixels.  This
 * should probably be fixed.
 * ------------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#include "loader/wine/avifmt.h" // for mmioFOURCC macro

/* ------------------------------------------------------------------------
 * This function decodes a buffer containing a CYUV encoded frame.
 *
 * buf - the input buffer to be decoded
 * size - the size of the input buffer
 * frame - the output frame buffer (UYVY format)
 * width - the width of the output frame
 * height - the height of the output frame
 * format - the requested output format
 */
void decode_cyuv(unsigned char *buf, int size, unsigned char *frame, int width, int height, int format)
{
int i, xpos, ypos, cur_Y = 0, cur_U = 0, cur_V = 0;
char *delta_y_tbl, *delta_c_tbl, *ptr;

	delta_y_tbl = buf + 16;
	delta_c_tbl = buf + 32;
	ptr = buf + (16 * 3);

	for(ypos = 0; ypos < height; ypos++)
		for(xpos = 0; xpos < width; xpos += 4)
			{
			if(xpos == 0)		/* first pixels in scanline */
				{
				cur_U = *(ptr++);
				cur_Y = (cur_U & 0x0f) << 4;
				cur_U = cur_U & 0xf0;
				if (format == mmioFOURCC('Y','U','Y','2'))
					{
					*frame++ = cur_Y;
					*frame++ = cur_U;
					}
				else
					{
					*frame++ = cur_U;
					*frame++ = cur_Y;
					}

				cur_V = *(ptr++);
				cur_Y = (cur_Y + delta_y_tbl[cur_V & 0x0f]) & 0xff;
				cur_V = cur_V & 0xf0;
				if (format == mmioFOURCC('Y','U','Y','2'))
					{
					*frame++ = cur_Y;
					*frame++ = cur_V;
					}
				else
					{
					*frame++ = cur_V;
					*frame++ = cur_Y;
					}
				}
			else			/* subsequent pixels in scanline */
				{
				i = *(ptr++);
				cur_U = (cur_U + delta_c_tbl[i >> 4]) & 0xff;
				cur_Y = (cur_Y + delta_y_tbl[i & 0x0f]) & 0xff;
				if (format == mmioFOURCC('Y','U','Y','2'))
					{
					*frame++ = cur_Y;
					*frame++ = cur_U;
					}
				else
					{
					*frame++ = cur_U;
					*frame++ = cur_Y;
					}

				i = *(ptr++);
				cur_V = (cur_V + delta_c_tbl[i >> 4]) & 0xff;
				cur_Y = (cur_Y + delta_y_tbl[i & 0x0f]) & 0xff;
				if (format == mmioFOURCC('Y','U','Y','2'))
					{
					*frame++ = cur_Y;
					*frame++ = cur_V;
					}
				else
					{
					*frame++ = cur_V;
					*frame++ = cur_Y;
					}
				}

			i = *(ptr++);
			cur_Y = (cur_Y + delta_y_tbl[i & 0x0f]) & 0xff;
			if (format == mmioFOURCC('Y','U','Y','2'))
				{
				*frame++ = cur_Y;
				*frame++ = cur_U;
				}
			else
				{
				*frame++ = cur_U;
				*frame++ = cur_Y;
				}

			cur_Y = (cur_Y + delta_y_tbl[i >> 4]) & 0xff;
			if (format == mmioFOURCC('Y','U','Y','2'))
				{
				*frame++ = cur_Y;
				*frame++ = cur_V;
				}
			else
				{
				*frame++ = cur_V;
				*frame++ = cur_Y;
				}
			}
}