原来本来说是不公开源码的 现在发现也没什么价值了 以下公布的源码支持linux3.0 linux2.6内核 linux3.1内核v4l2构架发生了变化 同时支持hdmi输出与tv输出 使用的板子是 斯道icool210
源码是根据android里的libhdmi库进行整理的 这里是基于linux2.6.35内核测试成功
/*
* hidmitest.c
*
* hclydao<hclydao@163.com>
*
* 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.youkuaiyun.com/detail/hclydao/8360065
============================================
作者:hclydao
http://blog.youkuaiyun.com/hclydao
版权没有,但是转载请保留此段声明
============================================