s5pv210 jpeg硬件编码

做qt摄像头程序的时候发现yuv转rgb然后显示 效果很不好 所以考虑转jpg后显示 但是使用libjpeg发现格式怎么设置都不对 之前在android上使用的函数拿过来都不能直接使用 所以还是研究硬编吧 这里使用的是广州斯道ICOOL210开发板 内核版本linux2.6.35

前面的一些流程我就不上代码了标准的v4l2流程 格式设置为V4L2_PIX_FMT_YUYV即yuv422格式 宽 640 高 480 主要是在获取到yuv数据后转成jpg然后保存 摄像头的程序网上有大把的例子 我这里比较乱我只放增加的函数了

首先把内核里的s3c-jpeg.h拷贝过来 这里是我的头文件

/*
 * v4l2.h
 * Author: hclydao
 */

#ifndef V4L2_H_
#define V4L2_H_
#include "s3c-jpeg.h"
#define CLEAR(x) memset (&(x), 0, sizeof (x))

void errno_exit(const char* s);
int xioctl(int fd, int request, void* argp);
void deviceOpen(void);
int select_input(int input);
void deviceInit(void);
void mmapInit(void);
void captureStart(void);
void mainLoop(void);
unsigned char* frameRead(void);
void imageProcess(const void* p);
static void deviceUninit(void);

static int jfd;
unsigned char *ydata;
static int name = 0;

struct jpg_args mArgs;

unsigned char *pInBuf;
int jpeg_init(void);
int test;
int jpg_enc(const void *p,int len);
#endif /* V4L2_H_ */</span>

我还是上代码吧 前面的这些流程完全都是标准的 网上的说明很详细 这里就不说明了

<span style="font-size:14px;">/*
 * v4l2.c
 * Author: hclydao
 */

#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 <malloc.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 <jpeglib.h>
#include <linux/fb.h>

#include "v4l2.h"

struct buffer {
        void *                  start;
        size_t                  length;
};

int              fd              = -1;
struct buffer *         buffers         = NULL;
static unsigned int     n_buffers       = 0;

// global settings
static unsigned int width = 640;
static unsigned int height = 480;
static char* deviceName = "/dev/video0";

static char* jpgdev = "/dev/s3c-jpg";

static int fb_bpp;
static int cam_fp = -1;
static int fb_fp = -1;
static char *fb_addr = NULL;

void deviceOpen(void)
{
	struct stat st;

	// stat file
	if (-1 == stat(deviceName, &st)) {
		fprintf(stderr, "Cannot identify '%s': %d, %s\n", deviceName, errno, strerror (errno));
		exit(EXIT_FAILURE);
	}
	// check if its device
	if (!S_ISCHR (st.st_mode)) {
		fprintf(stderr, "%s is no device\n", deviceName);
		exit(EXIT_FAILURE);
	}
	// open device
	fd = open(deviceName, O_RDWR /* required */ | O_NONBLOCK, 0);
	// check if opening was successfull
	if (-1 == fd) {
		fprintf(stderr, "Cannot open '%s': %d, %s\n", deviceName, errno, strerror (errno));
		exit(EXIT_FAILURE);
	}
}

int select_input(int input)
{
	int ret;

	ret = xioctl(fd, VIDIOC_S_INPUT, &input);
	if (ret) {
		printf("xioctl VIDIOC_S_INPUT failed errno(%d)\n", errno);
	}   

	return ret;
}
/**
  initialize device
*/
void deviceInit(void)
{
	struct v4l2_capability cap;
	struct v4l2_format fmt;

	unsigned int min;

	if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {
		if (EINVAL == errno) {
			fprintf(stderr, "%s is no V4L2 device\n",deviceName);
			exit(EXIT_FAILURE);
		} else {
			errno_exit("VIDIOC_QUERYCAP");
		}
	}

	if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
	{
		fprintf(stderr, "%s is no video capture device\n",deviceName);
		exit(EXIT_FAILURE);
	}

    if (!(cap.capabilities & V4L2_CAP_STREAMING))
    {
   		fprintf(stderr, "%s does not support streaming i/o\n",deviceName);
   		exit(EXIT_FAILURE);
    }

  	 CLEAR (fmt);

  // v4l2_format
  	  fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  	  fmt.fmt.pix.width       = width;
  	  fmt.fmt.pix.height      = height;
  	  fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_RGB32;
	  fmt.fmt.pix.field = V4L2_FIELD_NONE;//V4L2_FIELD_INTERLACED;//V4L2_FIELD_NONE;
      fmt.fmt.pix.priv = 1;

  	  if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
  		  errno_exit("VIDIOC_S_FMT");

  	  /* Note VIDIOC_S_FMT may change width and height. */
  	  if (width != fmt.fmt.pix.width) {
  		  width = fmt.fmt.pix.width;
  		  fprintf(stderr,"Image width set to %i by device %s.\n",width,deviceName);
  	  }
  	  if (height != fmt.fmt.pix.height) {
  		  height = fmt.fmt.pix.height;
  		  fprintf(stderr,"Image height set to %i by device %s.\n",height,deviceName);
  	  }

  	  /* Buggy driver paranoia. */
  	  min = fmt.fmt.pix.width * 2;
  	  if (fmt.fmt.pix.bytesperline < min)
  		  fmt.fmt.pix.bytesperline = min;

  	  min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
  	  if (fmt.fmt.pix.sizeimage < min)
  		  fmt.fmt.pix.sizeimage = min;

  	  mmapInit();
}

void mmapInit(void)
{
	struct v4l2_requestbuffers req;

	CLEAR (req);

	req.count               = 4;
	req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	req.memory              = V4L2_MEMORY_MMAP;

	if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
		if (EINVAL == errno) {
			fprintf(stderr, "%s does not support memory mapping\n", deviceName);
			exit(EXIT_FAILURE);
    } else {
    	errno_exit("VIDIOC_REQBUFS");
    	}
	}

	if (req.count < 2) {
		fprintf(stderr, "Insufficient buffer memory on %s\n", deviceName);
		exit(EXIT_FAILURE);
	}

	buffers = calloc(req.count, sizeof(*buffers));

	if (!buffers) {
		fprintf(stderr, "Out of memory\n");
		exit(EXIT_FAILURE);
	}

	for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
		struct v4l2_buffer buf;

		CLEAR (buf);

		buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory      = V4L2_MEMORY_MMAP;
		buf.index       = n_buffers;

	if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
		errno_exit("VIDIOC_QUERYBUF");

    buffers[n_buffers].length = buf.length;

    buffers[n_buffers].start =
    mmap (NULL /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, fd, buf.m.offset);

    if (MAP_FAILED == buffers[n_buffers].start)
    	errno_exit("mmap");
	}
}

void captureStart(void)
{
	unsigned int i;
	enum v4l2_buf_type type;

    for (i = 0; i < n_buffers; ++i)
    {
   		struct v4l2_buffer buf;

   		CLEAR (buf);
   		buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   		buf.memory      = V4L2_MEMORY_MMAP;
   		buf.index       = i;

   		if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
   			errno_exit("VIDIOC_QBUF");
  	}

   	type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

   	if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
    	errno_exit("VIDIOC_STREAMON");
}

void mainLoop(void)
{
	unsigned int count;
	count = 1;

	while (count-- > 0) {
		for (;;) {
			fd_set fds;
			struct timeval tv;
			int r;

			FD_ZERO(&fds);
			FD_SET(fd, &fds);

			/* Timeout. */
			tv.tv_sec = 2;
			tv.tv_usec = 0;

			r = select(fd + 1, &fds, NULL, NULL, &tv);

			if (-1 == r) {
				if (EINTR == errno)
					continue;
				errno_exit("select");
			}

		if (0 == r) {
			fprintf (stderr, "select timeout\n");
			exit(EXIT_FAILURE);
		}
		if (frameRead())
			break;
    }
  }
}

unsigned char* frameRead(void)
{

	struct v4l2_buffer buf;

	CLEAR (buf);

	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	buf.memory = V4L2_MEMORY_MMAP;

	if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
		switch (errno) {
			case EAGAIN:
				return 0;

			case EIO:
			default:
				errno_exit("VIDIOC_DQBUF");
		}
	}
	assert (buf.index < n_buffers);
	//imageProcess(buffers[buf.index].start);
	if(test > 44)//放弃前面的数据
		jpg_enc(buffers[buf.index].start,buffers[buf.index].length);
	if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
		errno_exit("VIDIOC_QBUF");
  return (unsigned char*)buffers[buf.index].start;
}

