当前位置:编程学习 > wap >>

Android Camera问题

我想将Android Camera采集的yuv420数据源直接纹理贴图,可是不知道怎么提取y、u、v分量,跪求解决啊、、、、 android Camera --------------------编程问答-------------------- 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;
}
--------------------编程问答-------------------- mark一下 学习了 --------------------编程问答-------------------- 高手啊 ,,,谢谢啦 --------------------编程问答-------------------- 不对,我不要转rgb的,我想要提取分量的~~ --------------------编程问答--------------------
引用 1 楼 youngc527 的回复:
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;
}



y分量里面的结构y1y2y3y4 y1y2y3y4...一直这样下去的顺序排序么? --------------------编程问答-------------------- 还有这个感觉还是不对。" v = data[offset+k  ]&0xff;"这个地方应该会报越界,在jni里面GetByteArrayElements()获取的源数据长度是size。 --------------------编程问答-------------------- 代码我没试,是从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 --------------------编程问答--------------------
引用 7 楼 youngc527 的回复:
代码我没试,是从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


我觉得主要是Android Camera取出来的数据长度有问题,可能是压缩了或是怎么得。(数据结构这方面不太懂),我在java这边打印了的,不是1.5倍的长度而是1倍的长度。这是头疼的地方 --------------------编程问答-------------------- 你不会是用中兴的手机测试的吧 --------------------编程问答--------------------
引用 9 楼 youngc527 的回复:
你不会是用中兴的手机测试的吧

三星的平板N8000 --------------------编程问答--------------------
引用 9 楼 youngc527 的回复:
你不会是用中兴的手机测试的吧


你有看过Android Camera 获取的源数据的长度么?好像都是一陪的长度,和手机无关,好像~ --------------------编程问答-------------------- 我给你的数据就是我用真机测的,我开发的应用也是从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 --------------------编程问答--------------------
引用 12 楼 youngc527 的回复:
我给你的数据就是我用真机测的,我开发的应用也是从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


我试了下,然后我仿照你这个写了个在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);

} --------------------编程问答--------------------
引用 12 楼 youngc527 的回复:
我给你的数据就是我用真机测的,我开发的应用也是从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


大牛,能帮我看下么,我这边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;
}

但是会出现偏色
--------------------编程问答--------------------
引用 12 楼 youngc527 的回复:
我给你的数据就是我用真机测的,我开发的应用也是从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



--------------------编程问答-------------------- --------------------编程问答-------------------- 这个吧,其实,OpenGL我不熟啊。
Android camera设置预览格式的时候,不一定什么格式都支持的,需要先检查一下

android.hardware.Camera.Parameters.getSupportedPreviewFormats()

另外吧,这个貌似你已经可以把RGB分量从YUV中解析出来了,
看你的截图,应该是把RGB分量组成Color值的时候某个分量写反了吧?在JNI里面读取/设置颜色的时候经常会有这种问题,你把R、G、B的值换换顺序?
补充:移动开发 ,  Android
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,