当前位置:   article > 正文

Android平台如何实现多路低延迟RTSP|RTMP播放?_android 播放rtsp

android 播放rtsp

技术背景

实际上,我们在2015年做Android平台RTSP、RTMP播放模块的时候,第一版就支持了多实例播放,因为SDK设计比较灵活,做个简单的player实例封装即可实现多实例播放(Android Unity的就有多路demo),所以官方一直没有正式demo,本次也是有个开发者提到,希望测试下我们多路播放的效果,自己又不想做封装,索性给做个版本。

技术实现

废话不多说,先上图:

我们针对的功能展示,主要是播放和录像这块,先说播放:

  1. /*
  2. * SmartPlayer.java
  3. * Author: https://daniusdk.com
  4. * Created by DaniuLive on 2015/09/26.
  5. */
  6. class ButtonPlayback1Listener implements View.OnClickListener {
  7. public void onClick(View v) {
  8. if (stream_player_1_.is_playing()) {
  9. Log.i(TAG, "Stop player1..");
  10. boolean iRet = stream_player_1_.StopPlayer();
  11. if (!iRet) {
  12. Log.e(TAG, "Call StopPlayer failed..");
  13. return;
  14. }
  15. stream_player_1_.try_release();
  16. btn_playback1.setText("开始播放1");
  17. SetViewVisibility(surface_view_1_);
  18. } else {
  19. Log.i(TAG, "Start playback stream1++");
  20. int play_buffer = 0;
  21. int is_using_tcp = 0;
  22. if(!stream_player_1_.OpenPlayerHandle(playback_url_1_, play_buffer, is_using_tcp))
  23. return;
  24. stream_player_1_.SetView(surface_view_1_);
  25. boolean is_mute = false;
  26. boolean iPlaybackRet = stream_player_1_.StartPlayer(isHardwareDecoder, is_enable_hardware_render_mode, is_mute);
  27. if (!iPlaybackRet) {
  28. Log.e(TAG, "Call StartPlayer failed..");
  29. return;
  30. }
  31. btn_playback1.setText("停止播放1");
  32. }
  33. }
  34. }

对应的OpenPlayerHandle()实现如下:

  1. /*
  2. * LibPlayerWrapper.java.java
  3. * Author: https://daniusdk.com
  4. */
  5. public boolean OpenPlayerHandle(String playback_url, int play_buffer, int is_using_tcp) {
  6. if (check_native_handle())
  7. return true;
  8. if(!isValidRtspOrRtmpUrl(playback_url))
  9. return false;
  10. long handle = lib_player_.SmartPlayerOpen(application_context());
  11. if (0==handle) {
  12. Log.e(TAG, "sdk open failed!");
  13. return false;
  14. }
  15. lib_player_.SetSmartPlayerEventCallbackV2(handle, new EventHandleV2());
  16. lib_player_.SmartPlayerSetBuffer(handle, play_buffer);
  17. // set report download speed(默认2秒一次回调 用户可自行调整report间隔)
  18. lib_player_.SmartPlayerSetReportDownloadSpeed(handle, 1, 4);
  19. boolean isFastStartup = true;
  20. lib_player_.SmartPlayerSetFastStartup(handle, isFastStartup ? 1 : 0);
  21. //设置RTSP超时时间
  22. int rtsp_timeout = 10;
  23. lib_player_.SmartPlayerSetRTSPTimeout(handle, rtsp_timeout);
  24. //设置RTSP TCP/UDP模式自动切换
  25. int is_auto_switch_tcp_udp = 1;
  26. lib_player_.SmartPlayerSetRTSPAutoSwitchTcpUdp(handle, is_auto_switch_tcp_udp);
  27. lib_player_.SmartPlayerSaveImageFlag(handle, 1);
  28. // It only used when playback RTSP stream..
  29. lib_player_.SmartPlayerSetRTSPTcpMode(handle, is_using_tcp);
  30. lib_player_.DisableEnhancedRTMP(handle, 0);
  31. lib_player_.SmartPlayerSetUrl(handle, playback_url);
  32. set(handle);
  33. return true;
  34. }

