📄 omap24xxcam.c
字号:
* also be adjusted to maintain the rescaling ratios. If successful, cam->crop * and cam->win are updated. * Returns zero if succesful, or -EINVAL if the requested cropping rectangle is * impossible and cannot reasonably be adjusted. */static intomap24xxcam_new_crop_rect(struct omap24xxcam_device *cam, const struct v4l2_rect *new_crop){ struct v4l2_pix_format *pix = &cam->pix; struct v4l2_window *win = &cam->win; struct v4l2_framebuffer *fbuf = &cam->fbuf; struct v4l2_rect *crop = &cam->crop; struct v4l2_rect try_crop; unsigned long vresize, hresize; /* make a working copy of the new_crop rectangle */ try_crop = *new_crop; /* adjust the cropping rectangle so it fits in the image */ if (try_crop.left < 0) { try_crop.width += try_crop.left; try_crop.left = 0; } if (try_crop.top < 0) { try_crop.height += try_crop.top; try_crop.top = 0; } try_crop.width = (try_crop.width < pix->width) ? try_crop.width : pix->width; try_crop.height = (try_crop.height < pix->height) ? try_crop.height : pix->height; if (try_crop.left + try_crop.width > pix->width) try_crop.width = pix->width - try_crop.left; if (try_crop.top + try_crop.height > pix->height) try_crop.height = pix->height - try_crop.top; try_crop.width &= ~1; try_crop.height &= ~1; if (try_crop.width <= 0 || try_crop.height <= 0) return -EINVAL; if (crop->height != win->w.height) { /* If we're resizing vertically, we can't support a crop width * wider than 768 pixels. */ if (try_crop.width > 768) try_crop.width = 768; } /* vertical resizing */ vresize = (1024*crop->height)/win->w.height; if (vresize > 2048) vresize = 2048; else if (vresize == 0) vresize = 1; win->w.height = ((1024*try_crop.height)/vresize) & ~1; if (win->w.height == 0) win->w.height = 2; if (win->w.height + win->w.top > fbuf->fmt.height) { /* We made the preview window extend below the bottom of the * display, so clip it to the display boundary and resize the * cropping height to maintain the vertical resizing ratio. */ win->w.height = (fbuf->fmt.height - win->w.top) & ~1; try_crop.height = ((vresize*win->w.height)/1024) & ~1; if (try_crop.height == 0) try_crop.height = 2; } /* horizontal resizing */ hresize = (1024*crop->width)/win->w.width; if (hresize > 2048) hresize = 2048; else if (hresize == 0) hresize = 1; win->w.width = ((1024*try_crop.width)/hresize) & ~1; if (win->w.width == 0) win->w.width = 2; if (win->w.width + win->w.left > fbuf->fmt.width) { /* We made the preview window extend past the right side of the * display, so clip it to the display boundary and resize the * cropping width to maintain the horizontal resizing ratio. */ win->w.width = (fbuf->fmt.width - win->w.left) & ~1; try_crop.width = ((hresize*win->w.width)/1024) & ~1; if (try_crop.width == 0) try_crop.width = 2; } /* update our cropping rectangle and we're done */ *crop = try_crop; return 0;}/* Given a new preview window in new_win, adjust the preview window to the * nearest supported configuration. The adjusted preview window parameters are * returned in new_win. * Returns zero if succesful, or -EINVAL if the requested preview window is * impossible and cannot reasonably be adjusted. */static intomap24xxcam_try_preview_window(struct omap24xxcam_device *cam, struct v4l2_window *new_win){ struct v4l2_framebuffer *fbuf = &cam->fbuf; struct v4l2_rect try_win; /* make a working copy of the new_win rectangle */ try_win = new_win->w; /* adjust the preview window so it fits on the display by clipping any * offscreen areas */ if (try_win.left < 0) { try_win.width += try_win.left; try_win.left = 0; } if (try_win.top < 0) { try_win.height += try_win.top; try_win.top = 0; } try_win.width = (try_win.width < fbuf->fmt.width) ? try_win.width : fbuf->fmt.width; try_win.height = (try_win.height < fbuf->fmt.height) ? try_win.height : fbuf->fmt.height; if (try_win.left + try_win.width > fbuf->fmt.width) try_win.width = fbuf->fmt.width - try_win.left; if (try_win.top + try_win.height > fbuf->fmt.height) try_win.height = fbuf->fmt.height - try_win.top; try_win.width &= ~1; try_win.height &= ~1; if (try_win.width <= 0 || try_win.height <= 0) return -EINVAL; /* We now have a valid preview window, so go with it */ new_win->w = try_win; new_win->field = V4L2_FIELD_NONE; return 0;}/* Given a new preview window in new_win, adjust the preview window to the * nearest supported configuration. The image cropping window cam->crop * will also be adjusted if necessary. Preference is given to keeping the * preview window as close to the requested configuration as possible. If * successful, new_win, cam->win, and cam->crop are updated. * Returns zero if succesful, or -EINVAL if the requested preview window is * impossible and cannot reasonably be adjusted. */static intomap24xxcam_new_preview_window(struct omap24xxcam_device *cam, struct v4l2_window *new_win){ struct v4l2_window *win = &cam->win; struct v4l2_rect *crop = &cam->crop; int err; err = omap24xxcam_try_preview_window(cam, new_win); if (err) return err; /* update our preview window */ win->w = new_win->w; win->field = new_win->field; win->chromakey = new_win->chromakey; /* adjust the cropping window to allow for resizing limitations */ if (crop->height/win->w.height >= 2) { /* The maximum vertical downsizing ratio is 2:1 */ crop->height = win->w.height*2; } if (crop->width/win->w.width >= 2) { /* The maximum horizontal downsizing ratio is 2:1 */ crop->width = win->w.width*2; } if (crop->width > 768) { /* The OMAP2420 vertical resizing line buffer is 768 pixels * wide. If the cropped image is wider than 768 pixels then it * cannot be vertically resized. */ if (crop->height != win->w.height) crop->width = 768; } return 0;}/* Given a capture format in cam->pix, the cam->crop, cam->win, and cam->fbuf * structures are initialized to default values. cam->fbuf is initialized by * reading the display controller registers for the graphics window. cam->crop * is initialized to the largest window size that will fit on the display. The * crop window is centered in the captured image. cam->win is initialized to * the same size as cam->crop and is centered on the display. * All sizes and offsets are constrained to be even numbers. */static voidomap24xxcam_new_capture_format(struct omap24xxcam_device *cam){ struct v4l2_rect *crop = &cam->crop; struct v4l2_window *win = &cam->win; struct v4l2_framebuffer *fbuf = &cam->fbuf; /* get the framebuffer parameters */ omap24xxcam_g_fbuf(cam); /* crop defines the preview source window in the image capture * buffer */ omap24xxcam_default_crop_rect(cam, crop); /* win defines the preview target window on the display */ win->w.width = crop->width; win->w.height = crop->height; win->w.left = ((fbuf->fmt.width - win->w.width) >> 1) & ~1; win->w.top = ((fbuf->fmt.height - win->w.height) >> 1) & ~1;}/* Program the camera interface xclk for the frequency cam->xclk based on * the functional clock frequency cam->mclk. If the specifed cam->xclk * frequency is not possible based on the value of cam->mclk, then the * closest xclk frequency lower than the specified xclk will be selected. * The actual xclk frequency is returned in cam->xclk. If cam->xclk is zero, * then xclk is turned off (stable low value). */static voidomap24xxcam_set_xclk(struct omap24xxcam_device *cam){ unsigned long divisor; if (cam->mclk == 0) cam->mclk = 96000000; /* supply a default mclk */ if (cam->xclk == 0) { cc_reg_out(cam, CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW); return; } if (cam->xclk > cam->mclk) cam->xclk = cam->mclk; divisor = cam->mclk/cam->xclk; if (cam->xclk*divisor < cam->mclk) divisor += 1; if (divisor > 30) divisor = 30; cam->xclk = cam->mclk/divisor; if (divisor == 1) cc_reg_out(cam, CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_BYPASS); else cc_reg_out(cam, CC_CTRL_XCLK, divisor);}/* Write the color space conversion coefficients to the display controller * registers. Each coefficient is a signed 11-bit integer in the range * [-1024, 1023]. The matrix coefficients are: * [ RY RCr RCb ] * [ GY GCr GCb ] * [ BY BCr BCb ] */static voidomap24xxcam_set_colorconv(struct omap24xxcam_device *cam, const short int mtx[3][3], int v){ unsigned long ccreg; ccreg = (mtx[0][0] & 0x7ff) | ((mtx[0][1] & 0x7ff) << 16); dispc_reg_out(cam, DISPC_VID_CONV_COEF0(v), ccreg); ccreg = (mtx[0][2] & 0x7ff) | ((mtx[1][0] & 0x7ff) << 16); dispc_reg_out(cam, DISPC_VID_CONV_COEF1(v), ccreg); ccreg = (mtx[1][1] & 0x7ff) | ((mtx[1][2] & 0x7ff) << 16); dispc_reg_out(cam, DISPC_VID_CONV_COEF2(v), ccreg); ccreg = (mtx[2][0] & 0x7ff) | ((mtx[2][1] & 0x7ff) << 16); dispc_reg_out(cam, DISPC_VID_CONV_COEF3(v), ccreg); ccreg = mtx[2][2] & 0x7ff; dispc_reg_out(cam, DISPC_VID_CONV_COEF4(v), ccreg);}/* Write the horizontal and vertical resizing coefficients to the display * controller registers. Each coefficient is a signed 8-bit integer in the * range [-128, 127] except for the middle coefficient (vc[1][i] and hc[3][i]) * which is an unsigned 8-bit integer in the range [0, 255]. The first index of * the matrix is the coefficient number (0 to 2 vertical or 0 to 4 horizontal) * and the second index is the phase (0 to 7). */static voidomap24xxcam_set_resize(struct omap24xxcam_device *cam, const short int vc[3][8], const short int hc[5][8], int v){ int i; unsigned long reg; for (i = 0; i < 8; i++) { reg = (hc[0][i] & 0xff) | ((hc[1][i] & 0xff) << 8) | ((hc[2][i] & 0xff) << 16) | ((hc[3][i] & 0xff) << 24); dispc_reg_out(cam, DISPC_VID_FIR_COEF_H(v, i), reg); reg = (hc[4][i] & 0xff) | ((vc[0][i] & 0xff) << 8) | ((vc[1][i] & 0xff) << 16) | ((vc[2][i] & 0xff) << 24); dispc_reg_out(cam, DISPC_VID_FIR_COEF_HV(v, i), reg); }}static voidomap24xxcam_configure_overlay(struct omap24xxcam_device *cam, struct omap24xx_vid2_format *vid2_format){ int v; struct v4l2_window *win = &cam->win; struct v4l2_rect *crop = &cam->crop; struct v4l2_pix_format *pix; struct v4l2_framebuffer *fbuf = &cam->fbuf; int vid_position_x, vid_position_y; unsigned long vid_position, vid_size, vid_picture_size; unsigned long vid_attributes; unsigned long firvinc, firhinc; /* color space conversion matrices */ const static short int cc_bt601[3][3] = { { 298, 409, 0 }, { 298, -208, -100 }, { 298, 0, 517 } }; const static short int cc_bt709[3][3] = { { 298, 459, 0 }, { 298, -137, -55 }, { 298, 0, 541 } }; const static short int cc_bt601_full[3][3] = { { 256, 351, 0 }, { 256, -179, -86 }, { 256, 0, 443 } }; /* vertical resizing matrix */ const static short int vc[3][8] = { { 0, 3, 12, 32, 0, 7, 5, 2 }, { 128, 123, 111, 89, 64, 89, 111, 123 }, { 0, 2, 5, 7, 64, 32, 12, 3 } }; /* horizontal resizing matrix */ const static short int hc[5][8] = { { 0, -1, -2, -5, 0, -2, -1, 0 }, { 0, 13, 30, 51, -9, -11, -11, -8 }, { 128, 124, 112, 95, 73, 95, 112, 124 }, { 0, -8, -11, -11, 73, 51, 30, 13 }, { 0, 0, -1, -2, -9, -5, -2, -1 } }; if (vid2_format) { pix = &vid2_format->pix; v = cam->vid2; } else { pix = &cam->pix; v = cam->vid1; } /* make sure the video overlay is disabled before we reconfigure it */ omap24xxcam_disable_vlayer(cam,v); /* configure the video attributes register */ vid_attributes = 0; switch (pix->pixelformat) { case V4L2_PIX_FMT_YUYV: vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFORMAT_YUV2; vid_attributes |= DISPC_VID_ATTRIBUTES_VIDCOLORCONVENABLE; break; case V4L2_PIX_FMT_UYVY: vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFORMAT_UYVY; vid_attributes |= DISPC_VID_ATTRIBUTES_VIDCOLORCONVENABLE; break; case V4L2_PIX_FMT_RGB565: default: vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFORMAT_RGB16; vid_attributes |= ((cam->gfx_attributes & DISPC_GFX_ATTRIBUTES_GFXREPLICATIONENABLE) << 5); break; case V4L2_PIX_FMT_RGB565X: vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFORMAT_RGB16; vid_attributes |= DISPC_VID_ATTRIBUTES_VIDENDIANNESS; vid_attributes |= ((cam->gfx_attributes & DISPC_GFX_ATTRIBUTES_GFXREPLICATIONENABLE) << 5); break; } if (cam->gfx_attributes & DISPC_GFX_ATTRIBUTES_GFXCHANNELOUT) vid_attributes |= DISPC_VID_ATTRIBUTES_VIDCHANNELOUT; vid_attributes |= ((cam->gfx_attributes & DISPC_GFX_ATTRIBUTES_GFXBURSTSIZE) << 8); switch (pix->colorspace) { case V4L2_COLORSPACE_SMPTE170M: case V4L2_COLORSPACE_SMPTE240M: case V4L2_COLORSPACE_BT878: case V4L2_COLORSPACE_470_SYSTEM_M: case V4L2_COLORSPACE_470_SYSTEM_BG: /* luma (Y) range lower limit is 16, BT.601 standard */ omap24xxcam_set_colorconv(cam, cc_bt601, v); break; case V4L2_COLORSPACE_REC709: /* luma (Y) range lower limit is 16, BT.709 standard */ omap24xxcam_set_colorconv(cam, cc_bt709, v); break; case V4L2_COLORSPACE_JPEG: case V4L2_COLORSPACE_SRGB: /* full luma (Y) range, assume BT.601 standard */ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFULLRANGE; omap24xxcam_set_colorconv(cam, cc_bt601_full, v); break; } if (!vid2_format) { /* use win and crop if it is for overlay */ if (win->w.width != crop->width) { vid_attributes |= DISPC_VID_ATTRIBUTES_VIDRESIZEENABLE_HRESIZE; if (win->w.width < crop->width) vid_attributes |= DISPC_VID_ATTRIBUTES_VIDHRESIZECONF; } if (win->w.height != crop->height) { vid_attributes |= DISPC_VID_ATTRIBUTES_VIDRESIZEENABLE_VRESIZE; if (win->w.height < crop->height) vid_attributes |= DISPC_VID_ATTRIBUTES_VIDVRESIZECONF; } } dispc_reg_out(cam, DISPC_VID_ATTRIBUTES(v), vid_attributes); /* configure transparency color key */ if (fbuf->flags & V4L2_FBUF_FLAG_CHROMAKEY) { /* enable chromakey */ if (vid_attributes & DISPC_VID_ATTRIBUTES_VIDCHANNELOUT) { /* digital output channel */ dispc_reg_out(cam, DISPC_TRANS_COLOR1, win->chromakey); dispc_reg_merge(cam, DISPC_CONFIG, DISPC_CONFIG_TCKDIGENABLE, DISPC_CONFIG_TCKDIGSELECTION | DISPC_CONFIG_TCKDIGENABLE); } else { /* LCD */ dispc_reg_out(cam, DISPC_TRANS_COLOR0, win->chromakey); dispc_reg_merge(cam, DISPC_CONFIG, DISPC_CONFIG_TCKLCDENABLE, DISPC_CONFIG_TCKLCDSELECTION | DISPC_CONFIG_TCKLCDENABLE); } } else { /* disable chromakey */ if (vid_attributes & DISPC_VID_ATTRIBUTES_VIDCHANNELOUT) { /* digital output channel */ dispc_reg_merge(cam, DISPC_CONFIG, 0, DISPC_CONFIG_TCKDIGSELECTION | DISPC_CONFIG_TCKDIGENABLE); } else { /* LCD */ dispc_reg_merge(cam, DISPC_CONFIG, 0, DISPC_CONFIG_TCKLCDSELECTION | DISPC_CONFIG_TCKLCDENABLE); } } /* initialize the resizing filter */ omap24xxcam_set_resize(cam, vc, hc, v);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -