基于V4L2驱动程序的USB摄像头Android(JNI)的编写(三)

来源:互联网 发布:便签的元数据 编辑:程序博客网 时间:2024/05/16 06:31

在上两篇文章基于V4L2驱动程序的USB摄像头Android(JNI)的编写(一)基于V4L2驱动程序的USB摄像头Android(JNI)的编写(二)中,我详细介绍了如何配置V4L2的环境、设置捕获视频数据的格式,以及视频流数据捕获的过程。但是由于我们捕获到的视频数据是YUYV422格式的,那么在这一篇文章中,我将主要介绍如何将YUYV422格式的数据转换成ARGB格式的数据,同时将ARGB格式数据转换成bitmap格式并上传给上层应用程序。

YUYV转ARGB

在YUYV422格式的数据转换成ARGB格式数据,我们这里采用了一个比较通用的转换函数。源代码如下:

[objc] view plain copy
  1. void yuyv422toABGRY(unsigned charchar *src)  
  2. {  
  3.   
  4.     int width=0;  
  5.     int height=0;  
  6.   
  7.     width = IMG_WIDTH;  
  8.     height = IMG_HEIGHT;  
  9.     //后面会介绍为什么这里要乘以2  
  10.     int frameSize =width*height*2;  
  11.   
  12.     int i;  
  13.   
  14.     if((!rgb || !ybuf)){  
  15.         return;  
  16.     }  
  17.     intint *lrgb = NULL;  
  18.     intint *lybuf = NULL;  
  19.     //将rgb的首地址赋给lrgb,这样只要给lrgb指向的地址赋值,那么rgb的值也会相应改变。  
  20.     lrgb = &rgb[0];  
  21.     lybuf = &ybuf[0];  
  22.   
  23.     if(yuv_tbl_ready==0){  
  24.         for(i=0 ; i<256 ; i++){  
  25.             //按照下面的代码,y1192_tbl[i]前面的16个数组都为0  
  26.             y1192_tbl[i] = 1192*(i-16);  
  27.             if(y1192_tbl[i]<0){  
  28.                 y1192_tbl[i]=0;  
  29.             }  
  30.   
  31.             v1634_tbl[i] = 1634*(i-128);  
  32.             v833_tbl[i] = 833*(i-128);  
  33.             u400_tbl[i] = 400*(i-128);  
  34.             u2066_tbl[i] = 2066*(i-128);  
  35.         }  
  36.         yuv_tbl_ready=1;  
  37.     }  
  38.     //由于是两个字节表示一个像素值,而这里每一次for循环,都会向前移4个字节,产生两个像素值,所以要产生IMG_WIDTH*IMG_HEIGHT个像素值,就必须乘以2  
  39.     for(i=0 ; i<frameSize ; i+=4){  
  40.         unsigned char y1, y2, u, v;  
  41.         //由于在上面的采集图像设置中设定为两个字节表示一个像素值,所以这4个字节便表示两个像素值  
  42.         y1 = src[i];//第一个字节  
  43.         u = src[i+1];//第二个字节  
  44.         y2 = src[i+2];//第三个字节  
  45.         v = src[i+3];//第四个字节  
  46.   
  47.         //根据y1、u、y2、v,以及上面的y1192_tbl[]、v1634_tbl[i]、v833_tbl[i]、u2066_tbl[i]数组的值,来设定r、g、b的值  
  48.         int y1192_1=y1192_tbl[y1];  
  49.         int r1 = (y1192_1 + v1634_tbl[v])>>10;  
  50.         int g1 = (y1192_1 - v833_tbl[v] - u400_tbl[u])>>10;  
  51.         int b1 = (y1192_1 + u2066_tbl[u])>>10;  
  52.   
  53.         int y1192_2=y1192_tbl[y2];  
  54.         int r2 = (y1192_2 + v1634_tbl[v])>>10;  
  55.         int g2 = (y1192_2 - v833_tbl[v] - u400_tbl[u])>>10;  
  56.         int b2 = (y1192_2 + u2066_tbl[u])>>10;  
  57.         //当r、g、b的值大于255时,赋值为255.当小于0时,赋值为0.  
  58.         r1 = r1>255 ? 255 : r1<0 ? 0 : r1;  
  59.         g1 = g1>255 ? 255 : g1<0 ? 0 : g1;  
  60.         b1 = b1>255 ? 255 : b1<0 ? 0 : b1;  
  61.         r2 = r2>255 ? 255 : r2<0 ? 0 : r2;  
  62.         g2 = g2>255 ? 255 : g2<0 ? 0 : g2;  
  63.         b2 = b2>255 ? 255 : b2<0 ? 0 : b2;  
  64.         //r由8位表示,g也由8位表示,b由8位表示。  
  65.         *lrgb++ = 0xff000000 | b1<<16 | g1<<8 | r1;  
  66.         *lrgb++ = 0xff000000 | b2<<16 | g2<<8 | r2;  
  67.         //将两个点的RGB值传入lrgb中  
  68.         if(lybuf!=NULL){  
  69.             *lybuf++ = y1;  
  70.             *lybuf++ = y2;  
  71.         }  
  72.     }  
  73.   
  74. }  
