我想将Android Camera采集的yuv420数据源直接纹理贴图,可是不知道怎么提取y、u、v分量,跪求解决啊、、、、androidCamera

解决方案 »

  1.   

    Camera默认的预览格式是 NV21,4:2:0 结构的,每个U、V用于4个Y
    参考下下面的代码/**
     * Converts YUV420 NV21 to ARGB8888
     * 
     * @param data byte array on YUV420 NV21 format.
     * @param width pixels width
     * @param height pixels height
     * @return a ARGB8888 pixels int array. Where each int is a pixels ARGB. 
     */
    public static int[] convertYUV420_NV21toARGB8888(byte [] data, int width, int height) {
        int size = width*height;
        int offset = size;
        int[] pixels = new int[size];
        int u, v, y1, y2, y3, y4;
     
        // i along Y and the final pixels
        // k along pixels U and V
        for(int i=0, k=0; i < size; i+=2, k+=1) {
            y1 = data[i  ]&0xff;
            y2 = data[i+1]&0xff;
            y3 = data[width+i  ]&0xff;
            y4 = data[width+i+1]&0xff;
     
            v = data[offset+k  ]&0xff;
            u = data[offset+k+1]&0xff;
            v = v-128;
            u = u-128;
     
            pixels[i  ] = convertYUVtoARGB(y1, u, v);
            pixels[i+1] = convertYUVtoARGB(y2, u, v);
            pixels[width+i  ] = convertYUVtoARGB(y3, u, v);
            pixels[width+i+1] = convertYUVtoARGB(y4, u, v);
     
            if (i!=0 && (i+2)%width==0)
                i+=width;
        }
     
        return pixels;
    }
     
    private static int convertYUVtoARGB(int y, int u, int v) {
        int r,g,b;
     
        r = y + (int)(1.402f*u);
        g = y - (int)(0.344f*v + 0.714f*u);
        b = y + (int)(1.772f*v);
        r = r>255? 255 : r<0 ? 0 : r;
        g = g>255? 255 : g<0 ? 0 : g;
        b = b>255? 255 : b<0 ? 0 : b;
        return 0xff000000 | (r<<16) | (g<<8) | b;
    }
      

  2.   

    不对,我不要转rgb的,我想要提取分量的~~
      

  3.   

    y分量里面的结构y1y2y3y4 y1y2y3y4...一直这样下去的顺序排序么?
      

  4.   

    还有这个感觉还是不对。" v = data[offset+k  ]&0xff;"这个地方应该会报越界,在jni里面GetByteArrayElements()获取的源数据长度是size。
      

  5.   

    代码我没试,是从wiki上复制过来的,问题应该不大,你要取分量的话,把解出来的Y、U、V保存到自己的数组里面就好了。
    关于NV21的结构,可以参考下面的文章
    http://ticktick.blog.51cto.com/823160/555791关于溢出的问题,我测试了一下,预览数据应该是没问题的,检查下是不是其他地方写错了Width: 480
    Height: 640
    size = Width * Height = 307200
    data.length = 460800
    data.length / size = 1.5
      

  6.   


    我觉得主要是Android Camera取出来的数据长度有问题,可能是压缩了或是怎么得。(数据结构这方面不太懂),我在java这边打印了的,不是1.5倍的长度而是1倍的长度。这是头疼的地方
      

  7.   


    你有看过Android Camera 获取的源数据的长度么?好像都是一陪的长度,和手机无关,好像~
      

  8.   

    我给你的数据就是我用真机测的,我开发的应用也是从Camera获取YUV处理,跑了二年了,挺正常的 @Override
    public synchronized void onPreviewFrame(byte[] data, Camera camera) {
    Size size = camera.getParameters().getPreviewSize();
    int format = camera.getParameters().getPreviewFormat();
    }
    10-12 12:06:31.916: D/@(29472): Data Length: 460800, Size: 640x480, format: 17
      

  9.   


    我试了下,然后我仿照你这个写了个在jni层的代码cpp的,用opengl纹理贴图之后颜色显示不出来,麻烦帮我看下,~~
    JNIEXPORT void JNICALL Java_com_spore_CameraView_decodeframe(JNIEnv * pEnv,
    jclass pClass, jbyteArray pSource, jint width, jint height,
    jbyteArray ydata, jbyteArray udata, jbyteArray vdata) {
    jbyte* data = (jbyte*) pEnv->GetByteArrayElements(pSource, 0);
    int32_t size = width * height;
    int32_t offset = size;
    int32_t lFrameSize = width * height;
    int32_t lYIndex, lUVIndex;
    int32_t  lM, lN;
    int8_t lColorY[lFrameSize];
    int8_t lColorU[lFrameSize / 4];
    int8_t lColorV[lFrameSize / 4]; // i along Y and the final pixels
    // k along pixels U and V
    lM=0;
    lN=0;
    for (int i = 0, k = 0; i < size; i += 2, k += 1) {
    lColorY[i] = data[i] & 0xff;
    lColorY[i+1] = data[i + 1] & 0xff;
    lColorY[width + i] = data[width + i] & 0xff;
    lColorY[width + i + 1] = data[width + i + 1] & 0xff; lColorV[lN] = data[offset + k] & 0xff-128;
    lColorU[lN] = data[offset + k + 1] & 0xff-128;
    lN++; if (i != 0 && (i + 2) % width == 0)
    i += width;
    }
    pEnv->SetByteArrayRegion(ydata, 0, lFrameSize, lColorY);
    pEnv->SetByteArrayRegion(udata, 0, lFrameSize / 4, lColorU);
    pEnv->SetByteArrayRegion(vdata, 0, lFrameSize / 4, lColorV); pEnv->ReleaseByteArrayElements(pSource, data, 0);}
      

  10.   


    大牛,能帮我看下么,我这边opengl贴图需要支持YV12的,所以我用了parameters.setPreviewFormat(ImageFormat.YV12);来设置预览格式
    yuv提取用了for (int32_t i = 0, k = 0; i < size; i += 2, k += 1) {
    lColorY[i] = data[i] ;
    lColorY[i+1] = data[i + 1] ;
    lColorY[width + i] = data[width + i] ;
    lColorY[width + i + 1] = data[width + i + 1];
    //
    lColorV[lN] = data[offset + k];
    lColorU[lN] = data[offset + k +width];
    lN++; if (i != 0 && (i + 2) % width == 0)
    i += width;
    }但是会出现偏色
      

  11.   

    这个吧,其实,OpenGL我不熟啊。
    Android camera设置预览格式的时候,不一定什么格式都支持的,需要先检查一下android.hardware.Camera.Parameters.getSupportedPreviewFormats()另外吧,这个貌似你已经可以把RGB分量从YUV中解析出来了,
    看你的截图,应该是把RGB分量组成Color值的时候某个分量写反了吧?在JNI里面读取/设置颜色的时候经常会有这种问题,你把R、G、B的值换换顺序?