当前位置: 代码迷 >> Android >> android4.0 USB Camera范例(一)HAL层
  详细解决方案

android4.0 USB Camera范例(一)HAL层

热度:417   发布时间:2016-04-28 06:36:32.0
android4.0 USB Camera实例(一)HAL层

一直想自己写一个从HAL层到应用层的Camera例子,android4.0上usb camera用不了 所以决定自己写一个  usb camera和coms原理都是一样的 基本v4l2 只不过源码数据格式不一样而已 下面我们就从HAL层开始

以下是我的代码,先上代码在 一步步说明

fimcgzsd.c

/* * Android USB Camera zc3xx Library * * Copyright (c) 2014  Store information technology guangzhou ltd<http://www.storeinf.com> * Copyright (c) 2014  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 as published by * the Free Software Foundation; either version 2 of the License. */#include <errno.h>#include <sys/types.h>	#include <sys/stat.h>	#include <fcntl.h>#include <sys/ioctl.h>#include <unistd.h>    #include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <asm/types.h>#include <linux/videodev2.h>#include <sys/mman.h>#include <string.h>#include <malloc.h>#include <linux/fb.h>#include <jni.h>#include <string.h>#include <android/log.h>#include <syslog.h>#define  LOG_TAG    "FimcGzsd"#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG  , LOG_TAG, __VA_ARGS__)#define LOGI(...) __android_log_print(ANDROID_LOG_INFO   , LOG_TAG, __VA_ARGS__)#define LOGW(...) __android_log_print(ANDROID_LOG_WARN   , LOG_TAG, __VA_ARGS__)#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , LOG_TAG, __VA_ARGS__)struct fimc_buffer {    unsigned char *start;    size_t  length;};static int fd = -1;struct fimc_buffer *buffers=NULL;struct v4l2_buffer v4l2_buf;static int bufnum = 1;static int mwidth,mheight;/* *open usb camera device */JNIEXPORT jint JNICALL Java_com_dao_usbcam_Fimcgzsd_open(JNIEnv * env, jclass obj, const jbyteArray devname){	jbyte *dev = (jbyte*)(*env)->GetByteArrayElements(env, devname, 0);	fd = open(dev, O_RDWR, 0);  	if (fd<0)	{		LOGE("%s ++++ open error\n",dev);		return  -1;	}	(*env)->ReleaseByteArrayElements(env, devname, dev, 0);	return fd;}/* * init device */JNIEXPORT jint JNICALL Java_com_dao_usbcam_Fimcgzsd_init(JNIEnv * env, jclass obj, jint width, jint height,jint numbuf){	int ret;	int i;	bufnum = numbuf;	mwidth = width;	mheight = height;	struct v4l2_format fmt;		struct v4l2_capability cap;    ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);    if (ret < 0) {        LOGE("%d :VIDIOC_QUERYCAP failed\n",__LINE__);        return -1;    }    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {        LOGE("%d : no capture devices\n",__LINE__);        return -1;    }					memset( &fmt, 0, sizeof(fmt));	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;	fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565;	fmt.fmt.pix.width = width;	fmt.fmt.pix.height = height;						if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0)	{		LOGE("++++%d : set format failed\n",__LINE__);		return -1;	}    struct v4l2_requestbuffers req;    req.count = numbuf;    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;    req.memory = V4L2_MEMORY_MMAP;    ret = ioctl(fd, VIDIOC_REQBUFS, &req);    if (ret < 0) {        LOGE("++++%d : VIDIOC_REQBUFS failed\n",__LINE__);        return -1;    }    buffers = calloc(req.count, sizeof(*buffers));    if (!buffers) {        LOGE ("++++%d Out of memory\n",__LINE__);		return -1;    }	for(i = 0; i< bufnum; ++i) {		memset(&v4l2_buf, 0, sizeof(v4l2_buf));		v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;		v4l2_buf.memory = V4L2_MEMORY_MMAP;		v4l2_buf.index = i;		ret = ioctl(fd , VIDIOC_QUERYBUF, &v4l2_buf);		if(ret < 0) {		   LOGE("+++%d : VIDIOC_QUERYBUF failed\n",__LINE__);		   return -1;		}		buffers[i].length = v4l2_buf.length;		if ((buffers[i].start = (char *)mmap(0, v4l2_buf.length,		                                     PROT_READ | PROT_WRITE, MAP_SHARED,		                                     fd, v4l2_buf.m.offset)) < 0) {		     LOGE("%d : mmap() failed",__LINE__);		     return -1;		}	}	return 0;}/* *open usb camera device */JNIEXPORT jint JNICALL Java_com_dao_usbcam_Fimcgzsd_streamon(JNIEnv * env, jclass obj){	int i;	int ret;	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;	for(i = 0; i< bufnum; ++i) {		memset(&v4l2_buf, 0, sizeof(v4l2_buf));		v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;		v4l2_buf.memory = V4L2_MEMORY_MMAP;		v4l2_buf.index = i;		ret = ioctl(fd, VIDIOC_QBUF, &v4l2_buf);		if (ret < 0) {		    LOGE("%d : VIDIOC_QBUF failed\n",__LINE__);		    return ret;		}	}    ret = ioctl(fd, VIDIOC_STREAMON, &type);    if (ret < 0) {        LOGE("%d : VIDIOC_STREAMON failed\n",__LINE__);        return ret;    }	return 0;}/* *get one frame data */JNIEXPORT jint JNICALL Java_com_dao_usbcam_Fimcgzsd_dqbuf(JNIEnv * env, jclass obj,const jbyteArray videodata){    int ret;	jbyte *data = (jbyte*)(*env)->GetByteArrayElements(env, videodata, 0);    v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;    v4l2_buf.memory = V4L2_MEMORY_MMAP;    ret = ioctl(fd, VIDIOC_DQBUF, &v4l2_buf);    if (ret < 0) {        LOGE("%s : VIDIOC_DQBUF failed, dropped frame\n",__func__);        return ret;    }	memcpy(data,buffers[v4l2_buf.index].start,buffers[v4l2_buf.index].length);	(*env)->ReleaseByteArrayElements(env, videodata, data, 0);	return v4l2_buf.index;}/* *put in frame buffer to queue */JNIEXPORT jint JNICALL Java_com_dao_usbcam_Fimcgzsd_qbuf(JNIEnv * env, jclass obj,jint index){    int ret;    v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;    v4l2_buf.memory = V4L2_MEMORY_MMAP;    v4l2_buf.index = index;    ret = ioctl(fd, VIDIOC_QBUF, &v4l2_buf);    if (ret < 0) {        LOGE("%s : VIDIOC_QBUF failed\n",__func__);        return ret;    }    return 0;}/* *streamoff */JNIEXPORT jint JNICALL Java_com_dao_usbcam_Fimcgzsd_streamoff(JNIEnv * env, jclass obj,jint index){    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;    int ret;    ret = ioctl(fd, VIDIOC_STREAMOFF, &type);    if (ret < 0) {        LOGE("%s : VIDIOC_STREAMOFF failed\n",__func__);        return ret;    }    return 0;}/* *release */JNIEXPORT jint JNICALL Java_com_dao_usbcam_Fimcgzsd_release(JNIEnv * env, jclass obj){    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;    int ret;	int i;    ret = ioctl(fd, VIDIOC_STREAMOFF, &type);    if (ret < 0) {        LOGE("%s : VIDIOC_STREAMOFF failed\n",__func__);        return ret;    }    for (i = 0; i < bufnum; i++) {       ret = munmap(buffers[i].start, buffers[i].length);		if (ret < 0) {		    LOGE("%s : munmap failed\n",__func__);		    return ret;    	}	}	free (buffers);	close(fd);	return 0;}

