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 29MODULE_AUTHOR("Texas Instruments"); 30MODULE_DESCRIPTION("OMAP Video library"); 31MODULE_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 */ 39void 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} 51EXPORT_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 */ 59int 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} 97EXPORT_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 */ 107int 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} 149EXPORT_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 */ 161int 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} 268EXPORT_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 */ 277void 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} 292EXPORT_SYMBOL_GPL(omap_vout_new_format); 293