上面的函数是YUYV422转ARGB数据格式的一个固定写法,当然里面的framesize的大小是要根据实际大小进行改变的。同时还要注意rgb指针是一个全局变量,这里通过将rgb指针指向的值赋给lrgb指针,那么rgb指针所指向的值便和lrgb指针指向的值一同变化了。

ARGB转Bitmap

经过上面一步的yuyv422toABGRY函数,我们已经得到了32位的ARGB格式数据,但得到的ARGB数据并不能直接显示在屏幕上,虽然我们已经离这一步很近了,但是我们还是得做最后一步的转换,即将ARGB转换为Bitmap格式的数据。

要进行这一步的转换,这里我们要引入一个新的JNI头文件,bitmap.h
[objc] view plain copy
  1. #include <android/bitmap.h>  
引入这个头文件之后呢,需要在Android.mk文件中指定
LOCAL_LDLIBS` += `-ljnigraphics
在这个头文件中,有一个非常重要的结构体AndroidBitmapInfo,还有几个重要的方法AndroidBitmap_getInfo、AndroidBitmap_lockPixels、AndroidBitmap_unlockPixels
首先是结构体AndroidBitmapInfo,顾名思义该结构体实际上就是对Android的bitmap对象的一种简单描述,如bitmap的长、宽、像素数据格式等等。
下面介绍这三个方法以及如何使用
  1. AndroidBitmap_getInfo: 该函数的作用是通过给其传入bitmap参数,从而获取该bitmap的AndroidBitmapInfo描述符。
  2. AndroidBitmap_lockPixels:对bitmap像素缓存上锁(确保不会有多个进程同时进来这一步修改pixels数据),其实就是获取该bitmap的像素缓存的pixels的地址
  3. AndroidBitmap_unlockPixels:在使用完AndroidBitmap_lockPixels获取到该bitmap的像素缓存pixels地址之后,我们会对pixels指向的值进行修改,我们的ARGB数据值传递给pixels也是在这里进行的。修改完之后我们便会调用AndroidBitmap_unlockPixels方法,对bitmap进行解锁。

下面详细介绍如何实现ARGB转Bitmap的

  • 第一步:在Android上层应用程序中设定好bitmap对象,设定的内容包括,长、宽、像素格式
    [objc] view plain copy
    1. Bitmap bmp = Bitmap.createBitmap(IMG_WIDTH, IMG_HEIGHT, Bitmap.Config.ARGB_8888);  

  • 第二步:编写jni程序
    [objc] view plain copy
    1. //将ARGB转换成bmp类型的图像  
    2. void   
    3. Java_com_intel_view_CameraPreview_pixeltobmp( JNIEnv* env,jobject thiz,jobject bitmap){  
    4.   
    5.     jboolean bo;  
    6.   
    7.   
    8.     AndroidBitmapInfo  info;  
    9.     void*              pixels;  
    10.     int                ret;  
    11.     int i;  
    12.     intint *colors;  
    13.   
    14.     int width=0;  
    15.     int height=0;  
    16.   
    17.     if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {  
    18.         LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);  
    19.         return;  
    20.     }  
    21.       
    22.     width = info.width;  
    23.     height = info.height;  
    24.   
    25.     if(!rgb || !ybuf) return;  
    26.   
    27.     if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {  
    28.         LOGE("Bitmap format is not RGBA_8888 !");  
    29.         return;  
    30.     }  
    31.   
    32.     if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {  
    33.         LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);  
    34.     }  
    35.     //由于pixels所指向的地址与bitmap密切相关,将pixels指向的地址传递给colors,这时只要改变colors指向的地址的值,就可以改变pixel指向地址的值  
    36.     colors = (int*)pixels;  
    37.     intint *lrgb =NULL;  
    38.     lrgb = &rgb[0];  
    39.   
    40.     for(i=0 ; i<width*height ; i++){  
    41.         //将lrgb的值赋给colors,也就相当于赋值给了pixels  
    42.         *colors++ = *lrgb++;  
    43.     }  
    44.   
    45.     AndroidBitmap_unlockPixels(env, bitmap);  
    46.   
    47. }  
通过上面两步,这个时候bitmap已经存满的视频数据了,现在在上层应用程序就可以通过调用方法来进行显示了。
阅读全文
0 0
原创粉丝点击