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/
相關文章
- Android 音視訊開發 視訊編碼,音訊編碼格式Android音訊
- Android 音視訊 - MediaCodec 編解碼音視訊Android
- Android音視訊(四)MediaCodec編解碼AACAndroid
- Android 音視訊錄製硬編碼實現Android
- AVAssetWriter視訊資料編碼
- 各種音訊視訊編碼方法音訊
- 音訊後設資料編輯器:Tagr for Mac音訊Mac
- 音訊後設資料編輯器Metadatas for Mac音訊Mac
- Metadatics for Mac音訊後設資料編輯工具Mac音訊
- Android音視訊之MediaPlayer音視訊播放Android
- Android音視訊之MediaRecorder音視訊錄製Android
- 音視訊開發-全網最全常用音視訊編碼和格式彙總
- 音視訊入門之音訊採集、編碼、播放音訊
- FFMPEG視音訊編解碼學習(1)音訊
- Activity生命週期回撥是如何被回撥的?
- android音視訊指南-管理音訊焦點Android音訊
- 如何做好 Android 端音視訊測試?Android
- 在.NET中使用Speex -- 音訊資料編解碼 (轉)音訊
- android回撥函式Android函式
- Android 回撥方法的實現Android
- 也談 Android 中的回撥Android
- 音視訊學習之 - H264編碼
- 【秒懂音視訊開發】14_AAC編碼
- 各種音視訊編解碼學習詳解
- Android音視訊(一) Camera2 API採集資料AndroidAPI
- 【詳細、開箱即用】.NET企業微信回撥配置(資料回撥URL和指令回撥URL驗證)
- android音視訊指南-處理音訊輸出的變化Android音訊
- Camera2錄製視訊(一):音訊的錄製及編碼音訊
- Android視訊編碼和直播推流教程Android
- Android音訊視覺化操作Android音訊視覺化
- android音視訊指南-MediaPlayer概述Android
- android音視訊指南-MediaRecorder概述Android
- 音訊編解碼標準音訊
- FFmpeg音視訊編譯配置選項編譯
- 【秒懂音視訊開發】23_H.264編碼
- 轉載:iOS音視訊實時採集硬體編碼iOS
- 3C視訊音訊內容資訊編碼引數檢測MediaInfo音訊AI
- Android之無法回撥onActivityResultAndroid