initial commit
[goodguy/history.git] / cinelerra-5.0 / quicktime / yuv2.c
1 #include "colormodels.h"
2 #include "funcprotos.h"
3 #include "quicktime.h"
4 #include "yuv2.h"
5
6 /* U V values are signed but Y R G B values are unsigned! */
7 /*
8  *      R = Y               + 1.40200 * V
9  *      G = Y - 0.34414 * U - 0.71414 * V
10  *      B = Y + 1.77200 * U
11  */
12
13 /*
14  *              Y =  0.2990 * R + 0.5870 * G + 0.1140 * B
15  *              U = -0.1687 * R - 0.3310 * G + 0.5000 * B
16  *              V =  0.5000 * R - 0.4187 * G - 0.0813 * B
17  */
18
19
20 typedef struct
21 {
22         unsigned char *work_buffer;
23         int coded_w, coded_h;
24
25 /* The YUV2 codec requires a bytes per line that is a multiple of 4 */
26         int bytes_per_line;
27         int initialized;
28
29         int is_2vuy;
30         uint8_t ** rows;
31   } quicktime_yuv2_codec_t;
32
33 static void quicktime_delete_codec_yuv2(quicktime_video_map_t *vtrack)
34 {
35         quicktime_yuv2_codec_t *codec;
36
37         codec = ((quicktime_codec_t*)vtrack->codec)->priv;
38         if(codec->work_buffer) free(codec->work_buffer);
39         if(codec->rows) free(codec->rows);
40         free(codec);
41 }
42 #if 0
43 static int quicktime_reads_colormodel_yuv2(quicktime_t *file,
44                 int colormodel,
45                 int track)
46 {
47         return (colormodel == BC_RGB888 ||
48                 colormodel == BC_YUV888 ||
49                 colormodel == BC_YUV422P);
50 }
51 #endif
52
53 static void convert_encode_yuv2(quicktime_yuv2_codec_t *codec)
54 {
55         int y, x;
56         for(y = 0; y < codec->coded_h; y++) {
57                 unsigned char *row = codec->work_buffer + y * codec->bytes_per_line;
58                 for(x = 0; x < codec->bytes_per_line; ) {
59                         row[1] -= 128;
60                         row[3] -= 128;
61                         row += 4;
62                         x += 4;
63                 }
64         }
65 }
66
67 static void convert_decode_yuv2(quicktime_yuv2_codec_t *codec)
68 {
69         int y, x;
70         for(y = 0; y < codec->coded_h; y++) {
71                 unsigned char *row = codec->work_buffer + y * codec->bytes_per_line;
72                 for(x = 0; x < codec->bytes_per_line; ) {
73                         row[1] += 128;
74                         row[3] += 128;
75                         row += 4;
76                         x += 4;
77                 }
78         }
79 }
80
81 static void convert_encode_2vuy(quicktime_yuv2_codec_t *codec)
82 {
83         int y, x;
84         for(y = 0; y < codec->coded_h; y++) {
85                 unsigned char *row = codec->work_buffer + y * codec->bytes_per_line;
86                 for(x = 0; x < codec->bytes_per_line; ) {
87                         int y0 = row[0], u = row[1];
88                         int y1 = row[2], v = row[3];
89                         row[0] = u;  row[1] = y0;
90                         row[2] = v;  row[3] = y1;
91                         row += 4;
92                         x += 4;
93                 }
94         }
95 }
96
97 static void convert_decode_2vuy(quicktime_yuv2_codec_t *codec)
98 {
99         int y, x;
100         for(y = 0; y < codec->coded_h; y++) {
101                 unsigned char *row = codec->work_buffer + y * codec->bytes_per_line;
102                 for(x = 0; x < codec->bytes_per_line; ) {
103                         int u = row[0], y0 = row[1];
104                         int v = row[2], y1 = row[3];
105                         row[0] = y0;  row[1] = u;
106                         row[2] = y1;  row[3] = v;
107                         row += 4;
108                         x += 4;
109                 }
110         }
111 }
112
113
114 static void initialize(quicktime_video_map_t *vtrack, quicktime_yuv2_codec_t *codec,
115                        int width, int height)
116 {
117         if(!codec->initialized)
118         {
119                 int y;
120 /* Init private items */
121                 codec->coded_w = (int)((float)width / 4 + 0.5) * 4;
122 //              codec->coded_h = (int)((float)vtrack->track->tkhd.track_height / 4 + 0.5) * 4;
123                 codec->coded_h = height;
124                 codec->bytes_per_line = codec->coded_w * 2;
125                 codec->work_buffer = malloc(codec->bytes_per_line * codec->coded_h);
126                 codec->rows = malloc(height * sizeof(*(codec->rows)));
127                 for(y = 0; y < height; y++)
128                         codec->rows[y] = &codec->work_buffer[y * codec->bytes_per_line];
129                 codec->initialized = 1;
130     }
131 }
132
133 static int decode(quicktime_t *file, unsigned char **row_pointers, int track)
134 {
135         int bytes;
136         quicktime_video_map_t *vtrack = &(file->vtracks[track]);
137         quicktime_yuv2_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
138         int width = quicktime_video_width(file, track);
139         int height = quicktime_video_height(file, track);
140         int result = 0;
141
142         initialize(vtrack, codec, width, height);
143         quicktime_set_video_position(file, vtrack->current_position, track);
144         bytes = quicktime_frame_size(file, vtrack->current_position, track);
145
146         result = !quicktime_read_data(file, (char*)codec->work_buffer, bytes);
147         if(codec->is_2vuy)
148                 convert_decode_2vuy(codec);
149         else
150                 convert_decode_yuv2(codec);
151
152         cmodel_transfer(row_pointers, codec->rows,
153                 row_pointers[0], row_pointers[1], row_pointers[2],
154                 0, 0, 0,
155                 file->in_x, file->in_y, file->in_w, file->in_h,
156                 0, 0, file->out_w, file->out_h,
157                 BC_YUV422, file->color_model,
158                 0, codec->coded_w, file->out_w);
159
160         return result;
161 }
162
163 static int encode(quicktime_t *file, unsigned char **row_pointers, int track)
164 {
165         int bytes;
166         quicktime_video_map_t *vtrack = &(file->vtracks[track]);
167         quicktime_trak_t *trak = vtrack->track;
168         quicktime_yuv2_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
169         int result = 1;
170         int width = vtrack->track->tkhd.track_width;
171         int height = vtrack->track->tkhd.track_height;
172         quicktime_atom_t chunk_atom;
173         initialize(vtrack, codec, width, height);
174         bytes = height * codec->bytes_per_line;
175
176         cmodel_transfer(codec->rows, row_pointers,
177                 0, 0, 0,
178                 row_pointers[0], row_pointers[1], row_pointers[2],
179                 0, 0, width, height,
180                 0, 0, width, height,
181                 file->color_model, BC_YUV422,
182                 0, width, codec->coded_w);
183
184         if( codec->is_2vuy )
185                 convert_encode_2vuy(codec);
186         else
187                 convert_encode_yuv2(codec);
188
189         quicktime_write_chunk_header(file, trak, &chunk_atom);
190         result = !quicktime_write_data(file, (char*)codec->work_buffer, bytes);
191         quicktime_write_chunk_footer(file, trak,
192                 vtrack->current_chunk, &chunk_atom, 1);
193
194         vtrack->current_chunk++;
195         return result;
196 }
197
198 static int reads_colormodel(quicktime_t *file,
199                 int colormodel,
200                 int track)
201 {
202
203         return (colormodel == BC_RGB888 ||
204                 colormodel == BC_YUV888 ||
205                 colormodel == BC_YUV422P ||
206                 colormodel == BC_YUV422);
207 }
208
209 static int writes_colormodel(quicktime_t *file,
210                 int colormodel,
211                 int track)
212 {
213
214         return (colormodel == BC_RGB888 ||
215                 colormodel == BC_YUV888 ||
216                 colormodel == BC_YUV422P ||
217                 colormodel == BC_YUV422);
218 }
219
220 void quicktime_init_codec_yuv2(quicktime_video_map_t *vtrack)
221 {
222         quicktime_codec_t *codec_base = (quicktime_codec_t*)vtrack->codec;
223
224 /* Init public items */
225         codec_base->priv = calloc(1, sizeof(quicktime_yuv2_codec_t));
226         codec_base->delete_vcodec = quicktime_delete_codec_yuv2;
227         codec_base->decode_video = decode;
228         codec_base->encode_video = encode;
229         codec_base->decode_audio = 0;
230         codec_base->encode_audio = 0;
231         codec_base->reads_colormodel = reads_colormodel;
232         codec_base->writes_colormodel = writes_colormodel;
233         codec_base->fourcc = QUICKTIME_YUV2;
234         codec_base->title = "Component Y'CbCr 8-bit 4:2:2 (yuv2)";
235         codec_base->desc = "YUV 4:2:2";
236 }
237
238 void quicktime_init_codec_2vuy(quicktime_video_map_t *vtrack)
239 {
240         quicktime_codec_t *codec_base = (quicktime_codec_t*)vtrack->codec;
241         quicktime_yuv2_codec_t * codec;
242 /* Init public items */
243         codec_base->priv = calloc(1, sizeof(quicktime_yuv2_codec_t));
244         codec_base->delete_vcodec = quicktime_delete_codec_yuv2;
245         codec_base->decode_video = decode;
246         codec_base->encode_video = encode;
247         codec_base->decode_audio = 0;
248         codec_base->encode_audio = 0;
249         codec_base->reads_colormodel = reads_colormodel;
250         codec_base->writes_colormodel = writes_colormodel;
251         codec_base->fourcc = QUICKTIME_2VUY;
252         codec_base->title = "Component Y'CbCr 8-bit 4:2:2 (2vuy)";
253         codec_base->desc = "YUV 4:2:2";
254         codec = (quicktime_yuv2_codec_t *)(codec_base->priv);
255         codec->is_2vuy = 1;
256 }
257