Воспроизведение пользовательского потока данных avi с использованием QtMultimedia

Мне нужно воспроизвести пользовательский файл AVI, содержащий классический видеопоток, аудиопоток , а также пользовательский поток данных.

Пользовательский поток содержит данные, которые визуализируются с помощью некоторых пользовательских виджетов; эти виджеты нуждаются только в том, чтобы каждый пользовательский кадр записывался в буфер в нужное время.

Наше приложение основано на Qt и уже использует QMediaPlayer/QVideoWidget для воспроизведения традиционных видео, но дополнительный пользовательский поток усложняет работу, потому что AFAIK QMediaPlayer воспроизводит только видео/аудио и игнорирует все остальное.

Я бы хотел избежать повторного использования всего qt-multimedia, но я не уверен, как сделать все возможное из доступных классов Qt.


Мои идеи до сих пор:

  • Создайте собственный медиаплеер, который демультиплексирует и декодирует видео с помощью ffmpeg, реализует синхронизацию, использует QAudioOutput для воспроизведения звука, создает поток QVideoFrame для воспроизведения на видео и записи пользовательских данных в некоторый буфер для визуализации.

    Проблема. Чтобы избежать написания кода для масштабирования/преобразования видеокадров, я хотел бы повторно использовать QVideoWidget, но, похоже, работает только с "реальным" QMediaPlayer.

  • Demux входной файл и канал QMediaPlayer с AV-потоками. Demux введите ffmpeg (возможно, оставив декодирование в бэкенд Qt), попросите QIODevice извлечь только видео/аудиопотоки из входного файла, а другой - для получения потока данных. Воспроизведите видео/аудио с помощью QMediaPlayer.

                  +-------+                          
                  | QFile |                          
                  +---^---+                          
                      |                              
                   inherits                          
                      |                              
            +--------------------+
            |    MyAviDemuxer    |
            |                    |
            |  holds a queue of  |
            |  demuxed packets   |
            +--------------------+
            |                    |
      readDataPacket      readVideoPacket
            |                    |
    +-------v--------+  +--------v-----------+            +-----------+
    | MyCustomReader |  | MyVideoAudioStream +--inherits--> QIODevice |
    +----------------+  +--------+-----------+            +-----------+
                                 |       
                              setMedia                  
                                 |                  
                         +-------v-------+           
                         | QMediaPlayer  |           
                         +---------------+           
    

    Проблема: синхронизировать синхронизацию потока данных с QMediaPlayer, обработать заголовки и метаданные правильно.


Я немного склонен к варианту 1, только потому, что он дает мне больше контроля, но мне интересно, пропустил ли я более простое решение (даже для Windows).

Ответ 1

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

Решение для: синхронизации времени потока данных с QMediaPlayer:
Попробуйте использовать некоторые таймерные потоки (сочетание Thread и таймер). Создайте тот, который использует любой индекс потока из MyVideoAudioStream (используя время как переменную в индексе) и "Mycustomreader" (используя массив пакетов со временем как переменную в индексе) в качестве тела. Добавьте в тело некоторую логику, которая циклически проходит через позицию (@param: time) в QMediaPlayer. Из этого вы можете проанализировать код выполнения обоих одновременно. По мере увеличения времени позиция в QMediaPlayer и индекс вашего потока будут увеличиваться.

Если у вас нет указателя или позиции в пользовательском потоке, я настоятельно рекомендую вам создать его.

Ответ 2

Похоже, что Qt на самом деле уже в некоторой степени поддерживает концепцию потоков данных - http://doc.qt.io/qt-5/qmediastreamscontrol.html#details показывает, что это среди выбираемых типов потоков для контроля qmediastreams.

Другие документы, включая http://doc.qt.io/qt-5/qmediaserviceproviderplugin.html, предполагают, что вы можете создать QMediaServiceProviderPlugin, который реализует видео и аудио интерфейсы QMediaControl (возможно, путем подкласса существующего поставщик медиа-услуг), также создайте собственный подкласмент интерфейса QMediaControl, чтобы создать элемент управления для обработки ваших необработанных данных.

Надеемся, что реализация таким образом позволит вам использовать существующие возможности для разделения потоков, обработки заголовков и аналогичных функций.

К сожалению, особенности построения QMediaService, по-видимому, "вне сферы действия этой документации и поддержки в соответствующих списках рассылки или IRC-каналах". (http://doc.qt.io/qt-5/qmediaservice.html#details). Источник (http://code.qt.io/cgit/qt/qtmultimedia.git/tree/src/multimedia) мог бы использовать это, однако, в дополнение к, возможно, источнику в http://code.qt.io/cgit/qt/qtmultimedia.git/tree/src/plugins, который включает в себя плагины directshow/gstreamer/coreaudio.

В любом случае я попытался бы подклассом и повторно реализовать как можно меньше