很多开发者在做Android平台RTMP推流或轻量级RTSP服务(摄像头或同屏)时,总感觉接口不够用,以大牛直播SDK为例 (Github) 我们来总结下,我们常规需要支持的编码前音视频数据有哪些类型:
1. Android摄像头前后camera通过OnPreviewFrame()回调的数据接口:
@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);
2. 部分定制设备,只支持YV12的数据:
/** * 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. 支持NV21数据接口:
nv21数据接口,除了用于常规的camera数据接入外,部分定制摄像头出来的数据发生翻转,这个接口也支持。
/** * 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);
4. 支持YUV数据接入:
/** * 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);
5. 支持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数据接入(主要用于同屏场景):
/** * 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接口对接):
/* * 专门为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. 支持PCM数据接入:
/** * 传递PCM音频数据给SDK, 每10ms音频数据传入一次 * * @param pcmdata: pcm数据, 需要使用ByteBuffer.allocateDirect分配, ByteBuffer.isDirect()是true的才行. * @param size: pcm数据大小 * @param sample_rate: 采样率,当前只支持{44100, 8000, 16000, 24000, 32000, 48000}, 推荐44100 * @param channel: 通道, 当前通道支持单通道(1)和双通道(2),推荐单通道(1) * @param per_channel_sample_number: 这个请传入的是 sample_rate/100 */ public native int SmartPublisherOnPCMData(long handle, ByteBuffer pcmdata, int size, int sample_rate, int channel, int per_channel_sample_number); /** * 传递PCM音频数据给SDK, 每10ms音频数据传入一次 * * @param pcmdata: pcm数据, 需要使用ByteBuffer.allocateDirect分配, ByteBuffer.isDirect()是true的才行. * @param offset: pcmdata的偏移 * @param size: pcm数据大小 * @param sample_rate: 采样率,当前只支持{44100, 8000, 16000, 24000, 32000, 48000}, 推荐44100 * @param channel: 通道, 当前通道支持单通道(1)和双通道(2),推荐单通道(1) * @param per_channel_sample_number: 这个请传入的是 sample_rate/100 */ public native int SmartPublisherOnPCMDataV2(long handle, ByteBuffer pcmdata, int offset, int size, int sample_rate, int channel, int per_channel_sample_number); /** * 传递PCM音频数据给SDK, 每10ms音频数据传入一次 * * @param pcm_short_array: pcm数据, short是native endian order * @param offset: 数组偏移 * @param len: 数组项数 * @param sample_rate: 采样率,当前只支持{44100, 8000, 16000, 24000, 32000, 48000}, 推荐44100 * @param channel: 通道, 当前通道支持单通道(1)和双通道(2),推荐单通道(1) * @param per_channel_sample_number: 这个请传入的是 sample_rate/100 */ public native int SmartPublisherOnPCMShortArray(long handle, short[] pcm_short_array, int offset, int len, int sample_rate, int channel, int per_channel_sample_number);
9. 支持远端PCM数据接入和混音后PCM数据接入(主要用于一对一互动):
/** * Set far end pcm data * * @param pcmdata : 16bit pcm data * @param sampleRate: audio sample rate * @param channel: auido channel * @param per_channel_sample_number: per channel sample numbers * @param is_low_latency: if with 0, it is not low_latency, if with 1, it is low_latency * @return {0} if successful */ public native int SmartPublisherOnFarEndPCMData(long handle, ByteBuffer pcmdata, int sampleRate, int channel, int per_channel_sample_number, int is_low_latency); /** * 传递PCM混音音频数据给SDK, 每10ms音频数据传入一次 * * @param stream_index: 当前只能传1, 传其他返回错误 * @param pcm_data: pcm数据, 需要使用ByteBuffer.allocateDirect分配, ByteBuffer.isDirect()是true的才行. * @param offset: pcmdata的偏移 * @param size: pcm数据大小 * @param sample_rate: 采样率,当前只支持{44100, 8000, 16000, 24000, 32000, 48000} * @param channels: 通道, 当前通道支持单通道(1)和双通道(2) * @param per_channel_sample_number: 这个请传入的是 sample_rate/100 */ public native int SmartPublisherOnMixPCMData(long handle, int stream_index, ByteBuffer pcm_data, int offset, int size, int sample_rate, int channels, int per_channel_sample_number); /** * 传递PCM混音音频数据给SDK, 每10ms音频数据传入一次 * * @param stream_index: 当前只能传1, 传其他返回错误 * @param pcm_short_array: pcm数据, short是native endian order * @param offset: 数组偏移 * @param len: 数组项数 * @param sample_rate: 采样率,当前只支持{44100, 8000, 16000, 24000, 32000, 48000} * @param channels: 通道, 当前通道支持单通道(1)和双通道(2) * @param per_channel_sample_number: 这个请传入的是 sample_rate/100 */ public native int SmartPublisherOnMixPCMShortArray(long handle, int stream_index, short[] pcm_short_array, int offset, int len, int sample_rate, int channels, int per_channel_sample_number);
总结:
以上只是编码前数据接口,一个产品如果想做的足够通用,需要对接的太多了,你觉得呢?