好多开发者问我们,Unity环境下,除了RTSP或RTMP的播放,如果有录像诉求,怎么实现?实际上录像相对播放来说,更简单一些,因为不涉及到绘制,只要拉流下来数据,直接写mp4文件就好了。
本文以大牛直播SDK的Windows平台为例,大概介绍下如何实现Unity环境下的录制,Linux、Android、iOS平台实现也类似,都是原生接口,然后对接下就好:
开始录像
因为涉及到可能同时录制多路的场景(考虑到磁盘读写IO,Windows平台一般不建议多录录制),录像的话,需要考虑的是,设置好文件录制规则,比如,是否录制纯音频或纯视频、单个录制文件大小、文件录制目录等,并设置录像回调事件:
/** SmartPlayerWinMono.cs* Author: daniusdk.com*/privatevoidStartRecorder(intsel) { Debug.Log("StartRecorder++, sel: "+sel); if (videoctrl[sel].is_recording_) { Debug.Log("StartRecorder, already started.. sel: "+sel); return; } if (!videoctrl[sel].is_playing_) { if (!OpenPlayerHandle(sel)) { Debug.LogError("call OpenPlayerHandle failed.."); return; } } boolis_rec_video=true; boolis_rec_audio=true; NTSmartPlayerSDK.NT_SP_SetRecorderVideo(videoctrl[sel].player_handle_, is_rec_video?1 : 0); NTSmartPlayerSDK.NT_SP_SetRecorderAudio(videoctrl[sel].player_handle_, is_rec_audio?1 : 0); Stringrec_dir="D:\\Rec"; //录像目录可自行指定Stringrec_name_file_prefix_="daniu"+sel.ToString(); UInt32max_file_size=200*1024; // 单位是KByte, 默认200MBboolis_append_date=true; boolis_append_time=true; boolis_audio_transcode_aac=true; UInt32ret=NTSmartPlayerSDK.NT_SP_SetRecorderDirectory(videoctrl[sel].player_handle_, rec_dir); if (NT.NTBaseCodeDefine.NT_ERC_OK!=ret) { Debug.LogError("设置录像目录失败,请确保目录存在且是英文目录"); return; } NTSmartPlayerSDK.NT_SP_SetRecorderFileMaxSize(videoctrl[sel].player_handle_, max_file_size); NT_SP_RecorderFileNameRulerrec_name_ruler=newNT_SP_RecorderFileNameRuler(); rec_name_ruler.type_=0; rec_name_ruler.file_name_prefix_=rec_name_file_prefix_; rec_name_ruler.append_date_=is_append_date?1 : 0; rec_name_ruler.append_time_=is_append_time?1 : 0; NTSmartPlayerSDK.NT_SP_SetRecorderFileNameRuler(videoctrl[sel].player_handle_, refrec_name_ruler); NTSmartPlayerSDK.NT_SP_SetRecorderAudioTranscodeAAC(videoctrl[sel].player_handle_, is_audio_transcode_aac?1 : 0); videoctrl[sel].record_call_back_=newSP_SDKRecorderCallBack(NT_SP_SDKRecorderCallBack); NTSmartPlayerSDK.NT_SP_SetRecorderCallBack(videoctrl[sel].player_handle_, IntPtr.Zero, videoctrl[sel].record_call_back_); videoctrl[sel].set_record_call_back_=newVideoControl.SetRecordCallBack(RecordCallBack); if (NT.NTBaseCodeDefine.NT_ERC_OK!=NTSmartPlayerSDK.NT_SP_StartRecorder(videoctrl[sel].player_handle_)) { Debug.LogError("call NT_SP_StartRecorder failed.."); return; } videoctrl[sel].is_recording_=true; }
其中OpenPlayerHandle()实现如下,通过调用Open()接口生成个player实例句柄,然后后续针对这个句柄操作即可,如果同一个实例句柄下需要播放,直接调用播放接口就好了。
privateboolOpenPlayerHandle(intsel) { if (videoctrl[sel].player_handle_!=IntPtr.Zero) returntrue; window_handle_=IntPtr.Zero; if (videoctrl[sel].player_handle_==IntPtr.Zero) { videoctrl[sel].player_handle_=newIntPtr(); UInt32ret_open=NTSmartPlayerSDK.NT_SP_Open(outvideoctrl[sel].player_handle_, window_handle_, 0, IntPtr.Zero); if (ret_open!=0) { videoctrl[sel].player_handle_=IntPtr.Zero; Debug.LogError("call NT_SP_Open failed, sel: "+sel); returnfalse; } } videoctrl[sel].event_call_back_=newSP_SDKEventCallBack(NT_SP_SDKEventCallBack); NTSmartPlayerSDK.NT_SP_SetEventCallBack(videoctrl[sel].player_handle_, window_handle_, videoctrl[sel].event_call_back_); videoctrl[sel].sdk_event_call_back_=newVideoControl.SetEventCallBack(SDKEventCallBack); if (IntPtr.Zero==videoctrl[sel].player_handle_) returnfalse; /* ++ 播放前参数配置可加在此处 ++ */intplay_buffer_time_=100; NTSmartPlayerSDK.NT_SP_SetBuffer(videoctrl[sel].player_handle_, play_buffer_time_); //设置buffer timeintis_using_tcp=1; //TCP模式NTSmartPlayerSDK.NT_SP_SetRTSPTcpMode(videoctrl[sel].player_handle_, is_using_tcp); inttimeout=10; NTSmartPlayerSDK.NT_SP_SetRtspTimeout(videoctrl[sel].player_handle_, timeout); intis_auto_switch_tcp_udp=1; NTSmartPlayerSDK.NT_SP_SetRtspAutoSwitchTcpUdp(videoctrl[sel].player_handle_, is_auto_switch_tcp_udp); Booleanis_mute_=false; NTSmartPlayerSDK.NT_SP_SetMute(videoctrl[sel].player_handle_, is_mute_?1 : 0); //是否启动播放的时候静音intis_fast_startup=1; NTSmartPlayerSDK.NT_SP_SetFastStartup(videoctrl[sel].player_handle_, is_fast_startup); //设置快速启动模式Booleanis_low_latency_=false; NTSmartPlayerSDK.NT_SP_SetLowLatencyMode(videoctrl[sel].player_handle_, is_low_latency_?1 : 0); //设置是否启用低延迟模式//设置旋转角度(设置0, 90, 180, 270度有效,其他值无效)introtate_degrees=0; NTSmartPlayerSDK.NT_SP_SetRotation(videoctrl[sel].player_handle_, rotate_degrees); intvolume=100; NTSmartPlayerSDK.NT_SP_SetAudioVolume(videoctrl[sel].player_handle_, volume); //设置播放音量, 范围是[0, 100], 0是静音,100是最大音量, 默认是100// 设置上传下载报速度intis_report=0; intreport_interval=2; NTSmartPlayerSDK.NT_SP_SetReportDownloadSpeed(videoctrl[sel].player_handle_, is_report, report_interval); //设置播放URLNTSmartPlayerSDK.NT_SP_SetURL(videoctrl[sel].player_handle_, videoctrl[sel].playback_url_); /* -- 播放前参数配置可加在此处 -- */returntrue; }
录像回调事件如下:
publicvoidRecordCallBack(UInt32status, [MarshalAs(UnmanagedType.LPStr)] Stringfile_name, intsel) { if (status==1) //status 1:表示开始写一个新录像文件 { Debug.Log("RecordCallBack, 开始一个新的录像文件, sel: "+sel+" status: "+status+", filename: "+file_name); } elseif (status==2) //status 2:表示已经写好一个录像文件 { Debug.Log("RecordCallBack, 已生成一个录像文件, sel: "+sel+" status: "+status+", filename: "+file_name); } }
停止录像
privatevoidStopRecorder(intsel) { Debug.Log("StopRecorder++, sel: "+sel); if (videoctrl[sel].player_handle_==IntPtr.Zero) { return; } NTSmartPlayerSDK.NT_SP_StopRecorder(videoctrl[sel].player_handle_); videoctrl[sel].is_recording_=false; if (!videoctrl[sel].is_playing_) { NTSmartPlayerSDK.NT_SP_Close(videoctrl[sel].player_handle_); videoctrl[sel].player_handle_=IntPtr.Zero; } }
以上是Unity平台RTMP或RTSP播放端录像相关接口设计和调用实例,感兴趣的开发者可以参考。