android4.0 USB Camera实例(三)UVC
https://blog.csdn.net/hclydao/article/details/30258241
下面顺便把通用的USB也写上 前面的ZC301获取到的格式是JPEG的所以不用进行什么处理就可以用来显示,但是标准的UVC获取到的是YUV422格式的需要转换成RGB后才能进行显示 这里我们在前面两篇的代码稍作修改就可以了
HAL层 代码如下
-
/* -
* 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> -
#include <android/log.h> -
#include <android/bitmap.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; -
static int c_type = 0; -
int *rgb = NULL; -
int *ybuf = NULL; -
int yuv_tbl_ready=0; -
int y1192_tbl[256]; -
int v1634_tbl[256]; -
int v833_tbl[256]; -
int u400_tbl[256]; -
int u2066_tbl[256]; -
/* -
*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,jint ctype) -
{ -
int ret; -
int i; -
bufnum = numbuf; -
mwidth = width; -
mheight = height; -
c_type = ctype; -
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; -
if(c_type == 1) -
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; -
else -
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; -
} -
} -
rgb = (int *)malloc(sizeof(int) * (mwidth*mheight)); -
ybuf = (int *)malloc(sizeof(int) * (mwidth*mheight)); -
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; -
} -
void yuyv422toABGRY(unsigned char *src) -
{ -
int width=0; -
int height=0; -
width = mwidth; -
height = mheight; -
int frameSize =width*height*2; -
int i; -
if((!rgb || !ybuf)){ -
return; -
} -
int *lrgb = NULL; -
int *lybuf = NULL; -
lrgb = &rgb[0]; -
lybuf = &ybuf[0]; -
if(yuv_tbl_ready==0){ -
for(i=0 ; i<256 ; i++){ -
y1192_tbl[i] = 1192*(i-16); -
if(y1192_tbl[i]<0){ -
y1192_tbl[i]=0; -
} -
v1634_tbl[i] = 1634*(i-128); -
v833_tbl[i] = 833*(i-128); -
u400_tbl[i] = 400*(i-128); -
u2066_tbl[i] = 2066*(i-128); -
} -
yuv_tbl_ready=1; -
} -
for(i=0 ; i<frameSize ; i+=4){ -
unsigned char y1, y2, u, v; -
y1 = src[i]; -
u = src[i+1]; -
y2 = src[i+2]; -
v = src[i+3]; -
int y1192_1=y1192_tbl[y1]; -
int r1 = (y1192_1 + v1634_tbl[v])>>10; -
int g1 = (y1192_1 - v833_tbl[v] - u400_tbl[u])>>10; -
int b1 = (y1192_1 + u2066_tbl[u])>>10; -
int y1192_2=y1192_tbl[y2]; -
int r2 = (y1192_2 + v1634_tbl[v])>>10; -
int g2 = (y1192_2 - v833_tbl[v] - u400_tbl[u])>>10; -
int b2 = (y1192_2 + u2066_tbl[u])>>10; -
r1 = r1>255 ? 255 : r1<0 ? 0 : r1; -
g1 = g1>255 ? 255 : g1<0 ? 0 : g1; -
b1 = b1>255 ? 255 : b1<0 ? 0 : b1; -
r2 = r2>255 ? 255 : r2<0 ? 0 : r2; -
g2 = g2>255 ? 255 : g2<0 ? 0 : g2; -
b2 = b2>255 ? 255 : b2<0 ? 0 : b2; -
*lrgb++ = 0xff000000 | b1<<16 | g1<<8 | r1; -
*lrgb++ = 0xff000000 | b2<<16 | g2<<8 | r2; -
if(lybuf!=NULL){ -
*lybuf++ = y1; -
*lybuf++ = y2; -
} -
} -
} -
void -
Java_com_dao_usbcam_Fimcgzsd_pixeltobmp( JNIEnv* env,jobject thiz,jobject bitmap){ -
jboolean bo; -
AndroidBitmapInfo info; -
void* pixels; -
int ret; -
int i; -
int *colors; -
int width=0; -
int height=0; -
if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) { -
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); -
return; -
} -
width = info.width; -
height = info.height; -
if(!rgb || !ybuf) return; -
if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { -
LOGE("Bitmap format is not RGBA_8888 !"); -
return; -
} -
if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) { -
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); -
} -
colors = (int*)pixels; -
int *lrgb =NULL; -
lrgb = &rgb[0]; -
for(i=0 ; i<width*height ; i++){ -
*colors++ = *lrgb++; -
} -
AndroidBitmap_unlockPixels(env, bitmap); -
} -
void yuyv422torgb(unsigned char *src,unsigned int *mrgb) -
{ -
int width=0; -
int height=0; -
width = mwidth; -
height = mheight; -
int frameSize =width*height*2; -
int i; -
if((!rgb || !ybuf)){ -
return; -
} -
int *lrgb = NULL; -
int *lybuf = NULL; -
lrgb = mrgb; -
lybuf = &ybuf[0]; -
if(yuv_tbl_ready==0){ -
for(i=0 ; i<256 ; i++){ -
y1192_tbl[i] = 1192*(i-16); -
if(y1192_tbl[i]<0){ -
y1192_tbl[i]=0; -
} -
v1634_tbl[i] = 1634*(i-128); -
v833_tbl[i] = 833*(i-128); -
u400_tbl[i] = 400*(i-128); -
u2066_tbl[i] = 2066*(i-128); -
} -
yuv_tbl_ready=1; -
} -
for(i=0 ; i<frameSize ; i+=4){ -
unsigned char y1, y2, u, v; -
y1 = src[i]; -
u = src[i+1]; -
y2 = src[i+2]; -
v = src[i+3]; -
int y1192_1=y1192_tbl[y1]; -
int r1 = (y1192_1 + v1634_tbl[v])>>10; -
int g1 = (y1192_1 - v833_tbl[v] - u400_tbl[u])>>10; -
int b1 = (y1192_1 + u2066_tbl[u])>>10; -
int y1192_2=y1192_tbl[y2]; -
int r2 = (y1192_2 + v1634_tbl[v])>>10; -
int g2 = (y1192_2 - v833_tbl[v] - u400_tbl[u])>>10; -
int b2 = (y1192_2 + u2066_tbl[u])>>10; -
r1 = r1>255 ? 255 : r1<0 ? 0 : r1; -
g1 = g1>255 ? 255 : g1<0 ? 0 : g1; -
b1 = b1>255 ? 255 : b1<0 ? 0 : b1; -
r2 = r2>255 ? 255 : r2<0 ? 0 : r2; -
g2 = g2>255 ? 255 : g2<0 ? 0 : g2; -
b2 = b2>255 ? 255 : b2<0 ? 0 : b2; -
*lrgb++ = 0xff000000 | b1<<16 | g1<<8 | r1; -
*lrgb++ = 0xff000000 | b2<<16 | g2<<8 | r2; -
if(lybuf!=NULL){ -
*lybuf++ = y1; -
*lybuf++ = y2; -
} -
} -
} -
JNIEXPORT jint JNICALL Java_com_dao_usbcam_Fimcgzsd_yuvtorgb(JNIEnv * env, jclass obj,const jbyteArray yuvdata, jintArray rgbdata) -
{ -
jbyte *ydata = (jbyte*)(*env)->GetByteArrayElements(env, yuvdata, 0); -
jint *rdata = (jint*)(*env)->GetIntArrayElements(env, rgbdata, 0); -
yuyv422torgb(ydata,rdata); -
(*env)->ReleaseByteArrayElements(env, yuvdata, ydata, 0); -
(*env)->ReleaseIntArrayElements(env, rgbdata, rdata, 0); -
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; -
} -
if(c_type == 1) -
yuyv422toABGRY((unsigned char *)buffers[v4l2_buf.index].start); -
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); -
if(rgb) free(rgb); -
if(ybuf) free(ybuf); -
close(fd); -
return 0; -
}
主要增加了两个函数
yuyv422toABGRY 这个是yuv转rgb
Java_com_dao_usbcam_Fimcgzsd_pixeltobmp 这个是rgb转bitmap
这两个函数是我在网上找到例子simplewebcam里拷出来的
同时Android.mk修改如下
-
LOCAL_PATH := $(call my-dir) -
include $(CLEAR_VARS) -
LOCAL_MODULE := fimcgzsd -
LOCAL_SRC_FILES := fimcgzsd.c -
LOCAL_LDLIBS := -llog -ljnigraphics -
include $(BUILD_SHARED_LIBRARY)
增加了一个Application.mk
-
# The ARMv7 is significanly faster due to the use of the hardware FPU -
APP_ABI := armeabi armeabi-v7a -
APP_PLATFORM := android-8
这样在终端进入工程所有目录直接执行ndk-build(环境变量已经设置)即可生成动态库
应用层
增加一个c_type指定是zc301还是uvc 我还是把代码贴上来吧
-
package com.dao.usbcam; -
import java.io.ByteArrayOutputStream; -
import java.io.File; -
import java.io.FileNotFoundException; -
import java.io.FileOutputStream; -
import java.io.IOException; -
import android.app.Activity; -
import android.graphics.Bitmap; -
import android.graphics.BitmapFactory; -
import android.graphics.ImageFormat; -
import android.graphics.Rect; -
import android.graphics.YuvImage; -
import android.os.Bundle; -
import android.os.Environment; -
import android.os.Handler; -
import android.text.format.Time; -
import android.view.Menu; -
import android.view.View; -
import android.view.View.OnClickListener; -
import android.view.Window; -
import android.view.WindowManager; -
import android.widget.Button; -
import android.widget.ImageView; -
import android.widget.Toast; -
public class MainActivity extends Activity { -
private ImageView mImag; -
private int width = 320; -
private int height = 240; -
private String devname = "/dev/video3"; -
private byte[] mdata; -
private Handler mHandler; -
private int numbuf = 0; -
private int index = 0; -
private int ret = 0; -
private int ctype = 1;//0 is zc301 1 is uvc camera -
public Button mcap; -
private Bitmap bitmap; -
private Bitmap bmp; -
private int[] rgb; -
@Override -
protected void onCreate(Bundle savedInstanceState) { -
super.onCreate(savedInstanceState); -
requestWindowFeature(Window.FEATURE_NO_TITLE); -
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, -
WindowManager.LayoutParams.FLAG_FULLSCREEN); -
setContentView(R.layout.activity_main); -
mImag = (ImageView)findViewById(R.id.mimg); -
mcap = (Button)findViewById(R.id.mcap); -
bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); -
numbuf = 4; -
mdata = new byte[width * height * numbuf]; -
rgb = new int[width * height * numbuf]; -
ret = Fimcgzsd.open(devname.getBytes()); -
if(ret < 0) -
finish(); -
ret = Fimcgzsd.init(width, height, numbuf,ctype); -
if(ret < 0) -
finish(); -
ret = Fimcgzsd.streamon(); -
if(ret < 0) -
finish(); -
mHandler = new Handler(); -
new StartThread().start(); -
mcap.setOnClickListener(new CaptureListener()); -
} -
final Runnable mUpdateUI = new Runnable() { -
@Override -
public void run() { -
// TODO Auto-generated method stub -
mImag.setImageBitmap(bitmap); -
} -
}; -
class StartThread extends Thread { -
@Override -
public void run() { -
// TODO Auto-generated method stub -
//super.run(); -
while(true) { -
if(ctype == 1){ -
index = Fimcgzsd.dqbuf(mdata); -
if((index < 0) || (mdata == null)) { -
onDestroy(); -
break; -
} -
Fimcgzsd.pixeltobmp(bmp); -
mHandler.post(mUpdateUI); -
bitmap = bmp; -
Fimcgzsd.qbuf(index); -
//Fimcgzsd.yuvtorgb(mdata, rgb); -
//mHandler.post(mUpdateUI); -
//bitmap = Bitmap.createBitmap(rgb,width,height,Bitmap.Config.ARGB_8888); -
//Fimcgzsd.qbuf(index); -
} else { -
index = Fimcgzsd.dqbuf(mdata); -
if(index < 0) { -
onDestroy(); -
break; -
} -
mHandler.post(mUpdateUI); -
bitmap = BitmapFactory.decodeByteArray(mdata, 0, width * height); -
Fimcgzsd.qbuf(index); -
} -
} -
} -
} -
public static void saveMyBitmap(Bitmap mBitmap) { -
Time mtime = new Time(); -
mtime.setToNow(); -
File fdir = new File(Environment.getExternalStorageDirectory().getPath() + "/DCIM/" + "/gzsd/"); -
if(!fdir.exists()) { -
fdir.mkdir(); -
} -
File f = new File(Environment.getExternalStorageDirectory().getPath() + "/DCIM/" + "/gzsd/" + mtime.year + mtime.month + mtime.monthDay + mtime.hour + mtime.minute +mtime.second+".png"); -
try { -
f.createNewFile(); -
} catch (IOException e) { -
e.printStackTrace(); -
} -
FileOutputStream fOut = null; -
try { -
fOut = new FileOutputStream(f); -
mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut); -
fOut.flush(); -
fOut.close(); -
} catch (FileNotFoundException e) { -
e.printStackTrace(); -
} catch (IOException e) { -
e.printStackTrace(); -
} -
} -
class CaptureListener implements OnClickListener{ -
@Override -
public void onClick(View v) { -
// TODO Auto-generated method stub -
//new CapThread().start(); -
//Fimcgzsd.streamoff(); -
saveMyBitmap(bitmap); -
//Fimcgzsd.streamon(); -
Toast.makeText(MainActivity.this, "Capture Successfully", Toast.LENGTH_SHORT).show(); -
} -
} -
class CapThread extends Thread { -
@Override -
public void run() { -
// TODO Auto-generated method stub -
//super.run(); -
saveMyBitmap(bitmap); -
Toast.makeText(MainActivity.this, "Capture Successfully", Toast.LENGTH_LONG).show(); -
} -
} -
@Override -
protected void onStop() { -
// TODO Auto-generated method stub -
super.onStop(); -
Fimcgzsd.release(); -
finish(); -
} -
@Override -
protected void onPause() { -
// TODO Auto-generated method stub -
super.onPause(); -
Fimcgzsd.release(); -
finish(); -
} -
@Override -
protected void onDestroy() { -
// TODO Auto-generated method stub -
super.onDestroy(); -
Fimcgzsd.release(); -
} -
@Override -
public boolean onCreateOptionsMenu(Menu menu) { -
// Inflate the menu; this adds items to the action bar if it is present. -
getMenuInflater().inflate(R.menu.main, menu); -
finish(); -
return true; -
} -
}
原理什么的我前面已经简单的进行了说明这里 我就不说了 具体效果如下