Как добиться воспроизведения 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
Углубленный анализ переполнения памяти CUDA: OutOfMemoryError: CUDA не хватает памяти. Попыталась выделить 3,21 Ги Б (GPU 0; всего 8,00 Ги Б).
boy illustration
[Решено] ошибка установки conda. Среда решения: не удалось выполнить первоначальное зависание. Повторная попытка с помощью файла (графическое руководство).
boy illustration
Прочитайте нейросетевую модель Трансформера в одной статье
boy illustration
.ART Теплые зимние предложения уже открыты
boy illustration
Сравнительная таблица описания кодов ошибок Amap
boy illustration
Уведомление о последних правилах Points Mall в декабре 2022 года.
boy illustration
Даже новички могут быстро приступить к работе с легким сервером приложений.
boy illustration
Взгляд на RSAC 2024|Защита конфиденциальности в эпоху больших моделей
boy illustration
Вы используете ИИ каждый день и до сих пор не знаете, как ИИ дает обратную связь? Одна статья для понимания реализации в коде Python общих функций потерь генеративных моделей + анализ принципов расчета.
boy illustration
Используйте (внутренний) почтовый ящик для образовательных учреждений, чтобы использовать Microsoft Family Bucket (1T дискового пространства на одном диске и версию Office 365 для образовательных учреждений)
boy illustration
Руководство по началу работы с оперативным проектом (7) Практическое сочетание оперативного письма — оперативного письма на основе интеллектуальной системы вопросов и ответов службы поддержки клиентов
boy illustration
[docker] Версия сервера «Чтение 3» — создайте свою собственную программу чтения веб-текста
boy illustration
Обзор Cloud-init и этапы создания в рамках PVE
boy illustration
Корпоративные пользователи используют пакет регистрационных ресурсов для регистрации ICP для веб-сайта и активации оплаты WeChat H5 (с кодом платежного узла версии API V3)
boy illustration
Подробное объяснение таких показателей производительности с высоким уровнем параллелизма, как QPS, TPS, RT и пропускная способность.
boy illustration
Удачи в конкурсе Python Essay Challenge, станьте первым, кто испытает новую функцию сообщества [Запускать блоки кода онлайн] и выиграйте множество изысканных подарков!
boy illustration
[Техническая посадка травы] Кровавая рвота и отделка позволяют вам необычным образом ощипывать гусиные перья! Не распространяйте информацию! ! !
boy illustration
[Официальное ограниченное по времени мероприятие] Сейчас ноябрь, напишите и получите приз
boy illustration
Прочтите это в одной статье: Учебник для няни по созданию сервера Huanshou Parlu на базе CVM-сервера.
boy illustration
Cloud Native | Что такое CRD (настраиваемые определения ресурсов) в K8s?
boy illustration
Как использовать Cloudflare CDN для настройки узла (CF самостоятельно выбирает IP) Гонконг, Китай/Азия узел/сводка и рекомендации внутреннего высокоскоростного IP-сегмента
boy illustration
Дополнительные правила вознаграждения амбассадоров акции в марте 2023 г.
boy illustration
Можно ли открыть частный сервер Phantom Beast Palu одним щелчком мыши? Супер простой урок для начинающих! (Прилагается метод обновления сервера)
boy illustration
[Играйте с Phantom Beast Palu] Обновите игровой сервер Phantom Beast Pallu одним щелчком мыши
boy illustration
Maotouhu делится: последний доступный внутри страны адрес склада исходного образа Docker 2024 года (обновлено 1 декабря)
boy illustration
Кодирование Base64 в MultipartFile
boy illustration
5 точек расширения SpringBoot, супер практично!
boy illustration
Глубокое понимание сопоставления индексов Elasticsearch.
boy illustration
15 рекомендуемых платформ разработки с нулевым кодом корпоративного уровня. Всегда найдется та, которая вам понравится.
boy illustration
Аннотация EasyExcel позволяет экспортировать с сохранением двух десятичных знаков.