首先是open这个就不作说明了

第二初始化init函数

    ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);    if (ret < 0) {        LOGE("%d :VIDIOC_QUERYCAP failed\n",__LINE__);        return -1;    }    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {        LOGE("%d : no capture devices\n",__LINE__);        return -1;    }
获取设备相关信息,检查是否支持capture模式

	memset( &fmt, 0, sizeof(fmt));	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;	fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565;	fmt.fmt.pix.width = width;	fmt.fmt.pix.height = height;						if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0)	{		LOGE("++++%d : set format failed\n",__LINE__);		return -1;	}
设置格式,usb camera获取到的已经是jpeg格式 所以这里设置成RGB565格式

    struct v4l2_requestbuffers req;    req.count = numbuf;    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;    req.memory = V4L2_MEMORY_MMAP;    ret = ioctl(fd, VIDIOC_REQBUFS, &req);    if (ret < 0) {        LOGE("++++%d : VIDIOC_REQBUFS failed\n",__LINE__);        return -1;    }
申请缓冲区,这里申请numbuf个缓冲帧
    buffers = calloc(req.count, sizeof(*buffers));    if (!buffers) {        LOGE ("++++%d Out of memory\n",__LINE__);		return -1;    }	for(i = 0; i< bufnum; ++i) {		memset(&v4l2_buf, 0, sizeof(v4l2_buf));		v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;		v4l2_buf.memory = V4L2_MEMORY_MMAP;		v4l2_buf.index = i;		ret = ioctl(fd , VIDIOC_QUERYBUF, &v4l2_buf);		if(ret < 0) {		   LOGE("+++%d : VIDIOC_QUERYBUF failed\n",__LINE__);		   return -1;		}		buffers[i].length = v4l2_buf.length;		if ((buffers[i].start = (char *)mmap(0, v4l2_buf.length,		                                     PROT_READ | PROT_WRITE, MAP_SHARED,		                                     fd, v4l2_buf.m.offset)) < 0) {		     LOGE("%d : mmap() failed",__LINE__);		     return -1;		}	}
映射虚拟内存到物理地址,获取每个缓冲区的物理地址


streamon函数

将缓冲区放入队列并开启数据流

dqbuf函数

获取一帧数据 返回当前缓冲区的序列号

qbuf函数

将指定缓冲区放入队列,获取到某一缓冲区的数据后需要重新将这个缓冲区放入队列

后面两个我就不多说明了


Android.mk文件:

LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE_TAGS := engLOCAL_SRC_FILES:= fimcgzsd.cLOCAL_MODULE := libfimcgzsdLOCAL_LDLIBS    := -llogLOCAL_SHARED_LIBRARIES := libc libcutilsinclude $(BUILD_SHARED_LIBRARY)



参考博文:http://blog.csdn.net/eastmoon502136/article/details/8190262

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

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


  相关解决方案