一直想自己写一个从JNI层到应用层的Camera例子,android4.0上usb camera用不了 所以决定自己写一个 usb camera和coms原理都是一样的 基本v4l2 只不过源码数据格式不一样而已 下面我们就从JNI层开始
以下是我的代码,先上代码在 一步步说明
fimcgzsd.c
- /*
- * Android USB Camera zc3xx Library
- *
- * Copyright (c) 2014 Store information technology guangzhou ltd<http://www.storeinf.com>
- * Copyright (c) 2014 hclydao <hclydao@gmail.com>
- *
- * 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;
- }
- 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;
- }
- }
streamon函数
将缓冲区放入队列并开启数据流
dqbuf函数
获取一帧数据 返回当前缓冲区的序列号
qbuf函数
将指定缓冲区放入队列,获取到某一缓冲区的数据后需要重新将这个缓冲区放入队列
后面两个我就不多说明了
Android.mk文件:
- LOCAL_PATH:= $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE_TAGS := eng
- LOCAL_SRC_FILES:= fimcgzsd.c
- LOCAL_MODULE := libfimcgzsd
- LOCAL_LDLIBS := -llog
- LOCAL_SHARED_LIBRARIES := libc libcutils
- include $(BUILD_SHARED_LIBRARY)