源码路径:

1.图像采集部分:

usb_v4l2.cpp

    //// Created by Administrator on 2018/12/17 0017.//#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <fcntl.h>#include <errno.h>#include <sys/mman.h>#include <linux/videodev2.h>#include <sys/inotify.h>#include "usb_v4l2.h"int g_videofd = -1;        //设备描述符struct v4l2_buffer buf;              //驱动中的一帧图像缓存,对应命令VIDIOC_QUERYBUFstruct frame_buf frame_buf;//投放一个空的视频缓冲区到视频缓冲区输入队列中 ;int usb_v4l2:: video_enqueue(int i){buf.index = i;if(ioctl(g_videofd, VIDIOC_QBUF, &buf) < 0){LOGW("enqueue failed");return -1;}return 0;}//摄像头设备信息查询及配置int usb_v4l2:: init_V4L2(int w,int h){struct v4l2_capability cap ;//视频设备的功能,对应命令VIDIOC_QUERYCAPstruct v4l2_fmtdesc stfmt; //当前视频支持的格式,对应命令VIDIOC_ENUM_FMTstruct v4l2_format  fmt;   //当前驱动的频捕获格式式,对应命令VIDIOC_G_FMT、VIDIOC_S_FMT//1).打开摄像头设备g_videofd = open(VIDEO_DEV, O_RDWR);if(g_videofd == -1){LOGW("open dev failed");return -1;}//2).查询摄像头设备的基本信息及功能if(ioctl(g_videofd, VIDIOC_QUERYCAP, &cap) < 0){LOGW("ioctl failed");return -1;}else{LOGW("driver:\t\t%s\n",cap.driver);LOGW("card:\t\t%s\n",cap.card);LOGW("bus_info:\t%s\n",cap.bus_info);LOGW("version:\t%d\n",cap.version);LOGW("capabilities:\t%#x\n",cap.capabilities);if((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE){LOGW("Device %s: supports capture.\n", VIDEO_DEV);}if((cap.capabilities & V4L2_CAP_STREAMING) == V4L2_CAP_STREAMING){LOGW("Device %s: supports streaming.\n", VIDEO_DEV);}}//3).列举摄像头所支持像素格式。memset(&stfmt, 0, sizeof(stfmt));stfmt.index = 0;stfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;LOGW("device support:\n");while(ioctl(g_videofd, VIDIOC_ENUM_FMT, &stfmt) != -1){LOGW("\t%d:  %s \n\n", stfmt.index++, stfmt.description);//stfmt.index++;}//4).设置当前驱动的频捕获格式memset(&fmt, 0 ,sizeof(fmt));fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;fmt.fmt.pix.height = w;fmt.fmt.pix.width = h;fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;ioctl(g_videofd, VIDIOC_S_FMT, &fmt);LOGW("Size: %d,%d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);LOGW("Video stored type: %d\n",fmt.fmt.pix.pixelformat);if(fmt.fmt.pix.height != 480){LOGW("%s,%d: Unable to set format\n",__func__,__LINE__);return -1;}return 0;}//采集初始化int usb_v4l2:: gather_picture_init(){struct v4l2_requestbuffers reqbuf;//申请帧缓存,对应命令VIDIOC_REQBUFSint i = 0;//1).向驱动申请帧缓存reqbuf.count = 4;// 缓存数量,也就是说在缓存队列里保持多少张照片reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;reqbuf.memory = V4L2_MEMORY_MMAP;if(ioctl(g_videofd, VIDIOC_REQBUFS, &reqbuf)==-1){LOGW("VIDEO_REQBUFS");return -1;}//2).获取申请的每个缓存的信息,并mmap到用户空间for (i = 0; i < reqbuf.count; i++){buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;buf.index = i;if (ioctl (g_videofd, VIDIOC_QUERYBUF, &buf) == -1){LOGW("query buffer error\n");return -1;}frame_buf.length[i] = buf.length;frame_buf.start[i] = mmap(NULL, buf.length, PROT_READ |PROT_WRITE, MAP_SHARED, g_videofd, buf.m.offset);if(frame_buf.start[i] == MAP_FAILED){LOGW("buffer map error:%s,%d\n", __func__, __LINE__);return-1;}video_enqueue(i);//帧缓存入队}return 0;}//开始采集int usb_v4l2:: gather_on(){enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if(ioctl(g_videofd, VIDIOC_STREAMON, &type) < 0){LOGW("stream on");return -1;}return 0;}//采集结束int usb_v4l2:: gather_off(){enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if(ioctl(g_videofd, VIDIOC_STREAMOFF, &type) < 0){LOGW("stream on");return -1;}return 0;}//取出视频缓冲区的输出队列中取得一个已经//保存有一帧视频数据的视频缓冲区;int usb_v4l2:: video_getframe(int i){buf.index = i;if(ioctl(g_videofd, VIDIOC_DQBUF, &buf) < 0){LOGW("release failed");return -1;}return 0;}

