我们在做Android平台GB28181设备接入模块的时候,遇到这样的需求,做移动对讲的时候,是不需要视频数据的,但是国标平台侧,没有视频的话,大多平台又无法播纯音频打包的数据(网页端大多基于http-flv或webrtc实现),基于此,我们做了个简单的处理,通过Bitmap生成个32*32的黑帧,然后,确保上行的音视频数据都有,但是由于视频系黑帧数据,几乎不占用带宽。
废话不多说,上代码:
代码语言:java复制 class LayerPostThread extends Thread
{
private volatile boolean is_exit_ = false;
private long handle_ = 0;
ByteBuffer image_buffer_ = null;
private int width_ = 32;
private int height_ = 32;
@Override
public void run() {
image_buffer_ = null;
if (0 == handle_)
return;
generateImageBuffer(width_, height_);
while(!is_exit_) {
postImageLayer(0, 0, 0, width_, height_);
waitSleep(40);
}
image_buffer_ = null;
}
private void generateImageBuffer(int width, int height)
{
Bitmap bitmap = android.graphics.Bitmap.createBitmap(width, height, android.graphics.Bitmap.Config.ARGB_8888);
bitmap.eraseColor(android.graphics.Color.argb(255, 0, 0, 0));
if (null == bitmap)
return;
if ( image_buffer_ != null) {
image_buffer_.rewind();
if ( image_buffer_.remaining() < bitmap.getByteCount())
image_buffer_ = null;
}
if (null == image_buffer_)
image_buffer_ = ByteBuffer.allocateDirect(bitmap.getByteCount());
bitmap.copyPixelsToBuffer(image_buffer_);
}
private int postImageLayer(int index, int left, int top, int video_w, int video_h) {
if (video_w < 1 || video_h < 1)
return 0;
int scale_w = 0, scale_h = 0, scale_filter_mode = 0;
libPublisher.PostLayerImageRGBA8888ByteBuffer(handle_, index, left, top, image_buffer_, 0,
4*video_w, video_w, video_h,
0, 0, scale_w, scale_h, scale_filter_mode,0);
return 0;
}
public void startPost(long handle, int w, int h, boolean is_text, boolean is_pitcure) {
this.is_exit_ = false;
this.handle_ = handle;
try {
this.start();
} catch (Exception e) {
e.printStackTrace();
}
}
public void stopPost() {
this.is_exit_ = true;
try {
this.join(1000);
}
catch (Exception e) {
e.printStackTrace();
}
handle_ = 0;
}
}
外部调用逻辑如下:
代码语言:java复制 private LayerPostThread layer_post_thread_ = null;
private void startLayerPostThread() {
if (null == layer_post_thread_) {
layer_post_thread_ = new LayerPostThread();
layer_post_thread_.startPost(publisherHandle, video_width_, video_height_, isHasTextWatermark(), isHasPictureWatermark());
}
}
private void stopLayerPostThread() {
if (layer_post_thread_ != null) {
layer_post_thread_.stopPost();
layer_post_thread_ = null;
}
}
简单来说,读取到的Bitmap数据,转bytebuffer,然后通过调用PostLayerImageRGBA8888ByteBuffer()接口投递到底层,PostLayerImageRGBA8888ByteBuffer()的接口设计如下:
代码语言:java复制 /*
* SmartPublisherJniV2.java
* Author: daniusdk.com
*/
/**
* 投递层RGBA8888图像,如果不需要Aplpha通道的话, 请使用RGBX8888接口, 效率高
*
* @param index: 层索引, 必须大于等于0, 注意:如果index是0的话,将忽略Alpha通道
*
* @param left: 层叠加的左上角坐标, 对于第0层的话传0
*
* @param top: 层叠加的左上角坐标, 对于第0层的话传0
*
* @param rgba_plane: rgba 图像数据
*
* @param offset: 图像偏移, 这个主要目的是用来做clip的, 一般传0
*
* @param row_stride: stride information
*
* @param width: width, 必须大于1, 如果是奇数, 将减1
*
* @param height: height, 必须大于1, 如果是奇数, 将减1
*
* @param is_vertical_flip: 是否垂直翻转, 0不翻转, 1翻转
*
* @param is_horizontal_flip:是否水平翻转, 0不翻转, 1翻转
*
* @param scale_width: 缩放宽,必须是偶数, 0或负数不缩放
*
* @param scale_height: 缩放高, 必须是偶数, 0或负数不缩放
*
* @param scale_filter_mode: 缩放质量, 传0使用默认速度,可选等级范围是:[1,3],值越大缩放质量越好, 但速度越慢
*
* @param rotation_degree: 顺时针旋转, 必须是0, 90, 180, 270, 注意:旋转是在缩放, 垂直/水品反转之后再做, 请留意顺序
*
* @return {0} if successful
*/
public native int PostLayerImageRGBA8888ByteBuffer(long handle, int index, int left, int top,
ByteBuffer rgba_plane, int offset, int row_stride, int width, int height,
int is_vertical_flip, int is_horizontal_flip,
int scale_width, int scale_height, int scale_filter_mode,
int rotation_degree);
这个接口非常强大,可以针对传下去的数据,进行裁剪、反转等各种操作,感兴趣的开发者可以尝试看看。