对应的开始播放、停止播放设计:

  1. /*
  2. * LibPlayerWrapper.java
  3. * Author: https://daniusdk.com
  4. */
  5. public boolean StartPlayer(boolean is_hardware_decoder, boolean is_enable_hardware_render_mode, boolean is_mute) {
  6. if (is_playing()) {
  7. Log.e(TAG, "already playing, native_handle:" + get());
  8. return false;
  9. }
  10. SetPlayerParam(is_hardware_decoder, is_enable_hardware_render_mode, is_mute);
  11. int ret = lib_player_.SmartPlayerStartPlay(get());
  12. if (ret != OK) {
  13. Log.e(TAG, "call StartPlay failed, native_handle:" + get() + ", ret:" + ret);
  14. return false;
  15. }
  16. write_lock_.lock();
  17. try {
  18. this.is_playing_ = true;
  19. } finally {
  20. write_lock_.unlock();
  21. }
  22. Log.i(TAG, "call StartPlayer OK, native_handle:" + get());
  23. return true;
  24. }
  25. public boolean StopPlayer() {
  26. if (!check_native_handle())
  27. return false;
  28. if (!is_playing()) {
  29. Log.w(TAG, "it's not playing, native_handle:" + get());
  30. return false;
  31. }
  32. boolean is_need_call = false;
  33. write_lock_.lock();
  34. try {
  35. if (this.is_playing_) {
  36. this.is_playing_ = false;
  37. is_need_call = true;
  38. }
  39. } finally {
  40. write_lock_.unlock();
  41. }
  42. if (is_need_call)
  43. lib_player_.SmartPlayerStopPlay(get());
  44. return true;
  45. }

录像设计:

  1. /*
  2. * SmartPlayer.java
  3. * Author: https://daniusdk.com
  4. */
  5. class ButtonRecorder1Listener implements View.OnClickListener {
  6. public void onClick(View v) {
  7. if (stream_player_1_.is_recording()) {
  8. Log.i(TAG, "Stop recorder1..");
  9. boolean iRet = stream_player_1_.StopRecorder();
  10. if (!iRet) {
  11. Log.e(TAG, "Call StopRecorder failed..");
  12. return;
  13. }
  14. stream_player_1_.try_release();
  15. btn_recorder1.setText("开始录像1");
  16. } else {
  17. Log.i(TAG, "Start recorder stream1++");
  18. int play_buffer = 0;
  19. int is_using_tcp = 0;
  20. if(!stream_player_1_.OpenPlayerHandle(playback_url_1_, play_buffer, is_using_tcp))
  21. return;
  22. stream_player_1_.ConfigRecorderParam(recDir, 400, 1, 1, 1);
  23. boolean iRecRet = stream_player_1_.StartRecorder();
  24. if (!iRecRet) {
  25. Log.e(TAG, "Call StartRecorder failed..");
  26. return;
  27. }
  28. btn_recorder1.setText("停止录像1");
  29. }
  30. }
  31. }

录像参数配置选项:

  1. /*
  2. * LibPlayerWrapper.java
  3. * Author: https://daniusdk.com
  4. */
  5. public boolean ConfigRecorderParam(String rec_dir, int file_max_size, int is_transcode_aac,
  6. int is_record_video, int is_record_audio) {
  7. if(!check_native_handle())
  8. return false;
  9. if (null == rec_dir || rec_dir.isEmpty())
  10. return false;
  11. int ret = lib_player_.SmartPlayerCreateFileDirectory(rec_dir);
  12. if (ret != 0) {
  13. Log.e(TAG, "Create record dir failed, path:" + rec_dir);
  14. return false;
  15. }
  16. if (lib_player_.SmartPlayerSetRecorderDirectory(get(), rec_dir) != 0) {
  17. Log.e(TAG, "Set record dir failed , path:" + rec_dir);
  18. return false;
  19. }
  20. if (lib_player_.SmartPlayerSetRecorderFileMaxSize(get(),file_max_size) != 0) {
  21. Log.e(TAG, "SmartPlayerSetRecorderFileMaxSize failed.");
  22. return false;
  23. }
  24. lib_player_.SmartPlayerSetRecorderAudioTranscodeAAC(get(), is_transcode_aac);
  25. // 更细粒度控制录像的, 一般情况无需调用
  26. lib_player_.SmartPlayerSetRecorderVideo(get(), is_record_video);
  27. lib_player_.SmartPlayerSetRecorderAudio(get(), is_record_audio);
  28. return true;
  29. }

