有开发者提到,在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;@Overridepublic 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_;}@Overridepublic 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;@Overridepublic 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组合使用,亦可单独使用。

Android如何回调编码后的音视频数据相关推荐

  1. android音视频工程师,音视频学习 (十三) Android 中通过 FFmpeg 命令对音视频编辑处理(已开源)...

    ## 音视频学习 (十三) Android 中通过 FFmpeg 命令对音视频编辑处理(已开源) ## 视音频编辑器 ## 前言 有时候我们想对音视频进行加工处理,比如视频编辑.添加字幕.裁剪等功能处 ...

  2. 视频直播源码在Android端实现1对1音视频实时通话

    我们要使用 WebRTC 进行音视频互动时需要申请访问硬件的权限,至少要申请以下三种权限 Camera 权限 Record Audio 权限 Intenet 权限 在Android中,申请权限分为静态 ...

  3. vlc-android对于通过Live555接收到音视频数据包后的处理分析

    转载地址:https://blog.csdn.net/c_m_deng/article/details/8487456 通过ndk-gdb跟踪调试vlc-android来分析从连接到RTSP服务器并接 ...

  4. 1小时学会:最简单的iOS直播推流(三)使用系统接口捕获音视频数据

    最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!! 源 ...

  5. 音视频方案,音视频扩展内容- 音视频数据解析,码流分析及质量评价(笔记)3

    -- 音视频编解码流程如下图: -- 关于音频各种参数: freq:音频数据的采样率.常用的有48000,44100等. format:音频数据的格式.举例几种格式: AUDIO_U16SYS:Uns ...

  6. 基于iOS的网络音视频实时传输系统(二)- 捕获音视频数据

    下载 GitHub: client 端:https://github.com/AmoAmoAmo/Smart_Device_Client server端:https://github.com/AmoA ...

  7. 音视频7——安卓软编音视频数据推送到rtmp服务器

    音视频开发路线: Android 音视频开发入门指南_Jhuster的专栏的技术博客_51CTO博客_android 音视频开发入门 demo地址: videoPath/Demo8Activity.j ...

  8. 【音视频数据数据处理 12】【H.264篇】解析H.264原始码流中的I帧 / P帧 / B帧数据(暂未解决,本文先放着,来日更新)

    [音视频数据数据处理 12][H.264篇]解析H.264原始码流中的I帧 / P帧 / B帧数据 一.如何判断是 I帧 / P帧 / B帧 1.1 slice_type 1.2 slice_head ...

  9. 【音视频数据数据处理 14】【FLV篇】解析FLV视频码流,并分离FLV中的视频及MP3音频文件

    [音视频数据数据处理 14][FLV篇]解析FLV视频码流,并分离FLV中的视频及MP3音频文件 一.FLV封装原理 1.1 Tag Data 1.1.1 Audio Tag Data结构(音频Tag ...

最新文章

  1. Z 字形变换 C++实现 java实现 leetcode系列(六)
  2. MyEclipse Web 项目的图标和右键New菜单
  3. python重复执行_关于计时器:在Python中每x秒重复执行一次函数的最佳方法是什么?...
  4. 腾达fh365虚拟服务器,腾达(Tenda)FH365路由器怎么设置?
  5. SAP ABAP Netweaver Note download debug
  6. 干货|MIT线性代数课程精细笔记[第二课]
  7. c语言 函数指针开销,函数指针是否使程序变慢?
  8. 过河卒(洛谷P1002题解,Java语言描述)
  9. JEECG_3.7开发环境搭建与代码生成器入门级教程-张代浩-专题视频课程
  10. 收录网zblog主题导航模板
  11. Go语言之父详述切片与数组的不同
  12. gitlab贡献率_如何为GitLab做贡献
  13. matlab 上穿,Matlab混入模式(Mixin)
  14. 手把手教你搭建Pytest+Allure2.X环境详细教程 - 01
  15. oracle 二进制与运算,Oracle怎么操作进行二进制的比对
  16. 海南大学计算机科学与技术知乎,海南大学计算机科学与技术怎么样
  17. 交换二叉树的左右子树——非递归方式
  18. Python-爬虫-requests库用语post登录
  19. Word或WPS中批量设置表格样式的宏
  20. 日本要把123万吨核污水排入太平洋,核威胁距离我们有多远?

热门文章

  1. Spring+SpringMVC+Mybatis 多数据源整合
  2. type c pin定义_在C中定义宏以设置和清除PIN的位
  3. Java LinkedList公共对象pollLast()方法(带示例)
  4. python中的替换函数_python:替换模块类中的函数
  5. python 发送邮件connect none_使用python向IP地址发送邮件
  6. oracle清理告警日志,Oracle 跟踪/告警/监听日志的清理脚本
  7. vue判断组件是否显示_vue组件中watch props根据v-if动态判断并挂载DOM的问题
  8. 解压android img文件怎么打开,解压压缩android img文件
  9. Java LinkedList addFirst()方法与示例
  10. c#象棋程序_C ++程序确定象棋方块的颜色