YUV420和YUV422的格式转换
2008-03-10 19:16:38

1 /* 
2  * Linux VeeJay
3  *
4  * Copyright(C)2002-2004 Niels Elburg 
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License , or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  */
19 #include 
20 
21 #ifdef SUPPORT_READ_DV2
22 #include 
23 #include 
24 #include "vj-dv.h"
25 
26 #define NTSC_W 720
27 #define NTSC_H 480
28 #define PAL_W 720
29 #define PAL_H 576
30 #define DV_PAL_SIZE 144000
31 #define DV_NTSC_SIZE 120000
32 
33 static dv_decoder_t *vj_dv_decoder;
34 static dv_encoder_t *vj_dv_encoder;
35 static uint8_t *vj_dv_video[3];
36 static uint8_t *vj_dv_encode_buf;
37 
38 /* init the dv decoder and decode buffer*/
39 void vj_dv_init(int width, int height)
40 {
41         
42     vj_dv_decoder = dv_decoder_new(1, 1, 0);
43     vj_dv_decoder->quality = DV_QUALITY_BEST;
44     vj_dv_video[0] =
45         (uint8_t *) malloc(width * height * 4 * sizeof(uint8_t));
46     vj_dv_video[1] = NULL;
47     vj_dv_video[2] = NULL;
48     memset( vj_dv_video[0], 0, (width*height*4));
49 }
50 
51 /* init the dv encoder and encode buffer */
52 void vj_dv_init_encoder(EditList * el)
53 {
54     vj_dv_encoder = dv_encoder_new(0, 0, 0);
55     vj_dv_encoder->isPAL = (el->video_norm == 'p' ? 1 : 0);
56     vj_dv_encoder->is16x9 = FALSE;
57     vj_dv_encoder->vlc_encode_passes = 3;
58     vj_dv_encoder->static_qno = 0;
59     vj_dv_encoder->force_dct = DV_DCT_AUTO;
60     vj_dv_encode_buf =
61         (uint8_t *) malloc(sizeof(uint8_t) * 3 *
62                            (vj_dv_encoder->
63                             isPAL ? DV_PAL_SIZE : DV_NTSC_SIZE));
64     memset( vj_dv_encode_buf, 0 ,  (3 *
65                            (vj_dv_encoder->
66                             isPAL ? DV_PAL_SIZE : DV_NTSC_SIZE)));
67 }
68 
69 /* this routine is the same as frame_YUV422_to_YUV420P , unpack
70  * libdv's 4:2:2-packed into 4:2:0 planar 
71  * See http://mjpeg.sourceforge.net/ (MJPEG Tools) (lav-common.c)
72  */
73 void yuy2toyv12(uint8_t * _y, uint8_t * _u, uint8_t * _v, uint8_t * input,
74                 int width, int height)
75 {
76 
77     int i, j, w2;
78     uint8_t *y, *u, *v;
79 
80     w2 = width / 2;
81 
82     //I420
83     y = _y;
84     v = _v;
85     u = _u;
86 
87     for (i = 0; i < height; i += 4) {
88         /* top field scanline */
89         for (j = 0; j < w2; j++) {
90             /* packed YUV 422 is: Y[i] U[i] Y[i+1] V[i] */
91             *(y++) = *(input++);
92             *(u++) = *(input++);
93             *(y++) = *(input++);
94             *(v++) = *(input++);
95         }
96         for (j = 0; j < w2; j++)
97         {
98             *(y++) = *(input++);
99             *(u++) = *(input++);
100             *(y++) = *(input++);
101             *(v++) = *(input++);
102         
103         }
104 
105         /* next two scanlines, one frome each field , interleaved */
106         for (j = 0; j < w2; j++) {
107             /* skip every second line for U and V */
108             *(y++) = *(input++);
109             input++;
110             *(y++) = *(input++);
111             input++;
112         }
113         /* bottom field scanline*/
114         for (j = 0; j < w2; j++) {
115             /* skip every second line for U and V */
116             *(y++) = *(input++);
117             input++;
118             *(y++) = *(input++);
119             input++;
120         }
121 
122     }
123 }
124 
125 /* convert 4:2:0 to yuv 4:2:2 */
126 void yuv420p_to_yuv422(uint8_t * yuv420[3], uint8_t * dest, int width,
127                        int height)
128 {
129     unsigned int x, y;
130 
131 
132     for (y = 0; y < height; ++y) {
133         uint8_t *Y = yuv420[0] + y * width;
134         uint8_t *Cb = yuv420[1] + (y / 2) * (width / 2);
135         uint8_t *Cr = yuv420[2] + (y / 2) * (width / 2);
136         for (x = 0; x < width; x += 2) {
137             *(dest + 0) = Y[0];
138             *(dest + 1) = Cb[0];
139             *(dest + 2) = Y[1];
140             *(dest + 3) = Cr[0];
141             dest += 4;
142             Y += 2;
143             ++Cb;
144             ++Cr;
145         }
146     }
147 }
148 
149 /* convert 4:2:0 to yuv 4:2:2 
150 static void convert_yuv420p_to_yuv422(uint8_t * yuv_in[3],
151                                       uint8_t * yuv422, int width,
152                                       int height)
153 {
154     unsigned int x, y;
155     unsigned int i = 0;
156 
157     for (y = 0; y < height; ++y) {
158         uint8_t *Y = yuv_in[0] + y * width;
159         uint8_t *Cb = yuv_in[1] + (y / 2) * (width / 2);
160         uint8_t *Cr = yuv_in[2] + (y / 2) * (width / 2);
161         for (x = 0; x < width; x += 2) {
162             *(yuv422 + i) = Y[0];
163             *(yuv422 + i + 1) = Cb[0];
164             *(yuv422 + i + 2) = Y[1];
165             *(yuv422 + i + 3) = Cr[0];
166             i += 4;
167             Y += 2;
168             ++Cb;
169             ++Cr;
170         }
171     }
172 }
173 */
174 
175 /* encode frame to dv format, dv frame will be in output_buf */
176 int vj_dv_encode_frame(uint8_t * input_buf[3], uint8_t * output_buf)
177 {
178 
179     time_t now = time(NULL);
180     uint8_t *pixels[3];
181 
182     if (!input_buf)
183         return 0;
184 
185     pixels[0] = (uint8_t *) vj_dv_encode_buf;
186 
187     if (vj_dv_encoder->isPAL) {
188         pixels[2] = (uint8_t *) vj_dv_encode_buf + (PAL_W * PAL_H);
189         pixels[1] = (uint8_t *) vj_dv_encode_buf + (PAL_W * PAL_H * 5) / 4;
190         yuv420p_to_yuv422(input_buf,vj_dv_encode_buf, PAL_W, PAL_H);
191     } else {
192         pixels[2] = (uint8_t *) vj_dv_encode_buf + (NTSC_W * NTSC_H);
193         pixels[1] =
194             (uint8_t *) vj_dv_encode_buf + (NTSC_W * NTSC_H * 5) / 4;
195         yuv420p_to_yuv422(input_buf,vj_dv_encode_buf, NTSC_W , NTSC_H);
196     }
197   
198     dv_encode_full_frame(vj_dv_encoder, pixels, e_dv_color_yuv,
199                          output_buf);
200     dv_encode_metadata(output_buf, vj_dv_encoder->isPAL,
201                        vj_dv_encoder->is16x9, &now, 0);
202     dv_encode_timecode(output_buf, vj_dv_encoder->isPAL, 0);
203 
204     if(vj_dv_encoder->isPAL) return DV_PAL_SIZE;
205     return DV_NTSC_SIZE;
206 }
207 
208 void vj_dv_free_encoder()
209 {
210     dv_encoder_free(vj_dv_encoder);
211     if(vj_dv_encode_buf) free(vj_dv_encode_buf);
212 }
213 
214 void vj_dv_free_decoder() {
215         if(vj_dv_video[0]) free(vj_dv_video[0]);
216         dv_decoder_free(vj_dv_decoder);
217 }
218 
219 int vj_dv_decode_frame(uint8_t * input_buf, uint8_t * Y,
220                        uint8_t * Cb, uint8_t * Cr, int width, int height)
221 {
222 
223     int pitches[3];
224 
225     if (!input_buf)
226         return 0;
227 
228     if (dv_parse_header(vj_dv_decoder, input_buf) < 0)
229         return 0;
230 
231     if (!((vj_dv_decoder->num_dif_seqs == 10)
232           || (vj_dv_decoder->num_dif_seqs == 12)))
233         return 0;
234 
235     /*
236        switch(vj_dv_decoder->sampling) {
237        case e_dv_sample_411:fprintf(stderr,"sample 411/n"); break;
238        case e_dv_sample_422:fprintf(stderr,"sample 422/n");break;
239        case e_dv_sample_420:fprintf(stderr,"sample 420/n");break;
240        default: fprintf(stderr,"unknown/n");break;
241        }
242      */
243 
244     if (vj_dv_decoder->sampling == e_dv_sample_411 ||
245         vj_dv_decoder->sampling == e_dv_sample_422 ||
246         vj_dv_decoder->sampling == e_dv_sample_420) {
247 
248         pitches[0] = width * 2;
249         pitches[1] = 0;
250         pitches[2] = 0;
251 
252 
253         dv_decode_full_frame(vj_dv_decoder, input_buf,
254                              e_dv_color_yuv, vj_dv_video, pitches);
255 
256         yuy2toyv12(Y, Cb, Cr, vj_dv_video[0], width, height);
257 
258         return 1;
259     }
260 
261     return 0;
262 }
263 
264 #endif

YUV格式有两大类:planar和packed。
对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。
对于packed的YUV格式,每个像素点的Y,U,V是连续交*存储的。

Logo

更多推荐