tag 标签: 视频应用

相关博文
  • 热度 9
    2012-3-21 19:14
    1157 次阅读|
    0 个评论
    简解要介绍 mx27 中强大的视频处理功能       Freescale 公司出品的 mx27 芯片,秉承了欧美系芯片产商内部资源丰富,性能稳定可靠的设计原则。其中最为耀眼的功能就是其使用简单却又功能强大的视频处理单元。其内部的视频处理部分共有 3 个模块,分别   1.CMOS Sensor Interface 可以直接接传统的 CMOS 摄像头接口,也可以接 CCIR 视频接口,这是负责视频的采集接口部分 2. 内部集成了增强型低功耗的多媒体加速器 eMMA ,可以进行视频的前预处理和后处理以及类似去环块( dering), 色彩空间转换 , 放大和图像的平滑缩放等,这是视频的前后期处理部分 . 3. 内置硬件编解码模块,支持 H.264/MPEG4 硬件编解码,全双工不占用 CPU 资源。   我们先来介绍视频的采集和预处理部分。 视频采集芯片我们采用的是可以支持 4 路视频输入的 TW2835 。可以达到 D1 的视频效果,完全满足基本的视频监控需求     Techwell 公司推出了 TW2835 四信道视频和音频控制器。建立在 TW2834 的成功基础之上, TW2835 将 6 个主要程序整合进一个芯片中,其中包括: 4 个高质量的 NTSC/PAL 视频解码器、 4 个音频模拟数字转换器、一个音频复用器,双色显示控制器,双视频译码器以及一个先进的 OSD (屏幕菜单式调节方式)。此外, TW2835 每个芯片还使用了一个单一的同步动态存储器 (SDRAM) ,可用于可选的 BGA 包中,还拥有一个被称为 TW2836 的 pin-to-pin (管脚到管脚)姊妹芯片。 TW2836 除了不包含音频之外,与 TW2835 具有同样的功能。 TW2835 利用了 Techwell 安全监控集成电路产品解决方案的广泛组合,是帮助 DVR (数码视频录像机)生产商提高质量与功能、加快上市时间以及减少成本的重要一步。在其众多功能中, TW2835 支持详尽的实时 D1 录制、在重放过程中将信道 ID 信息添加到视频流媒体中,用于自动解码与显示,同时还包含一个 5 层的图形覆盖功能,为 OSD 、单盒、 2D 阵列箱以及鼠标指示器显示特征 / 位图。 TW2835 还包含一个简单的界面,使用多段连接支持多达 16 个信道系统。此外, TW2835 还嵌入了几种特别的监视功能,其中包括:运动监测、放大以及水平与垂直缩放控制。凭借置入旨在减少交叉噪音的反锯齿过滤器和高质量的梳状过滤器, TW2835 已经成为一种针对 DVR 与 Quad/Multiplexers 的高性能、具有成本效益的解决方案。     tw2835 比较灵活,既可以单路切换采集 4 路 D1 视频,也可以将 4 路视频集成到 1 路 D1 视频输出,可以根据你的需求在应用程序上控制。成都莱得科技( www.nidetech.com )提供的驱动程序给应用程序提供了控制接口。并且提供完整的驱动程序源代码,该方案和代码在客户的实际产品中获得了成功的验证。现在我们简要的介绍一下 tw2835 在 mx27 开发板中的驱动编写和遇到的一些问题。         一、驱动的架构和实现         tw2835 和 mx27 的视频流传输是通过 mx27 的 CSI 接口,命令控制接口采用 I2C 也就是是说驱动分为两个部分 1、   i2c 驱动: 负责初始化和配置芯片,例如设置和获取颜色,复位芯片,设置通道属性,检测芯片的存在与否,设置 csi 接口的时钟等       // 驱动初始化       static __init int tw2835_init(void)     {              u8 err;                gpio_tw2835_active();                err = i2c_add_driver(tw2835_i2c_driver);              return err;     }       // 首先要对硬件引脚功能进行初始化,     void gpio_tw2835_active(void) {   // 设置 CSI 接口的引脚功能          gpio_request_mux(MX27_PIN_CSI_D0, GPIO_MUX_PRIMARY);          gpio_request_mux(MX27_PIN_CSI_D1, GPIO_MUX_PRIMARY);          gpio_request_mux(MX27_PIN_CSI_D2, GPIO_MUX_PRIMARY);          gpio_request_mux(MX27_PIN_CSI_D3, GPIO_MUX_PRIMARY);          gpio_request_mux(MX27_PIN_CSI_D4, GPIO_MUX_PRIMARY);          gpio_request_mux(MX27_PIN_CSI_MCLK, GPIO_MUX_PRIMARY);          gpio_request_mux(MX27_PIN_CSI_PIXCLK, GPIO_MUX_PRIMARY);          gpio_request_mux(MX27_PIN_CSI_D5, GPIO_MUX_PRIMARY);          gpio_request_mux(MX27_PIN_CSI_D6, GPIO_MUX_PRIMARY);          gpio_request_mux(MX27_PIN_CSI_D7, GPIO_MUX_PRIMARY);          gpio_request_mux(MX27_PIN_CSI_VSYNC, GPIO_MUX_PRIMARY);          gpio_request_mux(MX27_PIN_CSI_HSYNC, GPIO_MUX_PRIMARY);              /* Power down control */          mdelay(10);          gpio_request_mux(MX27_PIN_USBH1_RXDM, GPIO_MUX_GPIO);          mxc_set_gpio_direction(MX27_PIN_USBH1_RXDM, 0);          mxc_set_gpio_dataout(MX27_PIN_USBH1_RXDM, 1);            /* Reset 芯片 */          mdelay(10);          gpio_request_mux(MX27_PIN_CSPI1_RDY, GPIO_MUX_GPIO);          mxc_set_gpio_direction(MX27_PIN_CSPI1_RDY, 0);          mxc_set_gpio_dataout(MX27_PIN_CSPI1_RDY, 0);          mdelay(10);          mxc_set_gpio_dataout(MX27_PIN_CSPI1_RDY, 1);          mdelay(10);   }   然后,进行调用 i2c 驱动接口, i2c_add_driver ,加入新的驱动。由框架自动调用 attach 函数 在该函数中,设定 tw2835 的主时钟,然后调用 i2c_probe 进行芯片的地址检测 static int tw2835_attach(struct i2c_adapter *adap) {          uint32_t mclk = 27000000;          struct clk *clk;          int err;            clk = clk_get(NULL, "csi_clk");          clk_enable(clk);          set_mclk_rate(mclk);            err = i2c_probe(adap, addr_data, tw2835_detect_client);          clk_disable(clk);          clk_put(clk);            return err; } 在扫描到芯片的地址和预置的地址一致的时候,调用 tw2835_detect_client 该函数           #define TW2835_I2C_ADDRESS       0x42 //tw2835 的 i2c 地址 #define TW2835_DEVICE_ID   0x05 // 芯片内部的 id ,从寄存器中读出   1. 调用 i2c_attach_client 将 adapter 设置到 tw2835_i2c_client 中 2. 将 tw2835_i2c_client 加入到 i2c 设备列表中去 3. 分配一个摄像头接口数据,设置主时钟 static int tw2835_detect_client(struct i2c_adapter *adapter, int address,                                        int kind) {          tw2835_i2c_client.adapter = adapter;          if (i2c_attach_client(tw2835_i2c_client)) {                    tw2835_i2c_client.adapter = NULL;                    printk(KERN_ERR "tw2835_detect_client: i2c_attach_client failed\n");                    return -1;          }            interface_param = (sensor_interface *)              kmalloc(sizeof(sensor_interface), GFP_KERNEL);          if (!interface_param) {                    printk(KERN_ERR "tw2835_detect_client: kmalloc failed \n");                    return -1;          }          interface_param-mclk = 27000000;            printk(KERN_INFO "TW2835 Detected\n");            return 0; }     struct camera_sensor camera_sensor_if = {          .set_color = tw2835_set_color,          .get_color = tw2835_get_color,          .set_ae_mode = tw2835_set_ae_mode,          .get_ae_mode = tw2835_get_ae_mode,          .set_ae = tw2835_set_ae,          .set_awb = tw2835_set_awb,          .flicker_control = tw2835_flicker_control,          .get_control_params = tw2835_get_control_params,          .config = tw2835_config,          .reset = tw2835_reset,          .get_status = tw2835_get_status,          .set_channel = tw2835_set_channel, }; EXPORT_SYMBOL(camera_sensor_if); 导出 camera_sensor_if ,在 v4l2 采集驱动中被使用,用来实现该芯片的控制接口,因此如果有多个视频采集芯片驱动,那么同时只能有一个驱动导出该结构体。否则会 发生冲突。     static void tw2835_interface(sensor_interface * param, u32 width, u32 height) {          param-Vsync_pol = 0x0;          param-clk_mode = 0x0;           //gated          param-pixclk_pol = 0x0;          param-data_width = 0x1;          param-data_pol = 0x0;          param-ext_vsync = 0x1;          param-Vsync_pol = 0x0;          param-Hsync_pol = 0x0;          param-width = width - 1;          param-height = height - 1;          param-pixel_fmt = IPU_PIX_FMT_UYVY;          param-mclk = 27000000;          /* setup cropping */          g_cam-crop_bounds.left = 0;          g_cam-crop_bounds.width = width;          g_cam-crop_bounds.top = 0;          g_cam-crop_bounds.height = height;          g_cam-crop_defrect = g_cam-crop_bounds;          if ((g_cam-crop_current.width g_cam-crop_bounds.width)                 || (g_cam-crop_current.height g_cam-crop_bounds.height))                    g_cam-crop_current = g_cam-crop_bounds;          g_cam-streamparm.parm.capture.capturemode = 0;            g_cam-standard.index = 0;          g_cam-standard.id = (height == 576) ? V4L2_STD_PAL : V4L2_STD_NTSC;          g_cam-standard.frameperiod.denominator = (height == 576) ? 50 : 60;          g_cam-standard.frameperiod.numerator = 1;          g_cam-standard.framelines = height; }   在 mxc_v4l2_capture.c 中定义了 cam_data *g_cam; 我们在 tw2835.c 中来填充它, 设置我们需要采集的视频的制式,场数, crop 的高度和宽度等。     typedef struct _cam_data {          struct video_device *video_dev;            /* semaphore guard against SMP multithreading */          struct semaphore busy_lock;            int open_count;            /* params lock for this camera */          struct semaphore param_lock;            /* Encorder */          struct list_head ready_q;          struct list_head done_q;          struct list_head working_q;          int ping_pong_csi;          spinlock_t int_lock;          struct mxc_v4l_frame frame ;          int skip_frame;     int overflow;          wait_queue_head_t enc_queue;          int enc_counter;          dma_addr_t rot_enc_bufs ;          void *rot_enc_bufs_vaddr ;          int rot_enc_buf_size ;          enum v4l2_buf_type type;            /* still image capture */          wait_queue_head_t still_queue;          int still_counter;          dma_addr_t still_buf;          void *still_buf_vaddr;            /* overlay */          struct v4l2_window win;          struct v4l2_framebuffer v4l2_fb;          dma_addr_t vf_bufs ;          void *vf_bufs_vaddr ;          int vf_bufs_size ;          dma_addr_t rot_vf_bufs ;          void *rot_vf_bufs_vaddr ;          int rot_vf_buf_size ;          bool overlay_active;          int output;          struct fb_info *overlay_fb;            /* v4l2 format */          struct v4l2_format v2f;          int rotation;          struct v4l2_mxc_offset offset;            /* V4l2 control bit */          int bright;          int hue;          int contrast;          int saturation;          int red;          int green;          int blue;          int ae_mode;          int ae_enable;          int awb_enable;          int flicker_ctrl;            /* standart */          struct v4l2_streamparm streamparm;          struct v4l2_standard standard;            /* crop */          struct v4l2_rect crop_bounds;          struct v4l2_rect crop_defrect;          struct v4l2_rect crop_current;            int (*enc_update_eba) (dma_addr_t eba, int *bufferNum);          int (*enc_enable) (void *private);          int (*enc_disable) (void *private);          void (*enc_callback) (u32 mask, void *dev);          int (*vf_start_adc) (void *private);          int (*vf_stop_adc) (void *private);          int (*vf_start_sdc) (void *private);          int (*vf_stop_sdc) (void *private);          int (*csi_start) (void *private);          int (*csi_stop) (void *private);            /* misc status flag */          bool overlay_on;          bool capture_on;          int overlay_pid;          int capture_pid;          bool low_power;          wait_queue_head_t power_queue;            /* camera sensor interface */          struct camera_sensor *cam_sensor; } cam_data;   2、   v4l2 采集驱动以及显示驱动 负责控制 csi 接口采集视频,并实现标准的的 v4l2 接口,给应用程序调用。这是中应用层访问视频的标志接口。       二、常见问题。         1. 视频出现串扰现象         最后查出是使用了不合格的 tvs 管     2. 视频上出现了有规则的横向水波纹         将 TW2835 的 1.8V DC-DC 供电改为 1.8V LDO 供电消除开关噪声,无水波纹出现     3. 运行时 1 , 2 路的图像下部和 3 , 4 路蓝屏图像一起闪动         将 TW2835 的输出范围由 1 ~ 254 调整为 16 ~ 235     4. 运行一段时间后视频死掉         软件调整码流匹配 文章版权属于成都莱得科技有限责任公司所有,转载请注明出处。
相关资源