前言
我们在对接Android平台摄像头或者屏幕采集、编码打包推送场景的时候,随着采集设备的不同,出来的数据也是多样化的,比如NV21、YV12、RGB、YUV等,更有图像数据甚至是翻转或者倒置的,如果上层处理,效率低下,本篇文章主要介绍下常用的编码前数据接口。相关资料或版本测试,也可联系大牛直播SDK(官方)
接口描述
1. Android设备前后摄像头数据:
Android自带的camera摄像头数据对接是最基础的,需要考虑的是摄像头方向问题,比如横屏、竖屏、还有部分定制设备home键在左侧的情况,相对来说处理比较简单,直接上接口,不再赘述。
@Override public void onPreviewFrame(byte[] data, Camera camera) { frameCount++; if (frameCount % 3000 == 0) { Log.i("OnPre", "gc+"); System.gc(); Log.i("OnPre", "gc-"); } if (data == null) { Parameters params = camera.getParameters(); Size size = params.getPreviewSize(); int bufferSize = (((size.width | 0x1f) + 1) * size.height * ImageFormat.getBitsPerPixel(params.getPreviewFormat())) / 8; camera.addCallbackBuffer(new byte[bufferSize]); } else { if (isRTSPPublisherRunning || isPushingRtmp || isRecording || isPushingRtsp) { libPublisher.SmartPublisherOnCaptureVideoData(publisherHandle, data, data.length, currentCameraType, currentOrigentation); } camera.addCallbackBuffer(data); } }
对应接口定义:
/** * Set live video data(no encoded data). * * @param cameraType: CAMERA_FACING_BACK with 0, CAMERA_FACING_FRONT with 1 * * @param curOrg: * PORTRAIT = 1; //竖屏 * LANDSCAPE = 2; //横屏 home键在右边的情况 * LANDSCAPE_LEFT_HOME_KEY = 3; //横屏 home键在左边的情况 * * @return {0} if successful */ public native int SmartPublisherOnCaptureVideoData(long handle, byte[] data, int len, int cameraType, int curOrg);
这里有个问题,有的设备,出来的数据,可能是旋转或者倒置的,为此,我们提供了NV21的对接接口,以满足数据旋转、水平、垂直翻转诉求。注意:y_stride一般系video_width, uv_strde合到一起也是传video_width.
/** * NV21数据接口 * * @param data: nv21 data * * @param len: data length * * @param width: 图像宽 * * @param height: 图像高 * * @param y_stride: y面步长 * * @param uv_stride: uv面步长 * * rotation_degree: 顺时针旋转, 必须是0, 90, 180, 270 * * @return {0} if successful */ public native int SmartPublisherOnNV21Data(long handle, byte[] data, int len, int width, int height, int y_stride, int uv_stride, int rotation_degree); /** * NV21数据接口 * * @param data: nv21 data * * @param len: data length * * @param width: 图像宽 * * @param height: 图像高 * * @param y_stride: y面步长 * * @param uv_stride: uv面步长 * * rotation_degree: 顺时针旋转, 必须是0, 90, 180, 270 * * @param is_vertical_flip: 是否垂直翻转, 0不翻转, 1翻转 * * @param is_horizontal_flip:是否水平翻转, 0不翻转, 1翻转 * * @return {0} if successful */ public native int SmartPublisherOnNV21DataV2(long handle, byte[] data, int len, int width, int height, int y_stride, int uv_stride, int rotation_degree, int is_vertical_flip, int is_horizontal_flip);
2. YV12的数据接口:
YV12的数据接口,主要是用于第三方的设备对接居多,这个接口的u_stride, v_stride分别是(width+1)/2,如果出来的数据需要旋转,通过rotation_degree来控制旋转角度即可。
/** * YV12数据接口 * * @param data: YV12 data * * @param width: 图像宽 * * @param height: 图像高 * * @param y_stride: y面步长 * * @param v_stride: v面步长 * * @param u_stride: u面步长 * * rotation_degree: 顺时针旋转, 必须是0, 90, 180, 270 * * @return {0} if successful */ public native int SmartPublisherOnYV12Data(long handle, byte[] data, int width, int height, int y_stride, int v_stride, int u_stride, int rotation_degree);
3. YUV数据接口:
支持标准的I420数据接口对接,不再赘述:
/** * Set live video data(no encoded data). * * @param data: I420 data * * @param len: I420 data length * * @param yStride: y stride * * @param uStride: u stride * * @param vStride: v stride * * @return {0} if successful */ public native int SmartPublisherOnCaptureVideoI420Data(long handle, byte[] data, int len, int yStride, int uStride, int vStride);
为了方便对接,我们提供了I420的扩展接口:
/** * 传I420图像接口 * * @param data: I420 data * * @param width: 图像宽 * * @param height: 图像高 * * @param y_stride: y stride * * @param u_stride: u stride * * @param v_stride: v stride * * @return {0} if successful */ public native int SmartPublisherOnCaptureVideoI420DataV2(long handle, byte[] data, int width, int height, int y_stride, int u_stride, int v_stride);
4. NV21转I420并旋转接口
这个接口也是主要用于特定的数据类型对接,NV21的数据,直接转I420后,对接即可,接口参数比较简单,不再赘述。
/** * NV21转换到I420并旋转 * * @param src: nv21 data * * @param dst: 输出I420 data * * @param width: 图像宽 * * @param height: 图像高 * * rotation_degree: 顺时针旋转, 必须是0, 90, 180, 270 * * @return {0} if successful */ public native int SmartPublisherNV21ToI420Rotate(long handle, byte[] src, int src_y_stride, int src_uv_stride, byte[] dst, int dst_y_stride, int dst_u_stride, int dst_v_stride, int width, int height, int rotation_degree);
5. 支持RGBA数据接入(支持裁剪后数据接入,主要用于同屏场景):
RGBA的主要用于屏幕共享场景下。
/** * Set live video data(no encoded data). * * @param data: RGBA data * * @param rowStride: stride information * * @param width: width * * @param height: height * * @return {0} if successful */ public native int SmartPublisherOnCaptureVideoRGBAData(long handle, ByteBuffer data, int rowStride, int width, int height); /** * 投递裁剪过的RGBA数据 * * @param data: RGBA data * * @param rowStride: stride information * * @param width: width * * @param height: height * * @param clipedLeft: 左; clipedTop: 上; clipedwidth: 裁剪后的宽; clipedHeight: 裁剪后的高; 确保传下去裁剪后的宽、高均为偶数 * * @return {0} if successful */ public native int SmartPublisherOnCaptureVideoClipedRGBAData(long handle, ByteBuffer data, int rowStride, int width, int height, int clipedLeft, int clipedTop, int clipedWidth, int clipedHeight); /** * Set live video data(no encoded data). * * @param data: ABGR flip vertical(垂直翻转) data * * @param rowStride: stride information * * @param width: width * * @param height: height * * @return {0} if successful */ public native int SmartPublisherOnCaptureVideoABGRFlipVerticalData(long handle, ByteBuffer data, int rowStride, int width, int height);
6. 支持RGB565数据接入(主要用于同屏场景):
RGB565数据类型也主要用于屏幕采集这块。
/** * Set live video data(no encoded data). * * @param data: RGB565 data * * @param row_stride: stride information * * @param width: width * * @param height: height * * @return {0} if successful */ public native int SmartPublisherOnCaptureVideoRGB565Data(long handle,ByteBuffer data, int row_stride, int width, int height);
7. 支持camera数据接入(主要用于camera2接口对接):
为了更高效率的兼容camera2数据采集模式。
/* * 专门为android.media.Image的android.graphics.ImageFormat.YUV_420_888格式提供的接口 * * @param width: 必须是8的倍数 * * @param height: 必须是8的倍数 * * @param crop_left: 剪切左上角水平坐标, 一般根据android.media.Image.getCropRect() 填充 * * @param crop_top: 剪切左上角垂直坐标, 一般根据android.media.Image.getCropRect() 填充 * * @param crop_width: 必须是8的倍数, 填0将忽略这个参数, 一般根据android.media.Image.getCropRect() 填充 * * @param crop_height: 必须是8的倍数, 填0将忽略这个参数,一般根据android.media.Image.getCropRect() 填充 * * @param y_plane 对应android.media.Image.Plane[0].getBuffer() * * @param y_row_stride 对应android.media.Image.Plane[0].getRowStride() * * @param u_plane 对应android.media.Image.Plane[1].getBuffer() * * @param v_plane 对应android.media.Image.Plane[2].getBuffer() * * @param uv_row_stride 对应android.media.Image.Plane[1].getRowStride() * * @param uv_pixel_stride 对应android.media.Image.Plane[1].getPixelStride() * * @param rotation_degree: 顺时针旋转, 必须是0, 90, 180, 270 * * @param is_vertical_flip: 是否垂直翻转, 0不翻转, 1翻转 * * @param is_horizontal_flip:是否水平翻转, 0不翻转, 1翻转 * * @param scale_width: 缩放宽,必须是8的倍数, 0不缩放 * * @param scale_height: 缩放高, 必须是8的倍数, 0不缩放 * * @param scale_filter_mode: 缩放质量, 范围必须是[1,3], 传0使用默认速度 * * @return {0} if successful */ public native int SmartPublisherOnImageYUV420888(long handle, int width, int height, int crop_left, int crop_top, int crop_width, int crop_height, ByteBuffer y_plane, int y_row_stride, ByteBuffer u_plane, ByteBuffer v_plane, int uv_row_stride, int uv_pixel_stride, int rotation_degree, int is_vertical_flip, int is_horizontal_flip, int scale_width, int scale_height, int scale_filter_mode);
8. RGB24和RGBA32接口
/** * Set live video data(no encoded data). * * @param buffer: RGB24 data * * @param length: data length * * @param rowStride: stride information * * @param width: width * * @param height: height * * @param is_vertical_flip: 是否垂直翻转, 0不翻转, 1翻转 * * @param is_horizontal_flip:是否水平翻转, 0不翻转, 1翻转 * * @param rotation_degree: 顺时针旋转, 必须是0, 90, 180, 270 * * @param scale_width: 缩放宽,必须是8的倍数, 0不缩放 * * @param scale_height: 缩放高, 必须是8的倍数, 0不缩放 * * @param scale_filter_mode: 缩放质量, 范围必须是[1,3], 传0使用默认质量 * * @return {0} if successful */ public native int SmartPublisherOnCaptureVideoRGB24Data(long handle, long buffer, int length, int rowStride, int width, int height, int is_vertical_flip, int is_horizontal_flip,int rotation_degree, int scale_width, int scale_height, int scale_filter_mode); /** * Set live video data(no encoded data). * * @param buffer: RGBA data * * @param length: data length * * @param rowStride: stride information * * @param width: width * * @param height: height * * @param is_vertical_flip: 是否垂直翻转, 0不翻转, 1翻转 * * @param is_horizontal_flip:是否水平翻转, 0不翻转, 1翻转 * * @param rotation_degree: 顺时针旋转, 必须是0, 90, 180, 270 * * @param scale_width: 缩放宽,必须是8的倍数, 0不缩放 * * @param scale_height: 缩放高, 必须是8的倍数, 0不缩放 * * @param scale_filter_mode: 缩放质量, 范围必须是[1,3], 传0使用默认质量 * * @return {0} if successful */ public native int SmartPublisherOnCaptureVideoRGBA32Data(long handle, long buffer, int length, int rowStride, int width, int height, int is_vertical_flip, int is_horizontal_flip,int rotation_degree, int scale_width, int scale_height, int scale_filter_mode);
总结:
以上仅是Android视频编码前的数据接口分享,感兴趣的开发者可酌情参考。
由此可见,部分公司或开发者提到,一个Android平台的RTMP推送模块只要几个接口,化繁为简几乎是不可能的。
一个好的产品的迭代,必然需要付出很大的精力和代价。