原来本来说是不公开源码的 现在发现也没什么价值了 以下公布的源码支持linux3.0 linux2.6内核 linux3.1内核v4l2构架发生了变化 同时支持hdmi输出与tv输出 使用的板子是 斯道icool210
源码是根据android里的libhdmi库进行整理的 这里是基于linux2.6.35内核测试成功
/* * hidmitest.c * * hclydao<[email protected]> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <getopt.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/time.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <asm/types.h> #include <linux/videodev2.h> #include <linux/fb.h> #include "videodev2_samsung.h" #define HDMI_DEV "/dev/video14" #define TVOUT_DEV0 "/dev/video22" #define FIMC_DEV "/dev/video2" #define CLEAR(x) memset (&(x), 0, sizeof (x)) #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) static int fd = -1; v4l2_std_id std_id = 0; static int m_width = 0; static int m_height = 0; #define LCD_DEV "/dev/fb0" #define S3CFB_GET_LCD_ADDR _IOR ('F', 311, int) unsigned int phyLCDAddr = 0; unsigned int physYAddr = 0; static int lcd_fd = -1; static int ov_fd = -1; static int fimc_fd = -1; unsigned int mFimcRrvedPhysMemAddr; unsigned int hwver; static int out_w = 0; static int out_h = 0; struct overlay_param { struct v4l2_framebuffer overlay_frame; struct v4l2_window_s5p_tvout overlay_rect; struct v4l2_rect overlay_dst; }; typedef unsigned int dma_addr_t; struct fimc_buf { dma_addr_t base[3]; size_t length[3]; }; int lcd_open() { lcd_fd = open(LCD_DEV,O_RDWR, 0); if(lcd_fd < 0) { printf("++++++open tvout dev error\n"); return -1; } return lcd_fd; } int lcd_getaddr() { struct fb_var_screeninfo info; if (ioctl(lcd_fd, S3CFB_GET_LCD_ADDR, &phyLCDAddr) == -1) { printf("%s:ioctl(S3CFB_GET_LCD_ADDR) fail\n", __func__); return -1; } if(phyLCDAddr == 0) { printf("%s::S3CFB_GET_LCD_ADDR fail \n", __func__); return -1; } if (ioctl(lcd_fd, FBIOGET_VSCREENINFO, &info) == -1) { printf("%s:ioctl(FBIOGET_VSCREENINFO) fail\n", __func__); return -1; } m_width = info.xres; m_height = info.yres; return 0; } int hdmi_open() { fd = open(HDMI_DEV, O_RDWR); if(fd < 0) { printf("++++++open tvout dev error\n"); return fd; } return fd; } int tvout_v4l2_querycap(void) { struct v4l2_capability cap; int ret; ret = ioctl(fd, VIDIOC_QUERYCAP, &cap); if (ret < 0) { printf("tvout_v4l2_querycap VIDIOC_QUERYCAP failed %d\n", errno); return ret; } //printf("tvout_v4l2_querycap DRIVER : %s, CARD : %s, CAP.: 0x%08x\n", // cap.driver, cap.card, cap.capabilities); return ret; } int tvout_v4l2_s_std(void) { int ret; ret = ioctl(fd, VIDIOC_S_STD, &std_id); if (ret < 0) { printf("tvout_v4l2_s_std" "VIDIOC_S_STD failed %d\n", errno); return ret; } return ret; } int tvout_v4l2_enum_output(struct v4l2_output *output) { int ret; ret = ioctl(fd, VIDIOC_ENUMOUTPUT, output); return ret; } int tvout_v4l2_s_output(int index) { int ret; ret = ioctl(fd, VIDIOC_S_OUTPUT, &index); if (ret < 0) { printf("tvout_v4l2_s_output" "VIDIOC_S_OUTPUT failed %d\n", errno); return ret; } return ret; } int overlay_open() { ov_fd = open(TVOUT_DEV0, O_RDWR); if(ov_fd < 0) { printf("++++++open tv out 0 dev error\n"); return ov_fd; } return ov_fd; } int tvout_ov_s_parm(int fp, int buf_type, void *ptr) { struct v4l2_streamparm parm; struct v4l2_window_s5p_tvout *vparm = (struct v4l2_window_s5p_tvout*)ptr; int ret; parm.type = (enum v4l2_buf_type)buf_type; memcpy(parm.parm.raw_data, vparm, sizeof(struct v4l2_window_s5p_tvout)); ret = ioctl(fp, VIDIOC_S_PARM, &parm); if (ret < 0) { printf("tvout_v4l2_s_parm" "VIDIOC_S_PARM failed %d\n", errno); return ret; } return 0; } int tvout_v4l2_s_fbuf(int fp, struct v4l2_framebuffer *frame) { int ret; ret = ioctl(fp, VIDIOC_S_FBUF, frame); if (ret < 0) { printf("tvout_v4l2_s_fbuf" "VIDIOC_STREAMON failed %d\n", errno); return ret; } return 0; } int tvout_v4l2_cropcap(int fp, struct v4l2_cropcap *a) { struct v4l2_cropcap *cropcap = a; int ret; ret = ioctl(fp, VIDIOC_CROPCAP, cropcap); if (ret < 0) { printf("tvout_v4l2_cropcap" "VIDIOC_CROPCAP failed %d\n", errno); return ret; } printf("tvout_v4l2_cropcap" "bound width : %d, bound height : %d,\n", cropcap->bounds.width, cropcap->bounds.height); return ret; } int tvout_ov_s_crop(int fp, unsigned int type, struct v4l2_rect *rect) { struct v4l2_crop crop; int ret; crop.type = (enum v4l2_buf_type)type; crop.c.left = rect->left; crop.c.top = rect->top; crop.c.width = rect->width; crop.c.height = rect->height; ret = ioctl(fp, VIDIOC_S_CROP, &crop); if (ret < 0) { printf("tvout_v4l2_s_crop" "VIDIOC_S_CROP failed %d\n", errno); return ret; } return 0; } int tvout_v4l2_set_overlay(int fp) { struct overlay_param ov_param; struct v4l2_cropcap cropcap; int dst_w,dst_h; dst_w = out_w; dst_h = out_h; ov_param.overlay_frame.fmt.pixelformat = V4L2_PIX_FMT_RGB32; ov_param.overlay_frame.base = (void *)mFimcRrvedPhysMemAddr; ov_param.overlay_rect.flags = 0; ov_param.overlay_rect.priority = 0x02; ov_param.overlay_rect.win.w.left = 0; ov_param.overlay_rect.win.w.top = 0; ov_param.overlay_rect.win.w.width = dst_w; ov_param.overlay_rect.win.w.height = dst_h; ov_param.overlay_rect.win.global_alpha = 0; ov_param.overlay_dst.left = 0; ov_param.overlay_dst.top = 0; ov_param.overlay_dst.width = dst_w; ov_param.overlay_dst.height = dst_h; tvout_v4l2_s_fbuf(fp, &(ov_param.overlay_frame)); tvout_ov_s_parm(fp,V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, &(ov_param.overlay_rect)); cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY; tvout_v4l2_cropcap(fp, &cropcap); if( ov_param.overlay_dst.width <= cropcap.bounds.width && ov_param.overlay_dst.height <= cropcap.bounds.height) { tvout_ov_s_crop(fp, V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY,&(ov_param.overlay_dst)); } else { printf("[%s] invalid crop size dst.w=%d dst.h=%d bounds.w=%d bounds.h=%d\n", __func__, ov_param.overlay_dst.width, ov_param.overlay_dst.height, cropcap.bounds.width, cropcap.bounds.height); return -1; } return 0; } int tvout_v4l2_streamon(int fp, unsigned int type) { int ret; ret = ioctl(fp, VIDIOC_STREAMON, &type); if (ret < 0) { printf("tvout_v4l2_streamon" "VIDIOC_STREAMON failed %d\n", errno); return ret; } return 0; } int tvout_v4l2_start_overlay(int fp) { int ret, start = 1; ret = ioctl(fp, VIDIOC_OVERLAY, &start); if (ret < 0) { printf("tvout_v4l2_start_overlay" "VIDIOC_OVERLAY failed\n"); return ret; } return ret; } int fimc_open() { fimc_fd = open(FIMC_DEV, O_RDWR); if(fimc_fd < 0) { printf("++++++open tvout dev error\n"); return -1; } return fimc_fd; } int fimc_querycap(int fp) { struct v4l2_capability cap; int ret; ret = ioctl(fp, VIDIOC_QUERYCAP, &cap); if (ret < 0) { printf("%s VIDIOC_QUERYCAP failed %d\n",__func__, errno); return ret; } if (!(cap.capabilities & V4L2_CAP_STREAMING)) { printf("%s::%s has no streaming support\n", __func__, FIMC_DEV); return -1; } if (!(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { printf("%s::%s is no video output\n", __func__, FIMC_DEV); return -1; } return ret; } int fimc_gfmt(int fp) { struct v4l2_format fmt; int ret; fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ret = ioctl(fp, VIDIOC_G_FMT, &fmt); if (ret < 0) { printf("%s:: Error in video VIDIOC_G_FMT\n", __func__); return -1; } return ret; } int fimc_gctrl(int fp) { struct v4l2_control vc; int ret; vc.id = V4L2_CID_RESERVED_MEM_BASE_ADDR; vc.value = 0; ret = ioctl(fp, VIDIOC_G_CTRL, &vc); if (ret < 0) { printf("Error in video VIDIOC_G_CTRL - V4L2_CID_RESERVED_MEM_BAES_ADDR (%d)\n", ret); return -1; } mFimcRrvedPhysMemAddr = (unsigned int)vc.value; vc.id = V4L2_CID_FIMC_VERSION; vc.value = 0; ret = ioctl(fp, VIDIOC_G_CTRL, &vc); if (ret < 0) { printf("Error in video VIDIOC_G_CTRL - V4L2_CID_FIMC_VERSION (%d), FIMC version is set with default\n", ret); vc.value = 0x43; return -1; } hwver = vc.value; return ret; } int fimc_sctrl(int fp) { struct v4l2_control vc; int ret; vc.id = V4L2_CID_OVLY_MODE; vc.value = 0x3; ret = ioctl(fp, VIDIOC_S_CTRL, &vc); if (ret < 0) { printf("Error in video VIDIOC_S_CTRL - V4L2_CID_OVLY_MODE (%d)\n",ret); return -1; } return ret; } int fimc_v4l2_set_src(int fd, unsigned int hw_ver) { struct v4l2_format fmt; struct v4l2_crop crop; int ret_val; fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; fmt.fmt.pix.width = m_width; fmt.fmt.pix.height = m_height; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; fmt.fmt.pix.field = V4L2_FIELD_NONE; ret_val = ioctl (fd, VIDIOC_S_FMT, &fmt); if (ret_val < 0) { printf("VIDIOC_S_FMT failed : ret=%d\n", ret_val); return -1; } crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; if(hw_ver == 0x50) { crop.c.left = 0; crop.c.top = 0; } else { crop.c.left = 0; crop.c.top = 0; } crop.c.width = m_width; crop.c.height = m_height; ret_val = ioctl(fd, VIDIOC_S_CROP, &crop); if (ret_val < 0) { printf("Error in video VIDIOC_S_CROP (%d)\n",ret_val); return -1; } return ret_val; } int fimc_v4l2_req_buf(int fd, int num_bufs, int cacheable_buffers) { struct v4l2_requestbuffers reqbuf; int ret; reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; reqbuf.memory = V4L2_MEMORY_USERPTR; reqbuf.count = num_bufs; ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf); if (ret < 0) { printf("+++++reqbuf ioctl error"); return ret; } if (reqbuf.count > num_bufs) { printf("++Not enough buffer structs passed to get_buffers"); return -ENOMEM; } return 0; } int fimc_v4l2_set_dst(int fd,int rotation, unsigned int addr) { struct v4l2_format sFormat; struct v4l2_control vc; struct v4l2_framebuffer fbuf; int ret_val; /* * set rotation configuration */ vc.id = V4L2_CID_ROTATION; vc.value = rotation; ret_val = ioctl(fd, VIDIOC_S_CTRL, &vc); if (ret_val < 0) { printf("Error in video VIDIOC_S_CTRL - rotation (%d)\n",ret_val); return -1; } /* * set size, format & address for destination image (DMA-OUTPUT) */ ret_val = ioctl(fd, VIDIOC_G_FBUF, &fbuf); if (ret_val < 0) { printf("Error in video VIDIOC_G_FBUF (%d)\n", ret_val); return -1; } fbuf.base = (void *)addr; fbuf.fmt.width = out_w; fbuf.fmt.height = out_h; fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB32; ret_val = ioctl (fd, VIDIOC_S_FBUF, &fbuf); if (ret_val < 0) { printf("Error in video VIDIOC_S_FBUF (%d)\n",ret_val); return -1; } /* * set destination window */ sFormat.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; sFormat.fmt.win.w.left = 0; sFormat.fmt.win.w.top = 0; sFormat.fmt.win.w.width = out_w; sFormat.fmt.win.w.height = out_h; ret_val = ioctl(fd, VIDIOC_S_FMT, &sFormat); if (ret_val < 0) { printf("Error in video VIDIOC_S_FMT (%d)\n",ret_val); return -1; } return 0; } int fimc_v4l2_queue(int fd, struct fimc_buf *fimc_buf, int index) { struct v4l2_buffer buf; int ret_val; buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; buf.memory = V4L2_MEMORY_USERPTR; buf.m.userptr = (unsigned long)fimc_buf; buf.length = 0; buf.index = index; ret_val = ioctl (fd, VIDIOC_QBUF, &buf); if (ret_val < 0) { printf("Error in VIDIOC_QBUF : (%d) \n", ret_val); return -1; } return 0; } int fimc_v4l2_stream_on(int fd, enum v4l2_buf_type type) { if (ioctl (fd, VIDIOC_STREAMON, &type) < 0) { printf("Error in VIDIOC_STREAMON\n"); return -1; } return 0; } int fimc_v4l2_dequeue(int fd) { struct v4l2_buffer buf; buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; buf.memory = V4L2_MEMORY_USERPTR; if (ioctl (fd, VIDIOC_DQBUF, &buf) < 0) { printf("Error in VIDIOC_DQBUF\n"); return -1; } return buf.index; } int main(int argc, char *argv[]) { struct v4l2_output output; unsigned int i=0,ret=0,index; struct fimc_buf fimc_sbuf; unsigned int mode = 0; unsigned int hdmi_mode = 0; unsigned int y_size = 0; if(argc != 2) { printf("usage %s mode\n",argv[0]); printf("mode is 1080,720,480,tv\n"); printf("example %s 1080\n",argv[0]); return 0; } mode = strtol(argv[1],NULL,10); switch(mode) { case 1080: std_id = V4L2_STD_1080P_60; hdmi_mode = V4L2_OUTPUT_TYPE_DIGITAL; out_w = 1920; out_h = 1080; break; case 720: std_id = V4L2_STD_720P_60; hdmi_mode = V4L2_OUTPUT_TYPE_DIGITAL; out_w = 1280; out_h = 720; break; case 480: std_id = V4L2_STD_480P_60_16_9; hdmi_mode = V4L2_OUTPUT_TYPE_DIGITAL; out_w = 720; out_h = 480; break; default: std_id = V4L2_STD_PAL_BDGHI; hdmi_mode = V4L2_OUTPUT_TYPE_COMPOSITE; out_w = 720; out_h = 576; break; } y_size = ALIGN(ALIGN(out_w,128) * ALIGN(out_h, 32), 8*1024); lcd_open(); lcd_getaddr(); physYAddr = phyLCDAddr; hdmi_open(); tvout_v4l2_querycap(); tvout_v4l2_s_std(); do { output.index = i; ret = tvout_v4l2_enum_output(&output); if(output.type == hdmi_mode) break; i++; }while(ret >=0); tvout_v4l2_s_output(output.index); fimc_open(); fimc_querycap(fimc_fd); fimc_gfmt(fimc_fd); fimc_gctrl(fimc_fd); fimc_sctrl(fimc_fd); fimc_v4l2_set_src(fimc_fd,hwver); fimc_v4l2_set_dst(fimc_fd,0,mFimcRrvedPhysMemAddr); fimc_v4l2_req_buf(fimc_fd,1,0); fimc_v4l2_stream_on(fimc_fd,V4L2_BUF_TYPE_VIDEO_OUTPUT); fimc_sbuf.base[0] = phyLCDAddr; fimc_sbuf.base[1] = phyLCDAddr + y_size; fimc_sbuf.base[2] = 0; fimc_v4l2_queue(fimc_fd,&fimc_sbuf,0); overlay_open(); tvout_v4l2_set_overlay(ov_fd); tvout_v4l2_start_overlay(ov_fd); while(1) { index = fimc_v4l2_dequeue(fimc_fd); fimc_sbuf.base[0] = phyLCDAddr; fimc_sbuf.base[1] = phyLCDAddr + y_size; fimc_sbuf.base[2] = 0; fimc_v4l2_queue(fimc_fd,&fimc_sbuf,0); } return 1; }编译生成二进制后 执行
hdmitest 480是输出480p
hdmitest 720输出720p
hdmitest 1080输出1080p
hdmitest tv是tv输出 这是默认就是tv输出
时间过的比较久了具体原理也没有完全整明白 大致原理就是获取fb数据后通过fimc转换然后进行overlay(希望没有说错)
整个源码下载地址:http://download.csdn.net/detail/hclydao/8360065
============================================
作者:hclydao
http://blog.csdn.net/hclydao
版权没有,但是转载请保留此段声明
============================================