Android平台RTSP/RTMP推送端回調編碼後的音影片數據

  • 2019 年 10 月 4 日
  • 筆記

有開發者提到,在RTMP/RTSP推送端的基礎上,希望能回調編碼後的音影片數據,便於開發者對接第三方系統,如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組合使用,亦可單獨使用。