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

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

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

开始录像

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

ini 复制代码
/*
 * 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;
}

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

ini 复制代码
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;
}

录像回调事件如下:

arduino 复制代码
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);
  }
}

停止录像

ini 复制代码
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;
  }
}

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

相关推荐
哔哩哔哩技术6 小时前
B站第三代转码体系下流式转码测试实践
音视频开发
音视频牛哥1 天前
从「行走」到「思考」:机器人进化之路与感知—决策链路的工程化实践
机器学习·机器人·音视频开发
chenchao_shenzhen4 天前
RK3568嵌入式音视频硬件编解码4K 60帧 rkmpp FFmpeg7.1 音视频开发
ffmpeg·音视频·rk3588·音视频开发·嵌入式开发·瑞芯微rk3568·硬件编解码
码流怪侠6 天前
Google SoundStream音频编解码器技术解析
深度学习·音视频开发
字节跳动视频云技术团队7 天前
基于 DiT 大模型与字体级分割的视频字幕无痕擦除方案,助力短剧出海
aigc·音视频开发·视频编码
音视频牛哥8 天前
跨平台轻量级RTSP服务模块技术详解与内网低延迟直播实践
音视频开发·视频编码·直播
aqi009 天前
FFmpeg开发笔记(八十)使用百变魔音AiSound实现变声特效
android·ffmpeg·音视频·直播·流媒体
aqi0010 天前
FFmpeg开发笔记(七十九)专注于视频弹幕功能的国产弹弹播放器
android·ffmpeg·音视频·直播·流媒体
音视频牛哥13 天前
SmartMediaKit 模块化音视频框架实战指南:场景链路 + 能力矩阵全解析
音视频开发·视频编码·直播