实现 libYUV打包编译成so文件,并实现NV21转yuv420转码操作
1.下载libyuv源码,打包libyuv.so文件,mk文件如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := \
source/compare.cc \
source/compare_common.cc \
source/compare_neon.cc \
source/compare_neon64.cc \
source/compare_posix.cc \
source/compare_win.cc \
source/convert.cc \
source/convert_argb.cc \
source/convert_from.cc \
source/convert_from_argb.cc \
source/convert_jpeg.cc \
source/convert_to_argb.cc \
source/convert_to_i420.cc \
source/cpu_id.cc \
source/format_conversion.cc \
source/mjpeg_decoder.cc \
source/mjpeg_validate.cc \
source/planar_functions.cc \
source/rotate.cc \
source/rotate_argb.cc \
source/rotate_mips.cc \
source/rotate_neon.cc \
source/rotate_neon64.cc \
source/row_any.cc \
source/row_common.cc \
source/row_mips.cc \
source/row_neon.cc \
source/row_neon64.cc \
source/row_posix.cc \
source/row_win.cc \
source/row_x86.asm \
source/scale.cc \
source/scale_argb.cc \
source/scale_common.cc \
source/scale_mips.cc \
source/scale_neon.cc \
source/scale_neon64.cc \
source/scale_posix.cc \
source/scale_win.cc \
source/video_common.cc \
OpenCVHelper.cpp \
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_MODULE := libyuv
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
执行:ndk-build 生成 libyuv.so文件
2.调用libyuv中的方法实现NV21转yuv420,镜像,角度旋转代码实现:
int VideoStreamProcess(unsigned char *Src_data, unsigned char *Dst_data,
int src_width, int src_height,
bool EnableRotate, bool EnableMirror,
unsigned char *Dst_data_mirror, unsigned char *Dst_data_rotate,
int rotatemodel) {
//src:NV12 video size
int NV12_Size = src_width * src_height * 3 / 2;
int NV12_Y_Size = src_width * src_height;
//dst:YUV420 video size
int I420_Size = src_width * src_height * 3 / 2;
int I420_Y_Size = src_width * src_height;
int I420_U_Size = (src_width >> 1) * (src_height >> 1);
int I420_V_Size = I420_U_Size;
// video format transformation process
unsigned char *Y_data_Src = Src_data;
unsigned char *UV_data_Src = Src_data + NV12_Y_Size;
int src_stride_y = src_width;
int src_stride_uv = src_width;
unsigned char *Y_data_Dst = Dst_data;
unsigned char *U_data_Dst = Dst_data + I420_Y_Size;
unsigned char *V_data_Dst = Dst_data + I420_Y_Size + I420_U_Size;
int Dst_Stride_Y = src_width;
int Dst_Stride_U = src_width >> 1;
int Dst_Stride_V = Dst_Stride_U;
//NV12ToI420
libyuv::NV21ToI420(Y_data_Src, src_stride_y,
UV_data_Src, src_stride_uv,
Y_data_Dst, Dst_Stride_Y,
U_data_Dst, Dst_Stride_U,
V_data_Dst, Dst_Stride_V,
src_width, src_height);
// video mirror process
unsigned char *Y_data_Dst_mirror = Dst_data_mirror;
unsigned char *U_data_Dst_mirror = Dst_data_mirror + I420_Y_Size;
unsigned char *V_data_Dst_mirror = Dst_data_mirror + I420_Y_Size + I420_U_Size;
int Dst_Stride_Y_mirror = src_width;
int Dst_Stride_U_mirror = src_width >> 1;
int Dst_Stride_V_mirror = Dst_Stride_U_mirror;
if (EnableMirror) {
libyuv::I420Mirror(Y_data_Dst, Dst_Stride_Y,
U_data_Dst, Dst_Stride_U,
V_data_Dst, Dst_Stride_V,
Y_data_Dst_mirror, Dst_Stride_Y_mirror,
U_data_Dst_mirror, Dst_Stride_U_mirror,
V_data_Dst_mirror, Dst_Stride_V_mirror,
src_width, src_height);
}
//video rotate process
if (EnableRotate) {
int Dst_Stride_Y_rotate;
int Dst_Stride_U_rotate;
int Dst_Stride_V_rotate;
unsigned char *Y_data_Dst_rotate = Dst_data_rotate;
unsigned char *U_data_Dst_rotate = Dst_data_rotate + I420_Y_Size;
unsigned char *V_data_Dst_rotate = Dst_data_rotate + I420_Y_Size + I420_U_Size;
if (rotatemodel == libyuv::kRotate90 || rotatemodel == libyuv::kRotate270) {
Dst_Stride_Y_rotate = src_height;
Dst_Stride_U_rotate = src_height >> 1;
Dst_Stride_V_rotate = Dst_Stride_U_rotate;
}
else {
Dst_Stride_Y_rotate = src_width;
Dst_Stride_U_rotate = src_width >> 1;
Dst_Stride_V_rotate = Dst_Stride_U_rotate;
}
if (EnableMirror) {
libyuv::I420Rotate(Y_data_Dst_mirror, Dst_Stride_Y_mirror,
U_data_Dst_mirror, Dst_Stride_U_mirror,
V_data_Dst_mirror, Dst_Stride_V_mirror,
Y_data_Dst_rotate, Dst_Stride_Y_rotate,
U_data_Dst_rotate, Dst_Stride_U_rotate,
V_data_Dst_rotate, Dst_Stride_V_rotate,
src_width, src_height,
(libyuv::RotationMode) rotatemodel);
}
else {
libyuv::I420Rotate(Y_data_Dst, Dst_Stride_Y,
U_data_Dst, Dst_Stride_U,
V_data_Dst, Dst_Stride_V,
Y_data_Dst_rotate, Dst_Stride_Y_rotate,
U_data_Dst_rotate, Dst_Stride_U_rotate,
V_data_Dst_rotate, Dst_Stride_V_rotate,
src_width, src_height,
(libyuv::RotationMode) rotatemodel);
}
}
return 0;
}
3.测试调用
@Override
public void onPreviewFrame(byte[] data, Camera callbackCamera) {
if (mCamera == null || !CameraInterface.getInstance().isOpenCamera() || mCamera != callbackCamera) {
return;
}
try {
int rotation = 0;
if (myOrientationDetector != null)
rotation = myOrientationDetector.getRotation();
cameraType = CameraInterface.getInstance().getCameraType();
//调用libYuv,转yuv420并旋转270度
byte[] rotaeData = CodeUtil.getInstance().nv21To420(data, mCaptureWidth, mCaptureHeight, 270, false, true);
} catch (Exception e) {
e.printStackTrace();
}
mCamera.addCallbackBuffer(data);
}
4.测试结果比较(同一个时间段)
图一: 使用libyuv,转码旋转270度的cpu使用情况
图二:使用普通的算法,转码旋转270度的cpu使用情况