技術共有

VR ヘッドセットはどのようにして 8K RTSP|RTMP ストリームを低遅延で再生しますか?

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

技術的背景

私たちが Unity プラットフォーム用の RTSP および RTMP プレーヤーを作成していたとき、一部の企業はパノラマ 8K RTSP|RTMP ライブ ストリームと 8K データをヘッドセットで再生することを望んで、そのような技術要件を提示し、ヘッドセットとプレーヤーに新しいアイデアを提案しました。要件については、VR ヘッドマウント デバイスが 8K RTSP|RTMP ストリーミング データを再生する方法をいくつかの側面から説明します。

1. プレイヤーのサポート

  1. 互換性 : まず、RTSP|RTMP プレーヤーは 8K 解像度のビデオ ストリーミングをサポートする必要があります。これは、プレーヤーが 8K ビデオをデコードし、8K 解像度をサポートするディスプレイ デバイスで再生できる必要があることを意味します。言うまでもなく、これはすでにサポートされています。
  2. デコード能力 : プレーヤーには、8K ビデオ ストリーム内の大量のデータを処理する強力なデコード機能が必要です。これには通常、プレーヤーが効率的なデコード アルゴリズムを使用し、ハードウェア アクセラレーション機能 (GPU アクセラレーションなど) を最大限に活用する必要があり、そのためにはヘッドセットが 8K ハード デコードをサポートする必要があります。

2. ネットワーク要件

  1. 帯域幅 : 8K ビデオ ストリーミングでは、リアルタイム伝送をサポートするために非常に高いネットワーク帯域幅が必要です。再生中の遅延、遅延、バッファリングなどの問題を回避するために、ネットワーク帯域幅が十分に大きいことを確認してください。イントラネット環境の場合は、基本的に帯域幅の問題を心配する必要はありません。
  2. 安定性 : ネットワーク接続の安定性も非常に重要です。ネットワーク接続が不安定であると、ビデオ ストリーミングが中断されたり、品質が低下したりする可能性があります。

3. ハードウェア要件

  1. プロセッサとメモリ: VR ヘッドセットは 8K ビデオ ストリームを再生するため、VR ヘッドセットのパフォーマンスに非常に高い要件が課されます。たとえば、quest3 が適しています。

4. 再生手順

  1. RTSPプレーヤーを選択します: 私たちのアプローチは、Daniu Live SDK のネイティブ RTSP|RTMP プレーヤーをハード デコード モードで使用して、デコードされた YUV または RGB データを統一することです。8K RTSP|RTMP ストリームのため、データ量が増加することに注意してください。非常に大きいデータ、特にデコードされたデータの場合、条件が許せばコピーを最小限に抑える必要があります。

技術的な実現

この記事では、Daniu Live SDK の Android プラットフォーム Unity3D RTSP|RTMP 再生モジュールを例に挙げます。

プレイを開始します:

  1. /*
  2. * SmartPlayerAndroidMono.cs
  3. * Author: daniusdk.com
  4. * QQ:89030985
  5. */
  6. public void Play()
  7. {
  8. if (is_running)
  9. {
  10. Debug.Log("已经在播放。。");
  11. return;
  12. }
  13. //获取输入框的url
  14. string url = input_url_.text.Trim();
  15. if (!url.StartsWith("rtmp://") && !url.StartsWith("rtsp://"))
  16. {
  17. videoUrl = "rtsp://admin:[email protected]:554/h264/ch1/main/av_stream";
  18. }
  19. else
  20. {
  21. videoUrl = url;
  22. }
  23. OpenPlayer();
  24. if ( player_handle_ == 0 )
  25. return;
  26. NT_U3D_Set_Game_Object(player_handle_, game_object_);
  27. /* ++ 播放前参数配置可加在此处 ++ */
  28. int is_using_tcp = 0; //TCP/UDP模式设置
  29. NT_U3D_SetRTSPTcpMode(player_handle_, is_using_tcp);
  30. int is_report = 0;
  31. int report_interval = 1;
  32. NT_U3D_SetReportDownloadSpeed(player_handle_, is_report, report_interval); //下载速度回调
  33. NT_U3D_SetBuffer(player_handle_, play_buffer_time_); //设置buffer time
  34. NT_U3D_SetPlayerLowLatencyMode(player_handle_, is_low_latency_ ? 1 : 0); //设置是否启用低延迟模式
  35. NT_U3D_SetMute(player_handle_, is_mute_ ? 1 : 0); //是否启动播放的时候静音
  36. NT_U3D_SetAudioVolume(player_handle_, cur_audio_volume_); //设置播放音量
  37. NT_U3D_SetVideoDecoderMode(player_handle_, is_hw_decode_ ? 1 : 0); //设置H.264软硬解模式
  38. NT_U3D_SetVideoHevcDecoderMode(player_handle_, is_hw_decode_ ? 1 : 0); //设置H.265软硬解模式
  39. int is_output = 1;
  40. int disable_use_image_planes = 0;
  41. bool is_supports_texture_format = SystemInfo.SupportsTextureFormat(TextureFormat.RG16);
  42. Debug.Log("is_supports_texture_format: " + is_supports_texture_format);
  43. int is_supported_multiple_format = is_supports_texture_format? 1:0;
  44. int max_images = 3;
  45. int buffer_pool_max_size = 0;
  46. NT_U3D_SetImageReaderOutput(player_handle_, is_output, disable_use_image_planes, is_supported_multiple_format, max_images, buffer_pool_max_size); //硬解码image reader
  47. int is_fast_startup = 1;
  48. NT_U3D_SetFastStartup(player_handle_, is_fast_startup); //设置快速启动模式
  49. int rtsp_timeout = 10;
  50. NT_U3D_SetRTSPTimeout(player_handle_, rtsp_timeout); //设置RTSP超时时间
  51. int is_auto_switch_tcp_udp = 1;
  52. NT_U3D_SetRTSPAutoSwitchTcpUdp(player_handle_, is_auto_switch_tcp_udp); //设置TCP/UDP模式自动切换
  53. int is_audiotrack = 1;
  54. NT_U3D_SetAudioOutputType(player_handle_, is_audiotrack); //设置音频输出模式: if 0: 自动选择; if with 1: audiotrack模式
  55. NT_U3D_SetUrl(player_handle_, videoUrl);
  56. /* -- 播放前参数配置可加在此处 -- */
  57. int flag = NT_U3D_StartPlay(player_handle_);
  58. if (flag == DANIULIVE_RETURN_OK)
  59. {
  60. is_need_get_frame_ = true;
  61. Debug.Log("播放成功");
  62. }
  63. else
  64. {
  65. is_need_get_frame_ = false;
  66. Debug.LogError("播放失败");
  67. }
  68. is_running = true;
  69. }