开始录像、结束录像:

  1. /*
  2. * LibPlayerWrapper.java
  3. * Author: https://daniusdk.com
  4. */
  5. public boolean StartRecorder() {
  6. if (is_recording()) {
  7. Log.e(TAG, "already recording, native_handle:" + get());
  8. return false;
  9. }
  10. int ret = lib_player_.SmartPlayerStartRecorder(get());
  11. if (ret != OK) {
  12. Log.e(TAG, "call SmartPlayerStartRecorder failed, native_handle:" + get() + ", ret:" + ret);
  13. return false;
  14. }
  15. write_lock_.lock();
  16. try {
  17. this.is_recording_ = true;
  18. } finally {
  19. write_lock_.unlock();
  20. }
  21. Log.i(TAG, "call SmartPlayerStartRecorder OK, native_handle:" + get());
  22. return true;
  23. }
  24. public boolean StopRecorder() {
  25. if (!check_native_handle())
  26. return false;
  27. if (!is_recording()) {
  28. Log.w(TAG, "it's not recording, native_handle:" + get());
  29. return false;
  30. }
  31. boolean is_need_call = false;
  32. write_lock_.lock();
  33. try {
  34. if (this.is_recording_) {
  35. this.is_recording_ = false;
  36. is_need_call = true;
  37. }
  38. } finally {
  39. write_lock_.unlock();
  40. }
  41. if (is_need_call)
  42. lib_player_.SmartPlayerStopRecorder(get());
  43. return true;
  44. }

总结

说了这么多,以RTSP播放为例,大概说下实现的功能:

  • [支持播放协议]高稳定、超低延迟、业内首屈一指的RTSP直播播放器SDK;
  •  [多实例播放]支持多实例播放;
  •  [事件回调]支持网络状态、buffer状态等回调;
  •  [视频格式]支持H.265、H.264,此外,还支持RTSP MJPEG播放;
  •  [音频格式]支持AAC/PCMA/PCMU;
  •  [H.264/H.265软解码]支持H.264/H.265软解;
  •  [H.264硬解码]Windows/Android/iOS支持特定机型H.264硬解;
  •  [H.265硬解]Windows/Android/iOS支持特定机型H.265硬解;
  •  [H.264/H.265硬解码]Android支持设置Surface模式硬解和普通模式硬解码;
  •  [RTSP模式设置]支持RTSP TCP/UDP模式设置;
  •  [RTSP TCP/UDP自动切换]支持RTSP TCP、UDP模式自动切换;
  •  [RTSP超时设置]支持RTSP超时时间设置,单位:秒;
  •  [RTSP 401认证处理]支持上报RTSP 401事件,如URL携带鉴权信息,会自动处理;
  •  [缓冲时间设置]支持buffer time设置;
  •  [首屏秒开]支持首屏秒开模式;
  •  [复杂网络处理]支持断网重连等各种网络环境自动适配;
  •  [快速切换URL]支持播放过程中,快速切换其他URL,内容切换更快;
  •  [音视频多种render机制]Android平台,视频:surfaceview/OpenGL ES,音频:AudioTrack/OpenSL ES;
  •  [实时静音]支持播放过程中,实时静音/取消静音;
  •  [实时音量调节]支持播放过程中实时调节音量;
  •  [实时快照]支持播放过程中截取当前播放画面;
  •  [只播关键帧]Windows平台支持实时设置是否只播放关键帧;
  •  [渲染角度]支持0°,90°,180°和270°四个视频画面渲染角度设置;
  •  [渲染镜像]支持水平反转、垂直反转模式设置;
  •  [等比例缩放]支持图像等比例缩放绘制(Android设置surface模式硬解模式不支持);
  •  [实时下载速度更新]支持当前下载速度实时回调(支持设置回调时间间隔);
  •  [解码前视频数据回调]支持H.264/H.265数据回调;
  •  [解码后视频数据回调]支持解码后YUV/RGB数据回调;
  •  [解码前音频数据回调]支持AAC/PCMA/PCMU数据回调;
  •  [音视频自适应]支持播放过程中,音视频信息改变后自适应;
  •  [扩展录像功能]完美支持和录像SDK组合使用。

上面只是简单的播放、录像的演示,除此之外,大牛直播SDK的RTSP、RTMP播放器海康实现播放缓冲设置、软硬解码设置、实时快照、实时音量调节、实时解码后数据回调等。毫秒级延迟,完全满足对延迟、稳定性要求苛刻的场景下。感兴趣的开发者,可以单独和我沟通。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/852522
推荐阅读
相关标签
  

闽ICP备14008679号