2. 图像转换(YUV->RGBA)和显示部分

native-lib.cpp

#include <jni.h>
#include <string>
#include <unistd.h>
#include <android/log.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
#include "usb_v4l2.h"extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>}#define srcWidth 640
#define srcHeight 480#define outWidth 640
#define outHeight 480
usb_v4l2 device;//extern "C" 是不能少的,同时需要正确的返回函数的返回值,否则会出错
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_sunmi_player_UsbCamera_usb_1camera_1stream_1on(JNIEnv *env, jobject instance) {int re = 0;re = device.gather_on();if(re < 0) {LOGW("gather_on failed");return JNI_FALSE;}return JNI_TRUE;
}extern "C"
JNIEXPORT jboolean JNICALL
Java_com_sunmi_player_UsbCamera_usb_1camera_1init(JNIEnv *env, jobject instance) {int re = 0;re = device.init_V4L2(srcWidth,srcHeight);if(re < 0) {LOGW("init_V4L2 failed");return JNI_FALSE;}re = device.gather_picture_init();if(re < 0) {LOGW("gather_picture_init failed");return JNI_FALSE;}return JNI_TRUE;
}extern "C"
JNIEXPORT void JNICALL
Java_com_sunmi_player_UsbCamera_start_1preview(JNIEnv *env, jobject instance, jobject surface) {//设置输入视频文件的大小和视频格式const int src_w=srcWidth,src_h=srcHeight;AVPixelFormat src_pixfmt=AV_PIX_FMT_YUYV422;//获取输入视频文件每个像素占有的BIT数int src_bpp=av_get_bits_per_pixel(av_pix_fmt_desc_get(src_pixfmt));//设置输出图像的大小和格式const int dst_w=outWidth,dst_h=outHeight;AVPixelFormat dst_pixfmt=AV_PIX_FMT_RGBA;//获取输出视频文件每个像素占有的BIT数int dst_bpp=av_get_bits_per_pixel(av_pix_fmt_desc_get(dst_pixfmt));//Structuresuint8_t *src_data[4];int src_linesize[4];uint8_t *dst_data[4];int dst_linesize[4];struct SwsContext *img_convert_ctx;uint8_t *temp_buffer;int frame_idx=0;int ret=0;/*通过输入宽和高以及像素格式分配输入缓冲,对于yuv422的格式:* src_data[0]:yuv的数据是按照顺序依次存放的* align:输入宽度需要对齐到多少*/ret= av_image_alloc(src_data, src_linesize,src_w, src_h, src_pixfmt, 1);if (ret< 0) {LOGW( "Could not allocate source image\n");return ;}/*通过输出宽和高以及像素格式分配输入缓冲,对于RGBA的格式:* dst_data[0]:代表RGBA通道;dst_linesize[0]:对齐后的RGBA宽度(W*H*4),可能会大于输入的图像宽度* dst_data[1]:RGBA是非平面数据* dst_data[2]:RGBA是非平面数据* align:输出宽度需要对齐到多少*/ret = av_image_alloc(dst_data, dst_linesize,dst_w, dst_h, dst_pixfmt, 1);if (ret< 0) {LOGW( "Could not allocate destination image\n");return ;}//-----------------------------//Init Method 1//分配图像转换的上下文img_convert_ctx =sws_alloc_context();//Set Value//SWS_BICUBIC代表的是图像转换的其中一种算法av_opt_set_int(img_convert_ctx,"sws_flags",SWS_BICUBIC|SWS_PRINT_INFO,0);//设置图像转换输入源的宽av_opt_set_int(img_convert_ctx,"srcw",src_w,0);//设置图像转换输入源的高av_opt_set_int(img_convert_ctx,"srch",src_h,0);//设置图像转换输入源的格式av_opt_set_int(img_convert_ctx,"src_format",src_pixfmt,0);//'0' for MPEG (Y:0-235);'1' for JPEG (Y:0-255)/** FFmpeg中可以通过使用av_opt_set()设置“src_range”和“dst_range”来设置输入和输出的YUV的取值范围。* 如果“dst_range”字段设置为“1”的话,则代表输出的YUV的取值范围遵循“jpeg”标准;* 如果“dst_range”字段设置为“0”的话,则代表输出的YUV的取值范围遵循“mpeg”标准。* 下面记录一下YUV的取值范围的概念。与RGB每个像素点的每个分量取值范围为0-255不同(每个分量占8bit),YUV取值范围有两种:* (1)以Rec.601为代表(还包括BT.709 / BT.2020)的广播电视标准中,Y的取值范围是16-235,U、V的取值范围是16-240。FFmpeg中称之为“mpeg”范围。* (2)以JPEG为代表的标准中,Y、U、V的取值范围都是0-255。FFmpeg中称之为“jpeg” 范围。*/av_opt_set_int(img_convert_ctx,"src_range",1,0);//设置图像转换输出图像的宽av_opt_set_int(img_convert_ctx,"dstw",dst_w,0);//设置图像转换输出图像的高av_opt_set_int(img_convert_ctx,"dsth",dst_h,0);//设置图像转换输出图像的目标格式av_opt_set_int(img_convert_ctx,"dst_format",dst_pixfmt,0);//同上设置输出图像遵循Mjpeg还是Jpegav_opt_set_int(img_convert_ctx,"dst_range",1,0);//初始化图像转换上下文sws_init_context(img_convert_ctx,NULL,NULL);//显示窗口初始化ANativeWindow *nwin = ANativeWindow_fromSurface(env,surface);//设置显示窗口的格式ANativeWindow_setBuffersGeometry(nwin,outWidth,outHeight,WINDOW_FORMAT_RGBA_8888);//定义窗口bufANativeWindow_Buffer wbuf;int i = 0;do{ret = device.video_getframe(i);if(ret < 0) {LOGW("frame %d, get failed",i);goto Out;}temp_buffer = (uint8_t *)frame_buf.start[i];switch(src_pixfmt){case AV_PIX_FMT_GRAY8:{memcpy(src_data[0],temp_buffer,src_w*src_h);break;}case AV_PIX_FMT_YUV420P:{//通道转换,YUV420P有三个通道需要转换memcpy(src_data[0],temp_buffer,src_w*src_h);                    //Ymemcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h/4);      //Umemcpy(src_data[2],temp_buffer+src_w*src_h*5/4,src_w*src_h/4);  //Vbreak;}case AV_PIX_FMT_YUV422P:{//通道转换,YUV422P有三个通道需要转换memcpy(src_data[0],temp_buffer,src_w*src_h);                    //Ymemcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h/2);      //Umemcpy(src_data[2],temp_buffer+src_w*src_h*3/2,src_w*src_h/2);  //Vbreak;}case AV_PIX_FMT_YUV444P:{memcpy(src_data[0],temp_buffer,src_w*src_h);                    //Ymemcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h);        //Umemcpy(src_data[2],temp_buffer+src_w*src_h*2,src_w*src_h);      //Vbreak;}case AV_PIX_FMT_YUYV422:{memcpy(src_data[0],temp_buffer,src_w*src_h*2);                  //Packedbreak;}case AV_PIX_FMT_RGB24:{memcpy(src_data[0],temp_buffer,src_w*src_h*3);                  //Packedbreak;}default:{printf("Not Support Input Pixel Format.\n");break;}}//将数据转换,YUV422转换为RGBA格式sws_scale(img_convert_ctx, src_data, src_linesize, 0, src_h, dst_data, dst_linesize);//LOGW("Finish process frame %5d\n",frame_idx);frame_idx++;ANativeWindow_lock(nwin,&wbuf,0);//wbuf.bits:对应的就是surface的bufuint8_t *dst = (uint8_t*)wbuf.bits;//因为RGBA是非平面的数据,所以转换后数据是存放在dst_data[0]中的memcpy(dst,dst_data[0],outWidth*outHeight*4);ANativeWindow_unlockAndPost(nwin);if(device.video_enqueue(i) < 0){LOGW("video_enqueue(%d) failed\n",i);break ;}i=(i+1)%4;}while(true);Out:LOGW("end preview \n");device.gather_off();sws_freeContext(img_convert_ctx);av_freep(&src_data[0]);av_freep(&dst_data[0]);return;
}

