s5pv210 linux hdmi tv输出

原来本来说是不公开源码的 现在发现也没什么价值了 以下公布的源码支持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
版权没有,但是转载请保留此段声明

============================================


你可能感兴趣的:(s5pv210 linux hdmi tv输出)