Commit | Line | Data |
---|---|---|
5c7ab634 VH |
1 | /* |
2 | * omap_voutlib.c | |
3 | * | |
4 | * Copyright (C) 2005-2010 Texas Instruments. | |
5 | * | |
6 | * This file is licensed under the terms of the GNU General Public License | |
7 | * version 2. This program is licensed "as is" without any warranty of any | |
8 | * kind, whether express or implied. | |
9 | * | |
10 | * Based on the OMAP2 camera driver | |
11 | * Video-for-Linux (Version 2) camera capture driver for | |
12 | * the OMAP24xx camera controller. | |
13 | * | |
14 | * Author: Andy Lowe (source@mvista.com) | |
15 | * | |
16 | * Copyright (C) 2004 MontaVista Software, Inc. | |
17 | * Copyright (C) 2010 Texas Instruments. | |
18 | * | |
19 | */ | |
20 | ||
21 | #include <linux/module.h> | |
22 | #include <linux/errno.h> | |
23 | #include <linux/kernel.h> | |
24 | #include <linux/types.h> | |
25 | #include <linux/videodev2.h> | |
26 | ||
27 | #include <plat/cpu.h> | |
28 | ||
29 | MODULE_AUTHOR("Texas Instruments"); | |
30 | MODULE_DESCRIPTION("OMAP Video library"); | |
31 | MODULE_LICENSE("GPL"); | |
32 | ||
33 | /* Return the default overlay cropping rectangle in crop given the image | |
34 | * size in pix and the video display size in fbuf. The default | |
35 | * cropping rectangle is the largest rectangle no larger than the capture size | |
36 | * that will fit on the display. The default cropping rectangle is centered in | |
37 | * the image. All dimensions and offsets are rounded down to even numbers. | |
38 | */ | |
39 | void omap_vout_default_crop(struct v4l2_pix_format *pix, | |
40 | struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop) | |
41 | { | |
42 | crop->width = (pix->width < fbuf->fmt.width) ? | |
43 | pix->width : fbuf->fmt.width; | |
44 | crop->height = (pix->height < fbuf->fmt.height) ? | |
45 | pix->height : fbuf->fmt.height; | |
46 | crop->width &= ~1; | |
47 | crop->height &= ~1; | |
48 | crop->left = ((pix->width - crop->width) >> 1) & ~1; | |
49 | crop->top = ((pix->height - crop->height) >> 1) & ~1; | |
50 | } | |
51 | EXPORT_SYMBOL_GPL(omap_vout_default_crop); | |
52 | ||
53 | /* Given a new render window in new_win, adjust the window to the | |
54 | * nearest supported configuration. The adjusted window parameters are | |
55 | * returned in new_win. | |
56 | * Returns zero if succesful, or -EINVAL if the requested window is | |
57 | * impossible and cannot reasonably be adjusted. | |
58 | */ | |
59 | int omap_vout_try_window(struct v4l2_framebuffer *fbuf, | |
60 | struct v4l2_window *new_win) | |
61 | { | |
62 | struct v4l2_rect try_win; | |
63 | ||
64 | /* make a working copy of the new_win rectangle */ | |
65 | try_win = new_win->w; | |
66 | ||
67 | /* adjust the preview window so it fits on the display by clipping any | |
68 | * offscreen areas | |
69 | */ | |
70 | if (try_win.left < 0) { | |
71 | try_win.width += try_win.left; | |
72 | try_win.left = 0; | |
73 | } | |
74 | if (try_win.top < 0) { | |
75 | try_win.height += try_win.top; | |
76 | try_win.top = 0; | |
77 | } | |
78 | try_win.width = (try_win.width < fbuf->fmt.width) ? | |
79 | try_win.width : fbuf->fmt.width; | |
80 | try_win.height = (try_win.height < fbuf->fmt.height) ? | |
81 | try_win.height : fbuf->fmt.height; | |
82 | if (try_win.left + try_win.width > fbuf->fmt.width) | |
83 | try_win.width = fbuf->fmt.width - try_win.left; | |
84 | if (try_win.top + try_win.height > fbuf->fmt.height) | |
85 | try_win.height = fbuf->fmt.height - try_win.top; | |
86 | try_win.width &= ~1; | |
87 | try_win.height &= ~1; | |
88 | ||
89 | if (try_win.width <= 0 || try_win.height <= 0) | |
90 | return -EINVAL; | |
91 | ||
92 | /* We now have a valid preview window, so go with it */ | |
93 | new_win->w = try_win; | |
94 | new_win->field = V4L2_FIELD_ANY; | |
95 | return 0; | |
96 | } | |
97 | EXPORT_SYMBOL_GPL(omap_vout_try_window); | |
98 | ||
99 | /* Given a new render window in new_win, adjust the window to the | |
100 | * nearest supported configuration. The image cropping window in crop | |
101 | * will also be adjusted if necessary. Preference is given to keeping the | |
102 | * the window as close to the requested configuration as possible. If | |
103 | * successful, new_win, vout->win, and crop are updated. | |
104 | * Returns zero if succesful, or -EINVAL if the requested preview window is | |
105 | * impossible and cannot reasonably be adjusted. | |
106 | */ | |
107 | int omap_vout_new_window(struct v4l2_rect *crop, | |
108 | struct v4l2_window *win, struct v4l2_framebuffer *fbuf, | |
109 | struct v4l2_window *new_win) | |
110 | { | |
111 | int err; | |
112 | ||
113 | err = omap_vout_try_window(fbuf, new_win); | |
114 | if (err) | |
115 | return err; | |
116 | ||
117 | /* update our preview window */ | |
118 | win->w = new_win->w; | |
119 | win->field = new_win->field; | |
120 | win->chromakey = new_win->chromakey; | |
121 | ||
122 | /* Adjust the cropping window to allow for resizing limitation */ | |
123 | if (cpu_is_omap24xx()) { | |
124 | /* For 24xx limit is 8x to 1/2x scaling. */ | |
125 | if ((crop->height/win->w.height) >= 2) | |
126 | crop->height = win->w.height * 2; | |
127 | ||
128 | if ((crop->width/win->w.width) >= 2) | |
129 | crop->width = win->w.width * 2; | |
130 | ||
131 | if (crop->width > 768) { | |
132 | /* The OMAP2420 vertical resizing line buffer is 768 | |
133 | * pixels wide. If the cropped image is wider than | |
134 | * 768 pixels then it cannot be vertically resized. | |
135 | */ | |
136 | if (crop->height != win->w.height) | |
137 | crop->width = 768; | |
138 | } | |
139 | } else if (cpu_is_omap34xx()) { | |
140 | /* For 34xx limit is 8x to 1/4x scaling. */ | |
141 | if ((crop->height/win->w.height) >= 4) | |
142 | crop->height = win->w.height * 4; | |
143 | ||
144 | if ((crop->width/win->w.width) >= 4) | |
145 | crop->width = win->w.width * 4; | |
146 | } | |
147 | return 0; | |
148 | } | |
149 | EXPORT_SYMBOL_GPL(omap_vout_new_window); | |
150 | ||
151 | /* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to | |
152 | * the nearest supported configuration. The image render window in win will | |
153 | * also be adjusted if necessary. The preview window is adjusted such that the | |
154 | * horizontal and vertical rescaling ratios stay constant. If the render | |
155 | * window would fall outside the display boundaries, the cropping rectangle | |
156 | * will also be adjusted to maintain the rescaling ratios. If successful, crop | |
157 | * and win are updated. | |
158 | * Returns zero if succesful, or -EINVAL if the requested cropping rectangle is | |
159 | * impossible and cannot reasonably be adjusted. | |
160 | */ | |
161 | int omap_vout_new_crop(struct v4l2_pix_format *pix, | |
162 | struct v4l2_rect *crop, struct v4l2_window *win, | |
163 | struct v4l2_framebuffer *fbuf, const struct v4l2_rect *new_crop) | |
164 | { | |
165 | struct v4l2_rect try_crop; | |
166 | unsigned long vresize, hresize; | |
167 | ||
168 | /* make a working copy of the new_crop rectangle */ | |
169 | try_crop = *new_crop; | |
170 | ||
171 | /* adjust the cropping rectangle so it fits in the image */ | |
172 | if (try_crop.left < 0) { | |
173 | try_crop.width += try_crop.left; | |
174 | try_crop.left = 0; | |
175 | } | |
176 | if (try_crop.top < 0) { | |
177 | try_crop.height += try_crop.top; | |
178 | try_crop.top = 0; | |
179 | } | |
180 | try_crop.width = (try_crop.width < pix->width) ? | |
181 | try_crop.width : pix->width; | |
182 | try_crop.height = (try_crop.height < pix->height) ? | |
183 | try_crop.height : pix->height; | |
184 | if (try_crop.left + try_crop.width > pix->width) | |
185 | try_crop.width = pix->width - try_crop.left; | |
186 | if (try_crop.top + try_crop.height > pix->height) | |
187 | try_crop.height = pix->height - try_crop.top; | |
188 | ||
189 | try_crop.width &= ~1; | |
190 | try_crop.height &= ~1; | |
191 | ||
192 | if (try_crop.width <= 0 || try_crop.height <= 0) | |
193 | return -EINVAL; | |
194 | ||
195 | if (cpu_is_omap24xx()) { | |
196 | if (crop->height != win->w.height) { | |
197 | /* If we're resizing vertically, we can't support a | |
198 | * crop width wider than 768 pixels. | |
199 | */ | |
200 | if (try_crop.width > 768) | |
201 | try_crop.width = 768; | |
202 | } | |
203 | } | |
204 | /* vertical resizing */ | |
205 | vresize = (1024 * crop->height) / win->w.height; | |
206 | if (cpu_is_omap24xx() && (vresize > 2048)) | |
207 | vresize = 2048; | |
208 | else if (cpu_is_omap34xx() && (vresize > 4096)) | |
209 | vresize = 4096; | |
210 | ||
211 | win->w.height = ((1024 * try_crop.height) / vresize) & ~1; | |
212 | if (win->w.height == 0) | |
213 | win->w.height = 2; | |
214 | if (win->w.height + win->w.top > fbuf->fmt.height) { | |
215 | /* We made the preview window extend below the bottom of the | |
216 | * display, so clip it to the display boundary and resize the | |
217 | * cropping height to maintain the vertical resizing ratio. | |
218 | */ | |
219 | win->w.height = (fbuf->fmt.height - win->w.top) & ~1; | |
220 | if (try_crop.height == 0) | |
221 | try_crop.height = 2; | |
222 | } | |
223 | /* horizontal resizing */ | |
224 | hresize = (1024 * crop->width) / win->w.width; | |
225 | if (cpu_is_omap24xx() && (hresize > 2048)) | |
226 | hresize = 2048; | |
227 | else if (cpu_is_omap34xx() && (hresize > 4096)) | |
228 | hresize = 4096; | |
229 | ||
230 | win->w.width = ((1024 * try_crop.width) / hresize) & ~1; | |
231 | if (win->w.width == 0) | |
232 | win->w.width = 2; | |
233 | if (win->w.width + win->w.left > fbuf->fmt.width) { | |
234 | /* We made the preview window extend past the right side of the | |
235 | * display, so clip it to the display boundary and resize the | |
236 | * cropping width to maintain the horizontal resizing ratio. | |
237 | */ | |
238 | win->w.width = (fbuf->fmt.width - win->w.left) & ~1; | |
239 | if (try_crop.width == 0) | |
240 | try_crop.width = 2; | |
241 | } | |
242 | if (cpu_is_omap24xx()) { | |
243 | if ((try_crop.height/win->w.height) >= 2) | |
244 | try_crop.height = win->w.height * 2; | |
245 | ||
246 | if ((try_crop.width/win->w.width) >= 2) | |
247 | try_crop.width = win->w.width * 2; | |
248 | ||
249 | if (try_crop.width > 768) { | |
250 | /* The OMAP2420 vertical resizing line buffer is | |
251 | * 768 pixels wide. If the cropped image is wider | |
252 | * than 768 pixels then it cannot be vertically resized. | |
253 | */ | |
254 | if (try_crop.height != win->w.height) | |
255 | try_crop.width = 768; | |
256 | } | |
257 | } else if (cpu_is_omap34xx()) { | |
258 | if ((try_crop.height/win->w.height) >= 4) | |
259 | try_crop.height = win->w.height * 4; | |
260 | ||
261 | if ((try_crop.width/win->w.width) >= 4) | |
262 | try_crop.width = win->w.width * 4; | |
263 | } | |
264 | /* update our cropping rectangle and we're done */ | |
265 | *crop = try_crop; | |
266 | return 0; | |
267 | } | |
268 | EXPORT_SYMBOL_GPL(omap_vout_new_crop); | |
269 | ||
270 | /* Given a new format in pix and fbuf, crop and win | |
271 | * structures are initialized to default values. crop | |
272 | * is initialized to the largest window size that will fit on the display. The | |
273 | * crop window is centered in the image. win is initialized to | |
274 | * the same size as crop and is centered on the display. | |
275 | * All sizes and offsets are constrained to be even numbers. | |
276 | */ | |
277 | void omap_vout_new_format(struct v4l2_pix_format *pix, | |
278 | struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop, | |
279 | struct v4l2_window *win) | |
280 | { | |
281 | /* crop defines the preview source window in the image capture | |
282 | * buffer | |
283 | */ | |
284 | omap_vout_default_crop(pix, fbuf, crop); | |
285 | ||
286 | /* win defines the preview target window on the display */ | |
287 | win->w.width = crop->width; | |
288 | win->w.height = crop->height; | |
289 | win->w.left = ((fbuf->fmt.width - win->w.width) >> 1) & ~1; | |
290 | win->w.top = ((fbuf->fmt.height - win->w.height) >> 1) & ~1; | |
291 | } | |
292 | EXPORT_SYMBOL_GPL(omap_vout_new_format); | |
293 |