void imageProcess(const void* p)
{

	unsigned char* src = (unsigned char*)p;
	
    	memcpy(&fb_addr[0],src,width*height*4);

}

void deviceUninit(void)
{
  unsigned int i;

  	  for (i = 0; i < n_buffers; ++i)
  	  {
      if (-1 == munmap (buffers[i].start, buffers[i].length))
        errno_exit("munmap");
  	  }

  free(buffers);
}

void errno_exit(const char* s)
{
	fprintf(stderr, "%s error %d, %s\n", s, errno, strerror (errno));
	exit(EXIT_FAILURE);
}

int xioctl(int fd, int request, void* argp)
{
	int r;
	do r = ioctl(fd, request, argp);
	while (-1 == r && EINTR == errno);

	return r;
}

int jpg_enc(const void *p,int len)//编码函数
{
	FILE *fp;
	char tmp[20];
	int err;
	enum jpg_return_status ret = JPG_FAIL;
	unsigned char* src = (unsigned char*)p;
	memcpy(pInBuf, src, len);
	ret = (enum jpg_return_status)ioctl(jfd, IOCTL_JPG_ENCODE, &mArgs);
    if (ret != JPG_SUCCESS) {
		printf("++++++++IOCTL_JPG_ENCODE failed\n");
		return -1;
	}
	mArgs.out_buf = (char *)ioctl(jfd, IOCTL_JPG_GET_STRBUF, mArgs.mapped_addr);
	sprintf(tmp, "%d.jpg", name++);
	fp = fopen(tmp,"wb");
	if(fp < 0) {
		printf("+++++++++++=open file %s failed\n",tmp);
		return -1;
	}
	err = fwrite(mArgs.out_buf,sizeof(char),mArgs.enc_param->file_size,fp);
	if(err < 0) {
		printf("+++++++++++=write data failed\n");
		return -1;
	}
	fclose(fp);
	return mArgs.enc_param->file_size;
}

int jpeg_init(void)//jpg初始化
{
	jfd = open(jpgdev,O_RDWR);
	if(jfd < 0) {
		printf("++++open jfd failed\n");
		return -1;
	}

	mArgs.mapped_addr = mmap(0,640*480*4,PROT_READ | PROT_WRITE,MAP_SHARED, jfd, 0);
	if(mArgs.mapped_addr == MAP_FAILED) {
		printf("++++addr_base mmap failed\n");
		return -1;
	}
	
	mArgs.enc_param = (struct jpg_enc_proc_param *)malloc(sizeof(struct jpg_enc_proc_param));
	if(mArgs.enc_param == NULL) {
		printf("++++enc_param malloc failed\n");
		return -1;
	}
	memset(mArgs.enc_param,0,sizeof(struct jpg_enc_proc_param));

    mArgs.enc_param->sample_mode = JPG_422;
    mArgs.enc_param->enc_type = JPG_MAIN;
	mArgs.enc_param->in_format = JPG_MODESEL_YCBCR;
	mArgs.enc_param->quality = JPG_QUALITY_LEVEL_1;
	mArgs.enc_param->width = 640;
	mArgs.enc_param->height = 480;

	pInBuf = (unsigned char *)ioctl(jfd, IOCTL_JPG_GET_FRMBUF, mArgs.mapped_addr);
    if (pInBuf == NULL) {
        printf("+++++++=JPEG input buffer is NULL!!\n");
        return -1;
    }
}
下面是主函数

/*
 * main.c
 *
 *  Created on: Aug 4, 2011
 *      Author: gavin
 */

#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 <malloc.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 <jpeglib.h>
#include <linux/fb.h>

#include "v4l2.h"


int main()
{
	jpeg_init();
	deviceOpen();
	select_input(0);
	deviceInit();
	captureStart();
	for(test=0;test<50;test++)
	{
		mainLoop();
	}
	return 1;
}
不要前面的一些帧 前面的有可能会是全绿的 以下是效果图


测试完成开始修改qt工程

工程下载地址:http://download.csdn.net/detail/hclydao/8217081


============================================
作者:hclydao
http://blog.csdn.net/hclydao
版权没有,但是转载请保留此段声明

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

你可能感兴趣的:(s5pv210 jpeg硬件编码)