android4.0 USB Camera实例(一)JNI层

一直想自己写一个从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;
    }

获取设备相关信息,检查是否支持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 := 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

 

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

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

 

 

 

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 24
    评论
JNI(Java Native Interface)是 Java 平台上的一种机制,允许 Java 代码与本地代码(如 C、C++ 等)进行交互。下面是一个简单的 JNI 实例,演示了如何在 Android 中使用 JNI。 1. 在 Java 中定义 native 方法 ``` public class JNIExample { static { System.loadLibrary("native-lib"); } public native String getStringFromNative(); } ``` 注意,在静态块中加载库文件 `native-lib`。这个库文件后面会在 C++ 中用到。 2. 在 C++ 中实现 native 方法 ``` #include <jni.h> #include <string> extern "C" JNIEXPORT jstring JNICALL Java_com_example_jniexample_JNIExample_getStringFromNative(JNIEnv *env, jobject thiz) { std::string str = "Hello from C++"; return env->NewStringUTF(str.c_str()); } ``` 注意,函数名的命名规则是 `<包名>_<类名>_<方法名>`,并且要使用 `extern "C"` 声明,以便能够正确链接。 3. 编译生成动态库 在 C++ 代码所在的目录下执行以下命令: ``` $ <ndk-root>/ndk-build ``` 这将生成一个动态库 `libnative-lib.so`。 4. 在 Android 中调用 native 方法 在 Activity 中调用 native 方法: ``` public class MainActivity extends AppCompatActivity { private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = findViewById(R.id.text_view); JNIExample jniExample = new JNIExample(); String strFromNative = jniExample.getStringFromNative(); mTextView.setText(strFromNative); } } ``` 最后,将 `libnative-lib.so` 文件放到 `app/src/main/jniLibs` 目录下即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值