人生苦短,不说废话,不作无用功 java
当咱们在用android 开发视频录制时候,会遇到录制出来的视频 花屏、绿屏等现象,不用怀疑,90%是由于视频编码时候的颜色格式和编码器配置的编码格式不匹配。android
相机预览的数据通常是两种 NV21和YV12,如下代码能够查出手机支持的预览格式:编码
List<Integer> previewFormats = mCamera.getParameters().getSupportedPreviewFormats();
手机MediaCodec编解码颜色格式通常为:spa
一、COLOR_FormatYUV420Planar
二、COLOR_FormatYUV420SemiPlanar
YUV420Planar支持的颜色格式通常也有两种:NV2一、NV12orm
YUV420SemiPlanne支持的颜色格式通常也有两种:I420、YV12视频
对应关系以下:blog
I420: YYYYYYYY UU VV =>YUV420P
YV12: YYYYYYYY VV UU =>YUV420P
NV12: YYYYYYYY UVUV =>YUV420SP
NV21: YYYYYYYY VUVU =>YUV420SP开发
用Camera摄像头预览的时候:get
这里第一个参数data的数据格式,若是没有特殊配置,android默认返回的是NV21格式,查看源码能够看到:源码
因此若是相机支持YUV420SemiPlanne编码格式,那么NV21数据时没问题的,若是不支持那么须要将NV21的数据格式转为YUV420Planar所支持的
例如:
public final static int NV21_TO_yuv420P(byte[] dst, byte[] src, int w, int h){
int ysize = w * h;
int usize = w * h * 1 / 4;
byte[] dsttmp = dst;
// y
System.arraycopy(src, 0, dst, 0, ysize);
// u, 1/4
int srcPointer = ysize;
int dstPointer = ysize;
int count = usize;
while (count > 0)
{
srcPointer++;
dst[dstPointer] = src[srcPointer];
dstPointer++;
srcPointer++;
count--;
}
// v, 1/4
srcPointer = ysize;
count = usize;
while (count > 0)
{
dst[dstPointer] = src[srcPointer];
dstPointer++;
srcPointer += 2;
count--;
}
dst = dsttmp;
// _EF_TIME_DEBUG_END(0x000414141);
return 0;
}
同时设置mediaCodec的颜色编码格式:
mediaFormat_camera.setInteger(MediaFormat.KEY_COLOR_FORMAT,mColorFormat); //mColorFormat能够是 MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar 或者 MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar
若是相机支持YUV420SemiPlanne编码格式,那么NV21须要转为NV12 不然会报错
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];
}
}