対応する OpenPlayer() 実装は次のとおりです。

  1. private void OpenPlayer()
  2. {
  3. if ( java_obj_cur_activity_ == null )
  4. {
  5. Debug.LogError("getApplicationContext is null");
  6. return;
  7. }
  8. player_handle_ = NT_U3D_Open();
  9. if (player_handle_ != 0)
  10. Debug.Log("open success");
  11. else
  12. Debug.LogError("open fail");
  13. }

プレーヤーを閉じる:

  1. private void ClosePlayer()
  2. {
  3. is_need_get_frame_ = false;
  4. is_need_init_texture_ = false;
  5. int flag = NT_U3D_StopPlay(player_handle_);
  6. if (flag == DANIULIVE_RETURN_OK)
  7. {
  8. Debug.Log("停止成功");
  9. }
  10. else
  11. {
  12. Debug.LogError("停止失败");
  13. }
  14. flag = NT_U3D_Close(player_handle_);
  15. if (flag == DANIULIVE_RETURN_OK)
  16. {
  17. Debug.Log("关闭成功");
  18. }
  19. else
  20. {
  21. Debug.LogError("关闭失败");
  22. }
  23. player_handle_ = 0;
  24. NT_U3D_UnInit();
  25. is_running = false;
  26. video_format_ = VideoFrame.FORMAT_UNKNOWN;
  27. video_width_ = 0;
  28. video_height_ = 0;
  29. }

更新データを更新します。

  1. private void Update()
  2. {
  3. if (!is_need_get_frame_)
  4. return;
  5. if (player_handle_ == 0)
  6. return;
  7. AndroidJavaObject u3d_video_frame_obj = NT_U3D_GetVideoFrame(player_handle_);
  8. if (u3d_video_frame_obj == null)
  9. {
  10. return;
  11. }
  12. VideoFrame converted_video_frame = ConvertToVideoFrame(u3d_video_frame_obj);
  13. if (converted_video_frame == null)
  14. {
  15. u3d_video_frame_obj.Call("release");
  16. u3d_video_frame_obj = null;
  17. return;
  18. }
  19. if (!is_need_init_texture_)
  20. {
  21. if (converted_video_frame.format_ != video_format_)
  22. {
  23. is_need_init_texture_ = true;
  24. }
  25. else if (converted_video_frame.width_ != video_width_
  26. || converted_video_frame.height_ != video_height_
  27. || converted_video_frame.stride0_ != y_row_bytes_
  28. || converted_video_frame.stride1_ != u_row_bytes_
  29. || converted_video_frame.stride2_ != v_row_bytes_)
  30. {
  31. is_need_init_texture_ = true;
  32. }
  33. }
  34. if (is_need_init_texture_)
  35. {
  36. if (InitYUVTexture(converted_video_frame))
  37. {
  38. is_need_init_texture_ = false;
  39. }
  40. }
  41. UpdateYUVTexture(converted_video_frame);
  42. converted_video_frame.java_frame_obj_ = null;
  43. converted_video_frame = null;
  44. u3d_video_frame_obj.Call("release");
  45. u3d_video_frame_obj = null;
  46. }

要約する

VR ヘッドセットで 8K RTSP または RTSP ストリームを再生する必要がある場合、ハードウェアとネットワークに対する要件が非常に高いため、実際のアプリケーションではいくつかの課題が発生する可能性があります。実際のテストを通じて、Quest3 ヘッドセットと RTSP|RTMP プレーヤーを組み合わせると、Unity での 8K ビデオ データ再生のミリ秒レベルの遅延を実現でき、バランス制御などの非常に高いリアルタイム要件を伴う使用シナリオに対応できます。興味のある開発者はこれについて話し合うことができます。私と個別に。