• Unity下如何实现RTMP或RTSP播放端录像?


    好多开发者问我们,Unity环境下,除了RTSP或RTMP的播放,如果有录像诉求,怎么实现?实际上录像相对播放来说,更简单一些,因为不涉及到绘制,只要拉流下来数据,直接写mp4文件就好了。

    本文以大牛直播SDK的Windows平台为例,大概介绍下如何实现Unity环境下的录制,Linux、Android、iOS平台实现也类似,都是原生接口,然后对接下就好:

    开始录像

    因为涉及到可能同时录制多路的场景(考虑到磁盘读写IO,Windows平台一般不建议多录录制),录像的话,需要考虑的是,设置好文件录制规则,比如,是否录制纯音频或纯视频、单个录制文件大小、文件录制目录等,并设置录像回调事件:

    1. /*
    2. * SmartPlayerWinMono.cs
    3. * Author: daniusdk.com
    4. */
    5. private void StartRecorder(int sel)
    6. {
    7. Debug.Log("StartRecorder++, sel: " + sel);
    8. if (videoctrl[sel].is_recording_)
    9. {
    10. Debug.Log("StartRecorder, already started.. sel: " + sel);
    11. return;
    12. }
    13. if (!videoctrl[sel].is_playing_)
    14. {
    15. if (!OpenPlayerHandle(sel))
    16. {
    17. Debug.LogError("call OpenPlayerHandle failed..");
    18. return;
    19. }
    20. }
    21. bool is_rec_video = true;
    22. bool is_rec_audio = true;
    23. NTSmartPlayerSDK.NT_SP_SetRecorderVideo(videoctrl[sel].player_handle_, is_rec_video ? 1 : 0);
    24. NTSmartPlayerSDK.NT_SP_SetRecorderAudio(videoctrl[sel].player_handle_, is_rec_audio ? 1 : 0);
    25. String rec_dir = "D:\\Rec"; //录像目录可自行指定
    26. String rec_name_file_prefix_= "daniu" + sel.ToString();
    27. UInt32 max_file_size = 200 * 1024; // 单位是KByte, 默认200MB
    28. bool is_append_date = true;
    29. bool is_append_time = true;
    30. bool is_audio_transcode_aac = true;
    31. UInt32 ret = NTSmartPlayerSDK.NT_SP_SetRecorderDirectory(videoctrl[sel].player_handle_, rec_dir);
    32. if (NT.NTBaseCodeDefine.NT_ERC_OK != ret)
    33. {
    34. Debug.LogError("设置录像目录失败,请确保目录存在且是英文目录");
    35. return;
    36. }
    37. NTSmartPlayerSDK.NT_SP_SetRecorderFileMaxSize(videoctrl[sel].player_handle_, max_file_size);
    38. NT_SP_RecorderFileNameRuler rec_name_ruler = new NT_SP_RecorderFileNameRuler();
    39. rec_name_ruler.type_ = 0;
    40. rec_name_ruler.file_name_prefix_ = rec_name_file_prefix_;
    41. rec_name_ruler.append_date_ = is_append_date ? 1 : 0;
    42. rec_name_ruler.append_time_ = is_append_time ? 1 : 0;
    43. NTSmartPlayerSDK.NT_SP_SetRecorderFileNameRuler(videoctrl[sel].player_handle_, ref rec_name_ruler);
    44. NTSmartPlayerSDK.NT_SP_SetRecorderAudioTranscodeAAC(videoctrl[sel].player_handle_, is_audio_transcode_aac ? 1 : 0);
    45. videoctrl[sel].record_call_back_ = new SP_SDKRecorderCallBack(NT_SP_SDKRecorderCallBack);
    46. NTSmartPlayerSDK.NT_SP_SetRecorderCallBack(videoctrl[sel].player_handle_, IntPtr.Zero, videoctrl[sel].record_call_back_);
    47. videoctrl[sel].set_record_call_back_ = new VideoControl.SetRecordCallBack(RecordCallBack);
    48. if (NT.NTBaseCodeDefine.NT_ERC_OK != NTSmartPlayerSDK.NT_SP_StartRecorder(videoctrl[sel].player_handle_))
    49. {
    50. Debug.LogError("call NT_SP_StartRecorder failed..");
    51. return;
    52. }
    53. videoctrl[sel].is_recording_ = true;
    54. }

    其中OpenPlayerHandle()实现如下,通过调用Open()接口生成个player实例句柄,然后后续针对这个句柄操作即可,如果同一个实例句柄下需要播放,直接调用播放接口就好了。

    1. private bool OpenPlayerHandle(int sel)
    2. {
    3. if (videoctrl[sel].player_handle_ != IntPtr.Zero)
    4. return true;
    5. window_handle_ = IntPtr.Zero;
    6. if (videoctrl[sel].player_handle_ == IntPtr.Zero)
    7. {
    8. videoctrl[sel].player_handle_ = new IntPtr();
    9. UInt32 ret_open = NTSmartPlayerSDK.NT_SP_Open(out videoctrl[sel].player_handle_, window_handle_, 0, IntPtr.Zero);
    10. if (ret_open != 0)
    11. {
    12. videoctrl[sel].player_handle_ = IntPtr.Zero;
    13. Debug.LogError("call NT_SP_Open failed, sel: " + sel);
    14. return false;
    15. }
    16. }
    17. videoctrl[sel].event_call_back_ = new SP_SDKEventCallBack(NT_SP_SDKEventCallBack);
    18. NTSmartPlayerSDK.NT_SP_SetEventCallBack(videoctrl[sel].player_handle_, window_handle_, videoctrl[sel].event_call_back_);
    19. videoctrl[sel].sdk_event_call_back_ = new VideoControl.SetEventCallBack(SDKEventCallBack);
    20. if (IntPtr.Zero == videoctrl[sel].player_handle_)
    21. return false;
    22. /* ++ 播放前参数配置可加在此处 ++ */
    23. int play_buffer_time_ = 100;
    24. NTSmartPlayerSDK.NT_SP_SetBuffer(videoctrl[sel].player_handle_, play_buffer_time_); //设置buffer time
    25. int is_using_tcp = 1; //TCP模式
    26. NTSmartPlayerSDK.NT_SP_SetRTSPTcpMode(videoctrl[sel].player_handle_, is_using_tcp);
    27. int timeout = 10;
    28. NTSmartPlayerSDK.NT_SP_SetRtspTimeout(videoctrl[sel].player_handle_, timeout);
    29. int is_auto_switch_tcp_udp = 1;
    30. NTSmartPlayerSDK.NT_SP_SetRtspAutoSwitchTcpUdp(videoctrl[sel].player_handle_, is_auto_switch_tcp_udp);
    31. Boolean is_mute_ = false;
    32. NTSmartPlayerSDK.NT_SP_SetMute(videoctrl[sel].player_handle_, is_mute_ ? 1 : 0); //是否启动播放的时候静音
    33. int is_fast_startup = 1;
    34. NTSmartPlayerSDK.NT_SP_SetFastStartup(videoctrl[sel].player_handle_, is_fast_startup); //设置快速启动模式
    35. Boolean is_low_latency_ = false;
    36. NTSmartPlayerSDK.NT_SP_SetLowLatencyMode(videoctrl[sel].player_handle_, is_low_latency_ ? 1 : 0); //设置是否启用低延迟模式
    37. //设置旋转角度(设置0, 90, 180, 270度有效,其他值无效)
    38. int rotate_degrees = 0;
    39. NTSmartPlayerSDK.NT_SP_SetRotation(videoctrl[sel].player_handle_, rotate_degrees);
    40. int volume = 100;
    41. NTSmartPlayerSDK.NT_SP_SetAudioVolume(videoctrl[sel].player_handle_, volume); //设置播放音量, 范围是[0, 100], 0是静音,100是最大音量, 默认是100
    42. // 设置上传下载报速度
    43. int is_report = 0;
    44. int report_interval = 2;
    45. NTSmartPlayerSDK.NT_SP_SetReportDownloadSpeed(videoctrl[sel].player_handle_, is_report, report_interval);
    46. //设置播放URL
    47. NTSmartPlayerSDK.NT_SP_SetURL(videoctrl[sel].player_handle_, videoctrl[sel].playback_url_);
    48. /* -- 播放前参数配置可加在此处 -- */
    49. return true;
    50. }

    录像回调事件如下:

    1. public void RecordCallBack(UInt32 status, [MarshalAs(UnmanagedType.LPStr)] String file_name, int sel)
    2. {
    3. if (status == 1) //status 1:表示开始写一个新录像文件
    4. {
    5. Debug.Log("RecordCallBack, 开始一个新的录像文件, sel: " + sel + " status: " + status + ", filename: " + file_name);
    6. }
    7. else if (status == 2) //status 2:表示已经写好一个录像文件
    8. {
    9. Debug.Log("RecordCallBack, 已生成一个录像文件, sel: " + sel + " status: " + status + ", filename: " + file_name);
    10. }
    11. }

    停止录像

    1. private void StopRecorder(int sel)
    2. {
    3. Debug.Log("StopRecorder++, sel: " + sel);
    4. if (videoctrl[sel].player_handle_ == IntPtr.Zero)
    5. {
    6. return;
    7. }
    8. NTSmartPlayerSDK.NT_SP_StopRecorder(videoctrl[sel].player_handle_);
    9. videoctrl[sel].is_recording_ = false;
    10. if (!videoctrl[sel].is_playing_)
    11. {
    12. NTSmartPlayerSDK.NT_SP_Close(videoctrl[sel].player_handle_);
    13. videoctrl[sel].player_handle_ = IntPtr.Zero;
    14. }
    15. }

    以上是Unity平台RTMP或RTSP播放端录像相关接口设计和调用实例,感兴趣的开发者可以参考。

  • 相关阅读:
    二十六、【颜色调整】
    c# 实现定义一套中间SQL可以跨库执行的SQL语句
    Python Spider学习笔记(一):爬取B站视频基本信息
    Pytest框架实战二
    kubesphere
    【Python机器学习实战】----基于AdaBoost分类树模型、梯度提升分类树模型、Bagging分类树模型以及随机森林分类模型对空气质量等级进行预测
    C++多态
    高并发高可用之ElasticSearch
    springboot+zookeepr+dubbo的远程服务调用
    力扣之螺旋矩阵,一起旋转起来(都能看懂)
  • 原文地址:https://blog.csdn.net/renhui1112/article/details/132814624