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