How to implement RTMP or RTSP player recording under Unity?

Many developers ask us, in the Unity environment, in addition to RTSP or RTMP playback, if there is a video recording requirement, how to achieve it? In fact, video recording is simpler than playback because it does not involve drawing. You only need to stream the data and write it directly to the mp4 file.

This article takes the Windows platform of Daniu Live SDK as an example to briefly introduce how to implement recording in the Unity environment. The implementation on Linux, Android, and iOS platforms is also similar. They are all native interfaces, and then just connect them:

Start recording

Because it involves scenarios where multiple channels may be recorded at the same time (taking into account disk read and write IO, Windows platforms generally do not recommend multiple recordings). When recording, you need to consider setting the file recording rules, such as whether to record pure audio or pure audio. Video, single recording file size, file recording directory, etc., and set the recording callback event:

/*
 * SmartPlayerWinMono.cs
 * Author: daniusdk.com
 */
private void StartRecorder(int sel)
{
  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;
    }
  }

  bool is_rec_video = true;
  bool is_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);

  String rec_dir = "D:\\Rec";     //录像目录可自行指定
  String rec_name_file_prefix_= "daniu" + sel.ToString();
  UInt32 max_file_size = 200 * 1024; // 单位是KByte, 默认200MB
  bool is_append_date = true;
  bool is_append_time = true;
  bool is_audio_transcode_aac = true;

  UInt32 ret = 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_RecorderFileNameRuler rec_name_ruler = new NT_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_, ref rec_name_ruler);

  NTSmartPlayerSDK.NT_SP_SetRecorderAudioTranscodeAAC(videoctrl[sel].player_handle_, is_audio_transcode_aac ? 1 : 0);

  videoctrl[sel].record_call_back_ = new SP_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_ = new VideoControl.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;
}

The OpenPlayerHandle() implementation is as follows. Generate a player instance handle by calling the Open() interface, and then operate on this handle later. If you need to play under the same instance handle, just call the playback interface directly.

private bool OpenPlayerHandle(int sel)
{
  if (videoctrl[sel].player_handle_ != IntPtr.Zero)
    return true;

  window_handle_ = IntPtr.Zero;

  if (videoctrl[sel].player_handle_ == IntPtr.Zero)
  {
    videoctrl[sel].player_handle_ = new IntPtr();
    UInt32 ret_open = NTSmartPlayerSDK.NT_SP_Open(out videoctrl[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);
      return false;
    }
  }

  videoctrl[sel].event_call_back_ = new SP_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_ = new VideoControl.SetEventCallBack(SDKEventCallBack);

  if (IntPtr.Zero == videoctrl[sel].player_handle_)
    return false;

  /* ++ 播放前参数配置可加在此处 ++ */

  int play_buffer_time_ = 100;
  NTSmartPlayerSDK.NT_SP_SetBuffer(videoctrl[sel].player_handle_, play_buffer_time_);                 //设置buffer time

  int is_using_tcp = 1;        //TCP模式
  NTSmartPlayerSDK.NT_SP_SetRTSPTcpMode(videoctrl[sel].player_handle_, is_using_tcp);

  int timeout = 10;
  NTSmartPlayerSDK.NT_SP_SetRtspTimeout(videoctrl[sel].player_handle_, timeout);

  int is_auto_switch_tcp_udp = 1;
  NTSmartPlayerSDK.NT_SP_SetRtspAutoSwitchTcpUdp(videoctrl[sel].player_handle_, is_auto_switch_tcp_udp);

  Boolean is_mute_ = false;
  NTSmartPlayerSDK.NT_SP_SetMute(videoctrl[sel].player_handle_, is_mute_ ? 1 : 0);                    //是否启动播放的时候静音

  int is_fast_startup = 1;
  NTSmartPlayerSDK.NT_SP_SetFastStartup(videoctrl[sel].player_handle_, is_fast_startup);              //设置快速启动模式

  Boolean is_low_latency_ = false;
  NTSmartPlayerSDK.NT_SP_SetLowLatencyMode(videoctrl[sel].player_handle_, is_low_latency_ ? 1 : 0);    //设置是否启用低延迟模式

  //设置旋转角度(设置0, 90, 180, 270度有效,其他值无效)
  int rotate_degrees = 0;
  NTSmartPlayerSDK.NT_SP_SetRotation(videoctrl[sel].player_handle_, rotate_degrees);

  int volume = 100;
  NTSmartPlayerSDK.NT_SP_SetAudioVolume(videoctrl[sel].player_handle_, volume);	//设置播放音量, 范围是[0, 100], 0是静音,100是最大音量, 默认是100

  // 设置上传下载报速度
  int is_report = 0;
  int report_interval = 2;
  NTSmartPlayerSDK.NT_SP_SetReportDownloadSpeed(videoctrl[sel].player_handle_, is_report, report_interval);

  //设置播放URL
  NTSmartPlayerSDK.NT_SP_SetURL(videoctrl[sel].player_handle_, videoctrl[sel].playback_url_);
  /* -- 播放前参数配置可加在此处 -- */

  return true;
}

The recording callback events are as follows:

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

Stop recording

private void StopRecorder(int sel)
{
  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;
  }
}

The above are the design and calling examples of the recording-related interfaces of the RTMP or RTSP playback end of the Unity platform. Interested developers can refer to them.

Guess you like

Origin blog.csdn.net/renhui1112/article/details/132814624