Android如何回调编码后的音视频数据
有开发者提到,在RTMP推送端的基础上,希望能回调编码后的音视频数据,便于开发者对接第三方系统,如GB28181.
为此,我们加了一下接口:
1. 设置音视频callback
对应接口:
/**
* Set Audio Encoded Data Callback.
*
* @param audio_encoded_data_callback: Audio Encoded Data Callback.
*
* @return {0} if successful
*/
public native int SmartPublisherSetAudioEncodedDataCallback(long handle, Object audio_encoded_data_callback);
/**
* Set Video Encoded Data Callback.
*
* @param video_encoded_data_callback: Video Encoded Data Callback.
*
* @return {0} if successful
*/
public native int SmartPublisherSetVideoEncodedDataCallback(long handle, Object video_encoded_data_callback);
设置回调:
libPublisher.SmartPublisherSetAudioEncodedDataCallback(publisherHandle, new PublisherAudioEncodedDataCallback());
libPublisher.SmartPublisherSetVideoEncodedDataCallback(publisherHandle, new PublisherVideoEncodedDataCallback());
2. 实现 PublisherAudioEncodedDataCallback 和 PublisherVideoEncodedDataCallback:
class PublisherAudioEncodedDataCallback implements NTAudioDataCallback
{
private int audio_buffer_size = 0;
private int param_info_size = 0;
private ByteBuffer audio_buffer_ = null;
private ByteBuffer parameter_info_ = null;
@Override
public ByteBuffer getAudioByteBuffer(int size)
{
//Log.i("getAudioByteBuffer", "size: " + size);
if( size < 1 )
{
return null;
}
if ( size <= audio_buffer_size && audio_buffer_ != null )
{
return audio_buffer_;
}
audio_buffer_size = size + 512;
audio_buffer_size = (audio_buffer_size+0xf) & (~0xf);
audio_buffer_ = ByteBuffer.allocateDirect(audio_buffer_size);
// Log.i("getAudioByteBuffer", "size: " + size + " buffer_size:" + audio_buffer_size);
return audio_buffer_;
}
@Override
public ByteBuffer getAudioParameterInfo(int size)
{
//Log.i("getAudioParameterInfo", "size: " + size);
if(size < 1)
{
return null;
}
if ( size <= param_info_size && parameter_info_ != null )
{
return parameter_info_;
}
param_info_size = size + 32;
param_info_size = (param_info_size+0xf) & (~0xf);
parameter_info_ = ByteBuffer.allocateDirect(param_info_size);
//Log.i("getAudioParameterInfo", "size: " + size + " buffer_size:" + param_info_size);
return parameter_info_;
}
public void onAudioDataCallback(int ret, int audio_codec_id, int sample_size, int is_key_frame, long timestamp, int sample_rate, int channel, int parameter_info_size, long reserve)
{
Log.i("onAudioDataCallback", "ret: " + ret + ", audio_codec_id: " + audio_codec_id + ", sample_size: " + sample_size + ", timestamp: " + timestamp +
",sample_rate:" + sample_rate + ",chn: " + channel + ", parameter_info_size:" + parameter_info_size);
if ( audio_buffer_ == null)
return;
audio_buffer_.rewind();
if ( ret == 0 && publisherHandle2 != 0 ) {
libPublisher.SmartPublisherPostAudioEncodedData(publisherHandle2, audio_codec_id, audio_buffer_, sample_size, is_key_frame, timestamp, parameter_info_, parameter_info_size);
}
}
}
class PublisherVideoEncodedDataCallback implements NTVideoDataCallback
{
private int video_buffer_size = 0;
private ByteBuffer video_buffer_ = null;
@Override
public ByteBuffer getVideoByteBuffer(int size)
{
//Log.i("getVideoByteBuffer", "size: " + size);
if( size < 1 )
{
return null;
}
if ( size <= video_buffer_size && video_buffer_ != null )
{
return video_buffer_;
}
video_buffer_size = size + 1024;
video_buffer_size = (video_buffer_size+0xf) & (~0xf);
video_buffer_ = ByteBuffer.allocateDirect(video_buffer_size);
// Log.i("getVideoByteBuffer", "size: " + size + " buffer_size:" + video_buffer_size);
return video_buffer_;
}
public void onVideoDataCallback(int ret, int video_codec_id, int sample_size, int is_key_frame, long timestamp, int width, int height, long presentation_timestamp)
{
Log.i("onVideoDataCallback", "ret: " + ret + ", video_codec_id: " + video_codec_id + ", sample_size: " + sample_size + ", is_key_frame: "+ is_key_frame + ", timestamp: " + timestamp +
",width: " + width + ", height:" + height + ",presentation_timestamp:" + presentation_timestamp);
if ( video_buffer_ == null)
return;
video_buffer_.rewind();
if ( ret == 0 && publisherHandle2 !=0 ) {
libPublisher.SmartPublisherPostVideoEncodedData(publisherHandle2, video_codec_id, video_buffer_, sample_size, is_key_frame, timestamp, presentation_timestamp);
}
}
}
3. 提供开始回调数据和停止回调数据接口:
/**
* Start output Encoded Data(用于编码后的音视频数据回调)
*
* @return {0} if successful
*/
public native int SmartPublisherStartOutputEncodedData(long handle);
/**
* Stop output Encoded Data
*
* @return {0} if successful
*/
public native int SmartPublisherStopOutputEncodedData(long handle);
4. 上层demo调用实例:
class ButtonEncodedDataCallbackListener implements OnClickListener {
public void onClick(View v) {
if (isEncodedDatacallbackRunning) {
stopEncodedDataCallback();
if (!isPushing && !isRTSPPublisherRunning && !isRecording) {
ConfigControlEnable(true);
}
btnEncodedDataCallback.setText("启动编码数据回调");
isEncodedDatacallbackRunning = false;
if (publisherHandle2 != 0) {
libPublisher.SmartPublisherStopPublisher(publisherHandle2);
libPublisher.SmartPublisherClose(publisherHandle2);
publisherHandle2 = 0;
}
return;
}
Log.i(TAG, "onClick start encoded data callback..");
if (libPublisher == null)
return;
if (!isPushing && !isRTSPPublisherRunning && !isRecording) {
InitAndSetConfig();
}
libPublisher.SmartPublisherSetAudioEncodedDataCallback(publisherHandle, new PublisherAudioEncodedDataCallback());
libPublisher.SmartPublisherSetVideoEncodedDataCallback(publisherHandle, new PublisherVideoEncodedDataCallback());
int startRet = libPublisher.SmartPublisherStartOutputEncodedData(publisherHandle);
if (startRet != 0) {
isEncodedDatacallbackRunning = false;
Log.e(TAG, "Failed to start encoded data callback.");
return;
}
if (!isPushing && !isRTSPPublisherRunning && !isRecording) {
if (pushType == 0 || pushType == 1) {
CheckInitAudioRecorder(); //enable pure video publisher..
}
ConfigControlEnable(false);
}
btnEncodedDataCallback.setText("停止编码数据回调");
isEncodedDatacallbackRunning = true;
int audio_opt = 2;
int video_opt = 2;
publisherHandle2 = libPublisher.SmartPublisherOpen(myContext, audio_opt, video_opt,
videoWidth, videoHeight);
if (publisherHandle2 == 0) {
Log.e(TAG, "sdk open failed!");
return;
}
String relayUrl = "rtmp://player.daniulive.com:1935/hls/stream8888";
libPublisher.SmartPublisherSetURL(publisherHandle2, relayUrl);
libPublisher.SmartPublisherStartPublisher(publisherHandle2);
}
}
;
//停止编码后数据回调
private void stopEncodedDataCallback() {
if(!isEncodedDatacallbackRunning)
{
return;
}
if (!isPushing && !isRTSPPublisherRunning && !isRecording) {
if (audioRecord_ != null) {
Log.i(TAG, "stopRecorder, call audioRecord_.StopRecording..");
audioRecord_.Stop();
if (audioRecordCallback_ != null) {
audioRecord_.RemoveCallback(audioRecordCallback_);
audioRecordCallback_ = null;
}
audioRecord_ = null;
}
}
if (libPublisher != null) {
libPublisher.SmartPublisherStopOutputEncodedData(publisherHandle);
}
if (!isPushing && !isRTSPPublisherRunning && !isRecording) {
if (publisherHandle != 0) {
if (libPublisher != null) {
libPublisher.SmartPublisherClose(publisherHandle);
publisherHandle = 0;
}
}
}
}
此demo为了便于演示方便,另启动了个新的推送实例,音视频编码后的数据,通过新的实例,调用编码后的音视频数据接口,继续推RTMP出去。
此Demo的优越性在于,回调编码后的音视频数据功能,可与推RTMP、录像、内置RTSP服务SDK组合使用,亦可单独使用。
附录,目前大牛直播SDK RTMP推送端支持以下功能:
Windows/Android/iOS RTMP直播推流SDK
如不单独说明,系Windows、Android、iOS全平台支持。
- [视频采集处理]Windows平台涵盖“Windows视频采集处理SDK”功能;
- [音频采集处理]Windows平台涵盖“Windows音频采集处理SDK”功能;
- [本地预览]Windows平台支持摄像头/屏幕/合成数据实时预览功能,Android/iOS平台支持本地前后置摄像头预览;
- [摄像头反转/旋转]Windows平台支持摄像头水平反转、垂直反转、0°/90°/180°/270°旋转;
- [RTMP推流]超低延时的RTMP协议直播推流SDK(Windows支持RTMP扩展H.265推送);
- [视频格式]Windows平台支持H.264/H.265编码,Android/iOS平台支持H.264编码;
- [音频格式]Windows/Android/iOS平台支持AAC编码,Windows/Android平台支持Speex编码;
- [音频编码]Windows/Android平台支持Speex推送、Speex编码质量设置;
- [H.264硬编码]Android/iOS支持H.264硬编码;
- [硬编码码自适应]Android/iOS平台支持硬编码自适应,如检测到硬编码不支持,自动切换到软编;
- [编码参数配置]支持gop间隔、帧率、bit-rate、软编码profile、软编码速度设置;
- [多实例推送]支持多实例推送(如同时推送屏幕/摄像头和外部数据);
- [RTMP扩展H.265]Windows推送SDK支持RTMP扩展H.265推送,针对摄像头采集编码,使用H.265可变码率,带宽大幅节省,效果直逼传统H.265编码摄像头;
- [横竖屏推流]Android/iOS平台支持支持横屏、竖屏推流;
- [多分辨率支持]支持摄像头或屏幕多种分辨率设置;
- [Windows推屏]支持屏幕裁剪、窗口采集、屏幕/摄像头数据合成等多种模式推送;
- [移动端推屏]Android平台支持后台service推送摄像头或屏幕(推送屏幕需要5.0+版本);
- [移动端推屏]iOS平台支持后台推送屏幕(基于ReplayKit,需要iOS 10.0+版本);
- [事件回调]支持各种状态实时回调;
- [水印]Windows平台支持文字水印、png水印、实时遮挡,Android平台支持文字水印、png水印;
- [RTMP推送模式]支持RTMP推送 live|record模式设置(需服务器支持);
- [镜像]Android/iOS平台支持前置摄像头实时镜像功能;
- [前后摄像头实时切换]Android/iOS平台支持采集过程中,前后摄像头切换;
- [复杂网络处理]支持断网重连等各种网络环境自动适配;
- [动态码率]支持根据网络情况自动调整推流码率;
- [实时静音]支持推送过程中,实时静音/取消静音;
- [实时快照]支持推流过程中,实时快照;
- [纯音频推流]支持仅采集音频流并发起推流功能;
- [纯视频推流]支持特殊场景下的纯视频推流功能;
- [降噪]Windows/Android平台支持环境音、手机干扰等引起的噪音降噪处理、自动增益、VAD检测;
- [回音消除]android支持实时传递远端PCM数据,方便回音消除处理;
- [外部编码前视频数据对接]支持YUV数据对接;
- [外部编码前音频数据对接]支持PCM对接;
- [外部编码后视频数据对接]支持外部H.264数据对接;
- [外部编码后音频数据对接]外部AAC/PCMA/PCMU/SPEEX数据对接;
- [编码后数据输出]Android平台支持输出编码后的H264/AAC数据到上层,方便对接第三方平台(如GB28181)对接(接口说明和demo请点击以下链接);
- [扩展录像功能]完美支持和录像SDK组合使用,录像相关功能,可参见"8. Windows/Android/iOS录像SDK";
- [基础美颜]iOS平台自带基础美颜功能;
- [裁剪模式]Android/iOS平台支持特定分辨率摄像头裁剪模式设置;
- [服务器兼容]支持支持自建服务器(如Nginx、SRS)或CDN。
相关Demo:点击下载
相关资料参考:https://github.com/daniulive/SmarterStreaming/
关注公众号
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
Android开发 - 掌握ConstraintLayout(四)创建基本约束
上一篇我们介绍了编辑器的基本使用,本文我们介绍创建基本的约束。 "约束"表示View之间的位置关系。当我们在ConstraintLayout布局中创建View时,如果我们没有添加任何约束,虽然在设计视图我们可以拖动它们到任意位置,但是运行后都会在左上角的原点位置,同时代码中也会给出警告: 所以我们必须确保我们的View都被添加了适当的约束。我们常用的约束通常有两种,一种是相对父View的约束,一种是相对其它View的约束。 相对父布局的约束 创建相对布局的约束时比较简单,将对象方位的锚点拖动到对应方位的布局上即可。 这里我将这个按钮放到左上角,距父布局的左方和上方为50dp,在红色方框处可以调整具体的数值。 相对其它布局的约束 创建相对其它View的布局的形式就比较多样化了,结合相对父布局的约束,可以实现出非常复杂的界面。 当创建一个相对其它View的约束时,将锚点拖动到其它View上面的锚点即可。 创建父View约束时将锚点拖到父View边缘即可,创建与其它View约束时是将锚点拖到其它View的锚点上。 我们来举个应用的例子: 比如我们想要一个View相对另一个View居中显示,使...
-
下一篇
Android自定义View之文字居中
前言 本文讲文字的居中,不过在你阅读本文之前,强烈建议你读一下我的上一篇文章Android自定义View之DashBoard(仪表盘) ,因为上一篇的内容讲了Paint和Canvas等基础绘制的知识,你学会上一篇的内容再看现在的这篇会容易的多。看了文章题目,你会发现本文只讲一个点,就是文字居中,可能你会觉得就一个文字居中有必要单独拿一篇文章来讲吗?一开始我自己觉得没必要,后来发现有很多工作3、4年的Android开发者都没弄明白到底该怎么使文字居中,所以就有了这篇文章。关于文字居中,我保证你认真看了我的这篇文章,你一定能彻彻底底地明白如何去做。 文字居中 我们先来回忆一下绘制文字的方法:drawText(String text, float x, float y, Paint paint) 方法的参数很简单: text 是文字内容,x 和 y 是文字的坐标。但需要注意:这个坐标并不是文字的左上角,而是一个与左下角比较接近的位置。大概在这里: 坐标的位置 注意要特别强调一下y(也就是纵坐标)是 基线的位置,这时候你一定会问啥事基线,长什么样啊,接着看图 为什么会要用基线?这是因为每个字符...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Hadoop3单机部署,实现最简伪集群
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS关闭SELinux安全模块
- CentOS8编译安装MySQL8.0.19

微信收款码
支付宝收款码