Life is too short, don't talk nonsense, don't do useless work
When we use android to develop video recording, we will encounter the phenomenon of recorded video blurry screen, green screen, etc. There is no doubt that 90% of it is because the color format of the video encoding does not match the encoding format configured by the encoder.
The data previewed by the camera is generally two kinds of NV21 and YV12. The following code can find out the preview format supported by the mobile phone:
List previewFormats = mCamera.getParameters().getSupportedPreviewFormats();
Mobile MediaCodec codec color format is generally:
1、COLOR_FormatYUV420Planar
2、COLOR_FormatYUV420SemiPlanar
There are generally two color formats supported by YUV420Planar: NV21, NV12
There are generally two color formats supported by YUV420SemiPlanne: I420, YV12
The corresponding relationship is as follows:
I420: YYYYYYYY UU VV =>YUV420P
YV12: YYYYYYYY VV UU =>YUV420P
NV12: YYYYYYYY UVUV =>YUV420SP
NV21: YYYYYYYY VUVU =>YUV420SP
When previewing with the Camera camera:
The data format of the first parameter data here, if there is no special configuration, android returns the NV21 format by default, you can see the source code:
So if the camera supports YUV420SemiPlanne encoding format, then there is no problem with NV21 data, if not, then you need to convert the NV21 data format to the one supported by YUV420Planar
E.g:
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;
}
Also set the color coding format of mediaCodec:
mediaFormat_camera.setInteger(MediaFormat.KEY_COLOR_FORMAT,mColorFormat);
//mColorFormat can be MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar or MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar
If the camera supports YUV420SemiPlanne encoding format, then NV21 needs to be converted to NV12, otherwise an error will be reported
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];
}
}
———————————————
Original link: https://blog.csdn.net/weixin_42510446/article/details/111902999