1 /**
2 * @file frame.c Video Frame
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6
7 #include <string.h>
8 #include <re.h>
9 #include <rem_vid.h>
10
11
12 /**
13 * Get video frame buffer size
14 *
15 * @param fmt Video pixel format
16 * @param sz Size of video frame
17 *
18 * @return Number of bytes
19 */
vidframe_size(enum vidfmt fmt,const struct vidsz * sz)20 size_t vidframe_size(enum vidfmt fmt, const struct vidsz *sz)
21 {
22 if (!sz)
23 return 0;
24
25 switch (fmt) {
26
27 case VID_FMT_YUV420P: return sz->w * sz->h * 3 / 2;
28 case VID_FMT_YUYV422: return sz->w * sz->h * 2;
29 case VID_FMT_UYVY422: return sz->w * sz->h * 2;
30 case VID_FMT_RGB32: return sz->w * sz->h * 4;
31 case VID_FMT_ARGB: return sz->w * sz->h * 4;
32 case VID_FMT_RGB565: return sz->w * sz->h * 2;
33 case VID_FMT_RGB555: return sz->w * sz->h * 2;
34 case VID_FMT_NV12: return sz->w * sz->h * 3 / 2;
35 case VID_FMT_NV21: return sz->w * sz->h * 3 / 2;
36 case VID_FMT_YUV444P: return sz->w * sz->h * 3;
37 default:
38 return 0;
39 }
40 }
41
42
43 /**
44 * Initialize a video frame
45 *
46 * @param vf Video frame
47 * @param fmt Video pixel format
48 * @param sz Size of video frame
49 * @param data Pointer to video planes
50 * @param linesize Pointer to linesizes
51 */
vidframe_init(struct vidframe * vf,enum vidfmt fmt,const struct vidsz * sz,void * data[4],unsigned linesize[4])52 void vidframe_init(struct vidframe *vf, enum vidfmt fmt,
53 const struct vidsz *sz, void *data[4], unsigned linesize[4])
54 {
55 int i;
56
57 if (!vf || !sz || !data || !linesize)
58 return;
59
60 for (i=0; i<4; i++) {
61 vf->data[i] = data[i];
62 vf->linesize[i] = linesize[i];
63 }
64
65 vf->size = *sz;
66 vf->fmt = fmt;
67 }
68
69
70 /**
71 * Initialize a video frame from a buffer
72 *
73 * @param vf Video frame
74 * @param fmt Video pixel format
75 * @param sz Size of video frame
76 * @param buf Frame buffer
77 */
vidframe_init_buf(struct vidframe * vf,enum vidfmt fmt,const struct vidsz * sz,uint8_t * buf)78 void vidframe_init_buf(struct vidframe *vf, enum vidfmt fmt,
79 const struct vidsz *sz, uint8_t *buf)
80 {
81 unsigned w, h;
82
83 if (!vf || !sz || !buf)
84 return;
85
86 w = (sz->w + 1) >> 1;
87 h = (sz->h + 1) >> 1;
88
89 memset(vf->linesize, 0, sizeof(vf->linesize));
90 memset(vf->data, 0, sizeof(vf->data));
91
92 switch (fmt) {
93
94 case VID_FMT_YUV420P:
95 vf->linesize[0] = sz->w;
96 vf->linesize[1] = w;
97 vf->linesize[2] = w;
98
99 vf->data[0] = buf;
100 vf->data[1] = vf->data[0] + vf->linesize[0] * sz->h;
101 vf->data[2] = vf->data[1] + vf->linesize[1] * h;
102 break;
103
104 case VID_FMT_YUYV422:
105 case VID_FMT_UYVY422:
106 vf->linesize[0] = sz->w * 2;
107 vf->data[0] = buf;
108 break;
109
110 case VID_FMT_RGB32:
111 case VID_FMT_ARGB:
112 vf->linesize[0] = sz->w * 4;
113 vf->data[0] = buf;
114 break;
115
116 case VID_FMT_RGB565:
117 case VID_FMT_RGB555:
118 vf->linesize[0] = sz->w * 2;
119 vf->data[0] = buf;
120 break;
121
122 case VID_FMT_NV12:
123 case VID_FMT_NV21:
124 vf->linesize[0] = sz->w;
125 vf->linesize[1] = w*2;
126
127 vf->data[0] = buf;
128 vf->data[1] = vf->data[0] + vf->linesize[0] * sz->h;
129 break;
130
131 case VID_FMT_YUV444P:
132 vf->linesize[0] = sz->w;
133 vf->linesize[1] = sz->w;
134 vf->linesize[2] = sz->w;
135
136 vf->data[0] = buf;
137 vf->data[1] = vf->data[0] + vf->linesize[0] * sz->h;
138 vf->data[2] = vf->data[1] + vf->linesize[1] * sz->h;
139 break;
140
141 default:
142 (void)re_printf("vidframe: no fmt %s\n", vidfmt_name(fmt));
143 return;
144 }
145
146 vf->size = *sz;
147 vf->fmt = fmt;
148 }
149
150
151 /**
152 * Allocate an empty video frame
153 *
154 * @param vfp Pointer to allocated video frame
155 * @param fmt Video pixel format
156 * @param sz Size of video frame
157 *
158 * @return 0 for success, otherwise error code
159 */
vidframe_alloc(struct vidframe ** vfp,enum vidfmt fmt,const struct vidsz * sz)160 int vidframe_alloc(struct vidframe **vfp, enum vidfmt fmt,
161 const struct vidsz *sz)
162 {
163 struct vidframe *vf;
164
165 if (!sz || !sz->w || !sz->h)
166 return EINVAL;
167
168 vf = mem_zalloc(sizeof(*vf) + vidframe_size(fmt, sz), NULL);
169 if (!vf)
170 return ENOMEM;
171
172 vidframe_init_buf(vf, fmt, sz, (uint8_t *)(vf + 1));
173
174 *vfp = vf;
175
176 return 0;
177 }
178
179
180 /**
181 * Fill a video frame with a nice color
182 *
183 * @param vf Video frame
184 * @param r Red color component
185 * @param g Green color component
186 * @param b Blue color component
187 */
vidframe_fill(struct vidframe * vf,uint32_t r,uint32_t g,uint32_t b)188 void vidframe_fill(struct vidframe *vf, uint32_t r, uint32_t g, uint32_t b)
189 {
190 uint8_t *p;
191 unsigned h, i;
192
193 if (!vf)
194 return;
195
196 switch (vf->fmt) {
197
198 case VID_FMT_YUV420P:
199 h = vf->size.h;
200
201 memset(vf->data[0], rgb2y(r, g, b), h * vf->linesize[0]);
202 memset(vf->data[1], rgb2u(r, g, b), h/2 * vf->linesize[1]);
203 memset(vf->data[2], rgb2v(r, g, b), h/2 * vf->linesize[2]);
204 break;
205
206 case VID_FMT_YUV444P:
207 h = vf->size.h;
208
209 memset(vf->data[0], rgb2y(r, g, b), h * vf->linesize[0]);
210 memset(vf->data[1], rgb2u(r, g, b), h * vf->linesize[1]);
211 memset(vf->data[2], rgb2v(r, g, b), h * vf->linesize[2]);
212 break;
213
214 case VID_FMT_RGB32:
215 p = vf->data[0];
216 for (i=0; i<vf->linesize[0] * vf->size.h; i+=4) {
217 *p++ = b;
218 *p++ = g;
219 *p++ = r;
220 *p++ = 0;
221 }
222 break;
223
224 default:
225 (void)re_printf("vidfill: no fmt %s\n", vidfmt_name(vf->fmt));
226 break;
227 }
228 }
229
230
231 /**
232 * Copy content between to equally sized video frames of same pixel format
233 *
234 * @param dst Destination frame
235 * @param src Source frame
236 */
vidframe_copy(struct vidframe * dst,const struct vidframe * src)237 void vidframe_copy(struct vidframe *dst, const struct vidframe *src)
238 {
239 const uint8_t *ds0, *ds1, *ds2;
240 unsigned lsd, lss, w, h, y;
241 uint8_t *dd0, *dd1, *dd2;
242
243 if (!dst || !src)
244 return;
245
246 if (!vidsz_cmp(&dst->size, &src->size))
247 return;
248
249 if (dst->fmt != src->fmt)
250 return;
251
252 switch (dst->fmt) {
253
254 case VID_FMT_YUV420P:
255 lsd = dst->linesize[0];
256 lss = src->linesize[0];
257
258 dd0 = dst->data[0];
259 dd1 = dst->data[1];
260 dd2 = dst->data[2];
261
262 ds0 = src->data[0];
263 ds1 = src->data[1];
264 ds2 = src->data[2];
265
266 w = dst->size.w & ~1;
267 h = dst->size.h & ~1;
268
269 for (y=0; y<h; y+=2) {
270
271 memcpy(dd0, ds0, w);
272 dd0 += lsd;
273 ds0 += lss;
274
275 memcpy(dd0, ds0, w);
276 dd0 += lsd;
277 ds0 += lss;
278
279 memcpy(dd1, ds1, w/2);
280 dd1 += lsd/2;
281 ds1 += lss/2;
282
283 memcpy(dd2, ds2, w/2);
284 dd2 += lsd/2;
285 ds2 += lss/2;
286 }
287 break;
288
289 case VID_FMT_YUV444P:
290 lsd = dst->linesize[0];
291 lss = src->linesize[0];
292
293 dd0 = dst->data[0];
294 dd1 = dst->data[1];
295 dd2 = dst->data[2];
296
297 ds0 = src->data[0];
298 ds1 = src->data[1];
299 ds2 = src->data[2];
300
301 w = dst->size.w;
302 h = dst->size.h;
303
304 for (y=0; y<h; y++) {
305
306 /* Y */
307 memcpy(dd0, ds0, w);
308 dd0 += lsd;
309 ds0 += lss;
310
311 /* U */
312 memcpy(dd1, ds1, w);
313 dd1 += lsd;
314 ds1 += lss;
315
316 /* V */
317 memcpy(dd2, ds2, w);
318 dd2 += lsd;
319 ds2 += lss;
320 }
321 break;
322
323 case VID_FMT_NV12:
324 case VID_FMT_NV21:
325 lsd = dst->linesize[0];
326 lss = src->linesize[0];
327
328 dd0 = dst->data[0];
329 dd1 = dst->data[1];
330
331 ds0 = src->data[0];
332 ds1 = src->data[1];
333
334 w = dst->size.w & ~1;
335 h = dst->size.h & ~1;
336
337 for (y=0; y<h; y+=2) {
338
339 memcpy(dd0, ds0, w);
340 dd0 += lsd;
341 ds0 += lss;
342
343 memcpy(dd0, ds0, w);
344 dd0 += lsd;
345 ds0 += lss;
346
347 memcpy(dd1, ds1, w);
348 dd1 += lsd;
349 ds1 += lss;
350 }
351 break;
352
353 default:
354 (void)re_printf("vidframe_copy(): unsupported format\n");
355 break;
356 }
357 }
358