android4.0 USBカメラ例(一)JNI層


JNI層からアプリケーション層までのCameraの例を自分で書きたいと思っています.android 4.0の上でusb cameraは使えないので自分で1つのusb cameraとcomsの原理がすべて同じ基本v 4 l 2を書くことを決定しますただソースコードのデータのフォーマットは異なっています
以下は私のコードです.まずコードをつけて一歩一歩説明します.
fimcgzsd.c
 
/*
 * Android USB Camera zc3xx Library
 *
 * Copyright (c) 2014  Store information technology guangzhou ltd
 * Copyright (c) 2014  hclydao 
 *
 * 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 
#include 	
#include 	
#include 
#include 
#include     
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#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
",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
",__LINE__); return -1; } if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { LOGE("%d : no capture devices
",__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
",__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
",__LINE__); return -1; } buffers = calloc(req.count, sizeof(*buffers)); if (!buffers) { LOGE ("++++%d Out of memory
",__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
",__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
",__LINE__); return ret; } } ret = ioctl(fd, VIDIOC_STREAMON, &type); if (ret < 0) { LOGE("%d : VIDIOC_STREAMON failed
",__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
",__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
",__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
",__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
",__func__); return ret; } for (i = 0; i < bufnum; i++) { ret = munmap(buffers[i].start, buffers[i].length); if (ret < 0) { LOGE("%s : munmap failed
",__func__); return ret; } } free (buffers); close(fd); return 0; }

 
まずopenこれは説明しません
第2初期化init関数
 
    ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
    if (ret < 0) {
        LOGE("%d :VIDIOC_QUERYCAP failed
",__LINE__); return -1; } if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { LOGE("%d : no capture devices
",__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
",__LINE__); return -1; }

フォーマット、usb cameraが取得したのはすでにjpegフォーマットなのでここではRGB 565フォーマットに設定します
 
 
    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
",__LINE__); return -1; }

バッファを申請numbuf個のバッファフレームを申請する
    buffers = calloc(req.count, sizeof(*buffers));
    if (!buffers) {
        LOGE ("++++%d Out of memory
",__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
",__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関数
指定したバッファをキューに入れ、あるバッファのデータを取得した後、このバッファをキューに入れ直す必要があります.
後の2つはあまり説明しません
 
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)

 
 
 
 
 
 
参考文献:http://blog.csdn.net/eastmoon502136/article/details/8190262
 
============================================================lydaohttp://blog.csdn.net/hclydao著作権はありませんが、転載はこの声明を保留してください.
============================================