3.APP部分

UsbCamera.java

package com.sunmi.player;import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;/*** Created by Administrator on 2018/12/14 0014.*/public class UsbCamera extends GLSurfaceView implements Runnable,SurfaceHolder.Callback{public UsbCamera(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic void run() {boolean re = true;re = usb_camera_init();if(re == false) {Log.e("ffmpeg", "usb_camera_init failed");return ;}re = usb_camera_stream_on();if(re == false) {Log.e("ffmpeg", "usb_camera_stream_on failed");return ;}start_preview(getHolder().getSurface());}@Overridepublic void surfaceCreated(SurfaceHolder var1){new Thread(this).start();}@Overridepublic void surfaceChanged(SurfaceHolder var1, int var2, int var3, int var4){}@Overridepublic void surfaceDestroyed(SurfaceHolder var1){}public native boolean usb_camera_init();public native boolean usb_camera_stream_on();public native void start_preview(Object surface);
}

Android下基于UVC的UsbCam的开发相关推荐

  1. C++:Windows环境下基于Eclipse配置C/C++开发环境

    C++:Windows环境下基于Eclipse配置C/C++开发环境 目录 Windows下的MinGW下载.安装和配置 1.MinGW下载 2.MinGW安装与配置 3.基于Eclipse配置 Wi ...

  2. Android下基于XML的Graphics shape的高级UI设计,定义圆角背景等

    大家很多人都用过新浪微博android客户端,感觉它的UI实在做到很精致,昨天晚上熬夜研究了新浪微博的UI相关的代码,于是有了下面这个文章. 以前的UI设计一般有两种方式,首先是UI把图形设计好,分解 ...

  3. Android下基于SDL的位图渲染(一)

    环境准备 安装Android开发环境(java.android-sdk.android ndk.gcc). 我使用的ndk版本是r10b/r10d,在win10/ubutu 15.04编译 下载sdl ...

  4. Windows 10 下基于WSL的开源飞控开发环境配置(Ardupilot/PX4)

    目录 0 环境 1 环境概述 2 配置 WSL 2.1 安装 WSL2 2.2 安装工具链 3 配置VS Code 0 环境 Windows 10 build version >= 18917 ...

  5. Android下基于线程池的网络访问基础框架

    引言 现在的Android开发很多都使用Volley.OkHttp.Retrofit等框架,这些框架固然有优秀的地方(以后会写代码学习分享),但是我们今天介绍一种基于Java线程池的网络访问框架. 实 ...

  6. Android 外接基于UVC协议的摄像头并实现预览

    先来一段从网上找到的理论知识,对UVC协议有初步的印象 UVC协议:USB Video Class,USB视频类,是一种为USB视频捕获设备定义的协议标准. Android 平台支持使用即插即用的 U ...

  7. vxWorks6.6下基于vxBus的以太网驱动开发

    最近更换mpc8313的phy芯片,由原来的lxt972Phy更换为DP83849I,在此记录下本人在驱动开发过程中的点滴记录,以备日后查询,基于vxbus的网络驱动,vxBus驱动的注册遵循一致的方 ...

  8. C#下基于vlc的视频播放功能开发

    由于项目需要,要回放一些视频资料,经过多方调研,最后决定使用vlc方案.好处优点请大家自行百度谷歌,这里就不废话了. 开发环境: 工具: VS2010 .net4.0 程序类型:WindowsForm ...

  9. hal层 摄像头 android,Android下Linux摄像头的HAL封装设计

    摘要: 随着Android系统的推广,手机,移动设备以及各种智能终端大量采用Android作为操作系统.在Android系统当中,camera HAL (硬件抽象层)是联系上层摄像头接口与下层Linu ...

  10. Android应用---基于NDK的samples例程hello-jni学习NDK开发

    Android应用---基于NDK的samples例程hello-jni学习NDK开发 NDK下载地址:http://developer.android.com/tools/sdk/ndk/index ...

最新文章

  1. hql调用mysql存储过程_hibernate调用mysql存储过程
  2. R语言使用caret包的preProcess函数进行数据预处理:对所有的数据列进行YeoJohnson变换(将非正态分布数据列转换为正态分布数据、可以处理负数)、设置参数为YeoJohnson
  3. Ubuntu cocos2d-x 3.13版本游戏开发学习系列3 Cocos2d-x的坐标系
  4. SQL Server 临时表
  5. 什么是7层负载均衡?
  6. 模拟注册用户,按照以下要求实现相关功能:
  7. 云计算体系结构中soa构建层_云计算的服务模式及技术结构
  8. php图片制作源码,php进行图片裁剪及生成缩略图程序源代码
  9. JavaEE Tutorials (13) - 使用锁定控制对实体数据的并发访问
  10. mysql一对多关联查询分页_mysql一对多关联查询分页错误问题的解决方法
  11. LINUX安装依赖库冲突的最终版本:下列软件包有未满足的依赖关系/但是它将不会被安装/无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系
  12. ARM编译中的RO、RW和ZI DATA区段[转]
  13. 如何重启 Windows 10 子系统(WSL) ubuntu
  14. OpenCasCade开发环境搭建
  15. mysql8.0驱动包下载_Java JDBC 驱动包下载,MySQL 8及以上适用, mysql-connector-java-8.0.22.jar 官方版。...
  16. 产品规划三板斧:商业画布/精益画布/SWOT分析
  17. pdf照片显示正常打印时被翻转_2020年二级建造师打印须知
  18. 【HTML502】HTML基础02_标题_段落_文本格式化_链接
  19. dingding(钉钉)+sonar(代码质量管理工具)通知并打包成docker容器运行
  20. 计算机语言的发展历程和发展趋势

热门文章

  1. java折半查找(递归版)
  2. VS2005中ajax安装指南
  3. flask 请求上下文
  4. MySQL JDBC URL参数(转)
  5. 媒体查询@media scree
  6. 【FPGA】TestBench中关于@eachvec
  7. 三层交换机SVI实现不同VLAN通信.
  8. C语言的标准内存分配函数
  9. Windows Server 2003 R2中的DFS复制与管理
  10. mysql 的各种 join