Как добиться воспроизведения RTMP или RTSP со сверхнизкой задержкой в ​​WPF
Как добиться воспроизведения RTMP или RTSP со сверхнизкой задержкой в ​​WPF

Технический бэкграунд

Когда мы соединяем модули воспроизведения RTMP и RTSP на платформе Windows, некоторым разработчикам необходимо вызывать их под WPF. Если вы хотите использовать их под WPF, вам нужно только обратиться к демонстрации стыковки C#. Единственная разница заключается в том, что. данные видеопотока отображаются либо через режим управления, либо вы можете позволить модулям воспроизведения RTMP и RTSP вызывать данные RGB и рисовать их непосредственно в wpf.

Техническая реализация

В этой статье в качестве примера используется платформа Windows SmartPlayer из Daniu Live SDK. Режим данных обратного вызова не будет объяснен, пока обрабатываются входящие данные:

Перед воспроизведением установите обратный вызов и выберите NT_SP_E_VIDEO_FRAME_FORMAT_RGB32:

Язык кода:csharp
копировать
video_frame_call_back_ = new SP_SDKVideoFrameCallBack(SetVideoFrameCallBack);

NTSmartPlayerSDK.NT_SP_SetVideoFrameCallBack(player_handle_, (Int32)NT.NTSmartPlayerDefine.NT_SP_E_VIDEO_FRAME_FORMAT.NT_SP_E_VIDEO_FRAME_FORMAT_RGB32, IntPtr.Zero, video_frame_call_back_);

Обработка обратного вызова данных RGB:

Язык кода:csharp
копировать
       /*
        * nt_player_wrapper.cs
        * Author: daniusdk.com
        */
        public void SetVideoFrameCallBack(IntPtr handle, IntPtr userData, UInt32 status, IntPtr frame)
        {
            if (frame == IntPtr.Zero)
            {
                return;
            }

            //Если вам нужно обработать данные RGB напрямую, обратитесь к следующему процессу
            NT_SP_VideoFrame video_frame = (NT_SP_VideoFrame)Marshal.PtrToStructure(frame, typeof(NT_SP_VideoFrame));

            if (video_frame.format_ != (Int32)NT.NTSmartPlayerDefine.NT_SP_E_VIDEO_FRAME_FORMAT.NT_SP_E_VIDEO_FRAME_FORMAT_RGB32)
                return;

            NT_SP_VideoFrame pVideoFrame = new NT_SP_VideoFrame();

            pVideoFrame.format_ = video_frame.format_;
            pVideoFrame.width_ = video_frame.width_;
            pVideoFrame.height_ = video_frame.height_;

            pVideoFrame.timestamp_ = video_frame.timestamp_;
            pVideoFrame.stride0_ = video_frame.stride0_;
            pVideoFrame.stride1_ = video_frame.stride1_;
            pVideoFrame.stride2_ = video_frame.stride2_;
            pVideoFrame.stride3_ = video_frame.stride3_;


            Int32 argb_size = video_frame.stride0_ * video_frame.height_;

            pVideoFrame.plane0_ = Marshal.AllocHGlobal(argb_size);
            CopyMemory(pVideoFrame.plane0_, video_frame.plane0_, (UInt32)argb_size);
        }

Другой способ — использовать PictureBox и выполнить следующие настройки в MainWindow.xaml:

Язык кода:csharp
копировать
        <WindowsFormsHost HorizontalAlignment="Left" Height="338" Margin="10,10,0,0" VerticalAlignment="Top" Width="480" Background="Black">
            <wf:PictureBox x:Name="RealPlayWnd"></wf:PictureBox>
        </WindowsFormsHost>

Чтобы облегчить интеграцию нескольких экземпляров, в качестве примера возьмем 2 канала воспроизведения (один канал 2560*1440, один канал 1920*1080):

Конкретная реализация выглядит следующим образом:

Язык кода:csharp
копировать
       /*
        * MainWindow.xaml.cs
        * Author: daniusdk.com
        */
        public MainWindow()
        {
            InitializeComponent();

            if (!InitSDK())
                return;

            UIDispatcher = Dispatcher.CurrentDispatcher;

            player1_ = new nt_player_wrapper(RealPlayWnd, UIDispatcher);
            player1_.EventGetPlayerEventMsg += new DelGetPlayerEventMsg(GetPlayerEventMsgInfo);
            player1_.EventGetVideoSize += new DelGetVideoSize(GetVideoSize);

            player2_ = new nt_player_wrapper(RealPlayWnd1, UIDispatcher);
            player2_.EventGetPlayerEventMsg += new DelGetPlayerEventMsg(GetPlayerEventMsgInfo);
            player2_.EventGetVideoSize += new DelGetVideoSize(GetVideoSize);
        }

        private void GetPlayerEventMsgInfo(IntPtr handle, String msg)
        {
            this.Dispatcher.Invoke((Action)delegate()
            {
                event_label.Content = msg;
            });
        }

        private void GetVideoSize(IntPtr handle, String size)
        {
            this.Dispatcher.Invoke((Action)delegate()
            {
                video_size.Content = size;
            });
        }

        private bool InitSDK()
        {
            if (!is_player_sdk_init_)
            {
                UInt32 isPlayerInited = NT.NTSmartPlayerSDK.NT_SP_Init(0, IntPtr.Zero);
                if (isPlayerInited != 0)
                {
                    MessageBox.Show("Ошибка вызова NT_SP_Init..");
                    return false;
                }

                is_player_sdk_init_ = true;
            }

            return true;
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            if (!player1_.IsPlaying())
            {
                player1_.SetBuffer(0);
                bool is_mute = true;

                if (!player1_.StartPlay("rtsp://admin:daniulive12345@192.168.0.120:554/h264/ch1/main/av_stream", false, is_mute))
                    return;

                btn_playback1.Content = «Хватит играть»;
            }
            else
            {
                player1_.StopPlay();
                btn_playback1.Content = «Начать играть»;
            }
        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            if (!player2_.IsPlaying())
            {
                player2_.SetBuffer(0);
                bool is_mute = true;

                if (!player2_.StartPlay("rtsp://admin:admin123456@192.168.0.121:554/cam/realmonitor?channel=1&subtype=0", false, is_mute))
                    return;

                btn_playback2.Content = «Хватит играть»;
            }
            else
            {
                player2_.StopPlay();
                btn_playback2.Content = «Начать играть»;
            }
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            if (MessageBox.Show("Вы уверены, что хотите закрыть окно?", "подтверждать", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
            {
                // Если пользователь выбирает «Нет», отмените закрытие
                e.Cancel = true;
            }

            if (player1_.IsPlaying())
            {
                player1_.StopPlay();
            }

            player1_.Dispose();

            if (player2_.IsPlaying())
            {
                player2_.StopPlay();
            }

            player2_.Dispose();

            if (is_player_sdk_init_)
            {
                NTSmartPlayerSDK.NT_SP_UnInit();
                is_player_sdk_init_ = false;
            }    

            base.OnClosing(e);
        }

Задержка по-прежнему находится на уровне миллисекунд, а загрузка ЦП следующая. Если вы используете жесткое декодирование, качество будет лучше:

В качестве примера SmartPlayer использует кроссплатформенный RTSP-плеер. Мы реализуем следующие функции. Если не указано иное, они поддерживаются всеми платформами Windows, Linux, Android и iOS:

  • [Поддержка протокола воспроизведения] Высокая стабильность、сверхнизкая задержка、Впервые в отраслиRTSPпрямая трансляцияSDK проигрывателя
  • [Воспроизведение нескольких экземпляров] Поддерживает воспроизведение нескольких экземпляров;
  • [Обратный вызов по событию] поддерживает состояние сети, состояние буфера и другие обратные вызовы;
  • [Формат видео] поддерживает H.265, H.264, кроме того, также поддерживает воспроизведение RTSP MJPEG;
  • [Аудиоформат] Поддержка AAC/PCMA/PCMU;
  • [Мягкое декодирование H.264/H.265] Поддержка мягкого декодирования H.264/H.265;
  • [Жесткое декодирование H.264] Windows/Android/iOS поддерживает жесткое декодирование H.264 для определенных моделей;
  • [Жесткая расшифровка H.265] Windows/Android/iOS поддерживает жесткую расшифровку H.265 для определенных моделей;
  • [H.264/H.265 Hard Decoding] Android поддерживает настройку жесткого декодирования в режиме Surface и жесткого декодирования в обычном режиме;
  • [Настройка режима RTSP] Поддержка настройки режима RTSP TCP/UDP;
  • [Автоматическое переключение RTSP TCP/UDP] Поддерживает автоматическое переключение режимов RTSP TCP и UDP;
  • [Настройка тайм-аута RTSP] Поддерживает настройку тайм-аута RTSP, единица измерения: секунды;
  • [Обработка аутентификации RTSP 401] Поддерживает отчеты о событиях RTSP 401. Если URL-адрес содержит информацию аутентификации, она будет обработана автоматически;
  • [Настройка времени буфера] Поддержка настройки времени буфера;
  • [Открыть за секунды на первом экране] Поддерживает режим открытия за секунды на первом экране;
  • [Сложная сетевая обработка] Поддерживает автоматическую адаптацию к различным сетевым средам, например отключение и повторное подключение к сети;
  • [Быстрое переключение URL-адресов] Поддерживает быстрое переключение других URL-адресов во время воспроизведения, а переключение контента происходит быстрее;
  • [Множественные механизмы рендеринга аудио и видео] Платформа Android, видео: Surfaceview/OpenGL ES, аудио: AudioTrack/OpenSL ES;
  • [Отключение звука в реальном времени] Поддерживает отключение/включение звука в режиме реального времени во время воспроизведения;
  • [Регулировка громкости в реальном времени] Поддерживает регулировку громкости в реальном времени во время воспроизведения;
  • [Снимок в реальном времени] поддерживает захват текущего экрана воспроизведения во время воспроизведения;
  • [Воспроизведение только ключевых кадров] Платформа Windows поддерживает настройку в режиме реального времени, следует ли воспроизводить только ключевые кадры;
  • [Угол рендеринга] Поддерживает четыре настройки угла рендеринга видеоэкрана: 0°, 90°, 180° и 270°;
  • [Зеркало рендеринга] поддерживает настройки режима горизонтальной инверсии и вертикальной инверсии;
  • [Равное масштабирование] Поддерживает масштабирование и рисование изображений (режим жесткого решения для поверхностного режима Android не поддерживает это);
  • [Обновление скорости загрузки в реальном времени] Поддерживает обратный вызов текущей скорости загрузки в реальном времени (поддерживает настройку интервала обратного вызова);
  • [Обратный вызов видеоданных перед декодированием] Поддерживает обратный вызов данных H.264/H.265;
  • [Обратный вызов видеоданных после декодирования] Поддерживает обратный вызов данных YUV/RGB после декодирования;
  • [Обратный вызов аудиоданных перед декодированием] Поддерживает обратный вызов данных AAC/PCMA/PCMU;
  • [Адаптивная аудио и видео] поддерживает адаптивную адаптацию после изменения аудио- и видеоинформации во время воспроизведения;
  • [Расширенная функция видеозаписи] Идеально поддерживает совместное использование с модулем видеозаписи.

Подвести итог

Если вам нужно воспроизведение WPF на платформе Windows и вам нужно быть более гибким, вы можете использовать режим данных обратного вызова RGB. Верхний уровень рисует напрямую и воспроизводит изображение с низкой задержкой. Вы также можете использовать вышеуказанный режим управления. Помимо WPF мы предоставляем C++ и C#. Заинтересованные разработчики могут попробовать интерфейс и демо. Если у вас есть вопросы, вы можете связаться со мной индивидуально.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose