Android图片格式NV12(YUV420SP)转YUV420P

/ Android / 没有评论 / 3836浏览

Android设备调用摄像头采集数据时,Camera对象通过setPreviewCallback (Camera.PreviewCallback callback)函数,在onPreviewFrame(byte[] data,Camera camera)中回调采集的数据。采集到的数据格式和camera的参数配置有关,一般在打开摄像头预览之前,camera对象要进行一系列的配置,其中包括参数配置,camera.getParameters摄像头的parameter对象,再通过parameter对象配置参数,而onPreviewFrame()回调的数据格式就是通过parameter.setPreviewFormat(int format)配置的,通过调用ImageFormat的静态属性进行配置,一般我们会配置为NV21的格式。NV21是一种YUV图片格式,YUV格式因为数据排列等不同又分为NV21/NV12等很多格式。详细请查阅YUV格式详解,这里不为YUV原理作论述。 配置完成后,onPreviewFrame(byte[] data,Camera camera)中回调的data就是NV21格式的数据了,现在需要进行转换首先,我们来看看如何将NV21转换为NV12(YUV-420SP):

public static void NV21ToNV12(byte[] nv21,byte[] nv12,int width,int height) {
    if (nv21 ==null || nv12 ==null)return;

    int framesize = width * height;
    int i =0, j =0;

    System.arraycopy(nv21,0, nv12,0, framesize);

    for (i =0; i < framesize; i++) {
        nv12[i] = nv21[i];
    }

    for (j =0; j < framesize /2; j +=2) {
        nv12[framesize + j -1] = nv21[j + framesize];
    }

    for (j =0; j < framesize /2; j +=2) {
        nv12[framesize + j] = nv21[j + framesize -1];
    }
}

以上代码实现了NV21到NV12的转换,很多时候在进行视频采集,通过MediaCodec进行H264硬编码的时候,会进行这样的转换。

然后就是NV12转成YUV420P格式了。网上的YUV播放工具,很多不支持NV12的格式,所以我们需要进行转换才能播放。比如我们需要直接通过操作YUV,作视频叠加等,那肯定需要进行效果预览,所以,叠加后,转换成YUV420P格式,就可以通过YUV工具预览效果了。网上的NV12转换为YUV420P,我在查阅的时候只找到了C语言的。对于很多没有C语言基础的小伙伴,不是很友好,下面贴上JAVA的转换代码:


public static void NV12ToYuv420P(byte[] nv12, byte[] yuv420p, int width, int height) {
    int ySize = width * height;
    int i, j;
    //y
    for (i = 0; i < ySize; i++) {
        yuv420p[i] = nv12[i];
    }
    //u
    i = 0;
    for (j = 0; j < ySize / 2; j += 2) {
        yuv420p[ySize + i] = nv12[ySize + j];
        i++;
    }
    //v
    i = 0;
    for (j = 1; j < ySize / 2; j += 2) {
        yuv420p[ySize * 5 / 4 + i] = nv12[ySize + j];
        i++;
    }
}