Pull to refresh

Comments 28

Если вы еще тут, и вдруг интересен свободный и кроссплатформенный плеер на основе FFmpeg?

Интересен. Пытался в своё время заставить ffplay выдувать через Decklink в SDI, но две вещи остановили:

  1. Нарастающий рассинхрон звука и видео при малейших ошибках в MPEG2TS или отсутствии потока по входу на некоторое время

  2. Долгое время ожидания первого кадра, порядка 6-7 секунд. От настроек кодека не зависит. Cinegy, Aja Bridge Live, да даже Dune укладываются в секунду-полторы.

если ffplay не умеет, то плееры, на основе ffmpeg, тоже не сумеют. Эх, точно также и с gst. Сначало надо проверять через gst-launch...

FFmpeg (равно как и ffplay) умеют нативно работать с картами от Blackmagic, используя их API. Но вот эти два момента перечеркннули всю затею плейаута. Кодер на базе этой связки работает нормально, даже телетекст захватывает на ура из SDI (как в sd, так и VANC для HD)

По опыту QtVLC часто неплохая альтернатива без всех этих хлопот.

Вцелом, если просто проигрывать видео, то и QtMultimedia нормально, особенно если это линукс. К тому же QtVLC сильно старый, наверное ему тяжело в QML...

Никогда не забуду, как я неделю искал причину "зависания" UI в QtQuick приложении. Как оказалось, из-за вызова g_source_remove (отключает обработку системных message в главном message loop) вместо g_source_destroy из ~QGstreamerBusHelperPrivate, по тому, что я имел глупость использовать QAudioDecoder в фоновом потоке (API-то вроде как синхронное, хотя из доков сложно понять). А QAudioDecoder пришлось использовать для самодельного вывода звука через QAudioOutput, по тому, что циклический вывод коротких звуков через QMediaPlayer вызывал серьезные утечки памяти с gstreamer бекендом.

Это был второй по веселости баг, после 2х недель отладки другого трудноуловимого "повисания" приложения. Как выяснилось, из-за несовместимых форматов поверхностей и OpenGL'контекста. Ну правильно, проверять код возврата glMakeCurrent - это не по нашему. Не вышло - ну и хрен с ним. Сам же программист дурак, да? Не нашел в справке по QQuickWindow описание метода setDefaultAlphaBuffer? На! RTFM!

Оххх, а сколько было веселья с переключением в полноэкранный режим. Особо умные разработчики решили, что это хорошая идея автоматом врубать "истинный" полноэкранный режим OpenGL когда геометрия клиентской части окна совпадает с геометрией экрана. Такие мелочи как контекстные меню и подсказки (которых из коробки не было и пришлось сделать самому), т.е. всплывающие окна поверх полноэкрана - разрабов не озаботили. А выглядит оно так себе. Поэтому сейчас используется элегантное решение с выезжанием окна на 1 пиксель за границы экрана, что бы случайно не включился полноэкранный режим. Такой borderless full screen по Qt-шному.

Но это под Win. А под X11 у нас ведь xinerama, и если надо на несколько мониторов - это уже через XSendEvent с _NET_WM_FULLSCREEN_MONITORS. Ой, но ведь оно не всеми оконными менеджерами поддерживается, так что еще надо смотреть на XDG_CURRENT_DESKTOP. Даа, кроссплатформа что надо.

Ох, а как земечательно сделан "многопоточный рендеринг" (QSG_RENDER_LOOP=threaded). Который на самом деле просто тормозит GUI поток и ждет пока там отрисует фоновый. Что по факту просто медленнее чем нарисовать кадр синхронно из GUI потока... Ух, а если еще в приложении несколько окон...

А производительность рендеринга на больших scenegraph? Хочешь 100500 QQuickItem с автоматической обрезкой геометрии? Неее, это тебе надо QGraphicsScene. Там тебе и BSP-дерево, и растровое кеширование, и шрифты без глюков на масштабе, отличном от 1:1 (ох уж этот distance field). Но вот проблемка - оно же для QPainter... Ну ничего есть же QSGSimpleTextureNode, дальше пользователи платформы как-нить сообразят.

А глюк c разваливающимся деревом...

В общем, если бы у меня были злейшие враги, я бы от души пожелал им стать первоклассными разработчиками кроссплатформенных Desktop приложений на C++/Qt.

А QAudioDecoder пришлось использовать для самодельного вывода звука через QAudioOutput, по тому, что циклический вывод коротких звуков через QMediaPlayer вызывал серьезные утечки памяти с gstreamer бекендом.

Ну, скорее всего QAudioDecoder никогда и не работал, если учесть, что только wmf и gst реализовали это. И сам файл был закодированный, и нужно было его проиграть? QMediaPlayer правильный выбор тут, а утечки, это наверное было очень давно.

(API-то вроде как синхронное, хотя из доков сложно понять)

Что-то мне подсказывает, что это не совсем так. И не следует рассчитывать, что API в других потоках будут работать. Лучше создавать и использовать их на главном, но через сигналы.

Грузить UI поток перекачкой семпл-буферов не хотелось. Сигналы - лишние события и задержки. UI высоконагруженный, не хотелось, что бы воспроизведение аудио заикалось до окончания декодирования. Оно работает нормально, только нельзя уничтожать QAudioDecoder. Утечки QMediaPlayer - в 5.9 оно точно есть, а дальше не знаю. Это, конечно, относительно давно, только вот обновить версию QT для большого приложения занятие не из простых. Нужно выделять время на обкатку новых багов.

Оно работает нормально, только нельзя уничтожать QAudioDecoder.

О, это называется повезло. Но этот класс мертворожденный и никогда не использовался по-серьезному, он то реализован только в gst и wmf...И его благополучно удалось похоронить и не откапывать. Надеюсь не воскреснет.

Уточнение про

(API-то вроде как синхронное, хотя из доков сложно понять)

Там внутри может быть куча тредов и так, и да, такого рода АПИ как QAudioOutput, можно и нужно юзать на соседних потоках, чтобы птенциально не было прерываний. Но вот ожидать повышение производительности в таких классах как QMediaPlayer, то наверное не стоит.

Не нашел в справке по QQuickWindow описание метода setDefaultAlphaBuffer? 

Зависания были в том, что не рендерилось вообще, типа завис UI, или рендерилось черным? И useAlpha помогло? Там было много блендинга?

Переставало рендерится после показа модального диалога, для которого у окна была включена прозрачность. А у основного окна не была. Оставался последний нарисованный кадр в окне, который стирался белым при утаскивании окна за границу экрана. При этом внятно юзеры сформулировать причину "зависания" не смогли. Типа что-то сделали и оно перестало обновлять окно. При этом всплывало только на Linux. Виндузовый opengl32.dll такое прощает.

Поэтому сейчас используется элегантное решение с выезжанием окна на 1 пиксель за границы экрана, что бы случайно не включился полноэкранный режим. Такой borderless full screen по Qt-шному.

А есть доки на эту тему?

 т.е. всплывающие окна поверх полноэкрана - разрабов не озаботили. А выглядит оно так себе

Такой костыль нужен был из-за этой проблемы? Это какая платформа? Может там требовали оверлей окна, другие фреймбаферы?

А, это винда...

Есть QWindow::showFullScreen и он врубает настоящий полноэкранный режим. И он так же врубается автоматом, если у окна отключить рамку и задать геометрию под экран. В этом режиме попытки показать поверх полноэкранного приложения другие окна выглядят так себе. Все мерцает, появляется/пропадает. В общем такое. Попробуйте запустить старую полноэкранную игру, а потом поверх неё вытащить другое окно. Поэтому сейчас в моде borderless full screen (просто top level окно с геометрией на весь экран).

если надо на несколько мониторов - это уже через XSendEvent с _NET_WM_FULLSCREEN_MONITORS. Ой, но ведь оно не всеми оконными менеджерами поддерживается, так что еще надо смотреть на XDG_CURRENT_DESKTOP

Если не везде реализовано, то не ясно как мейнтенеры это пропустили. - это ирония, если что. Хотя идея добавить фикс в Кют, который потенциально решает проблему правильным способом, а то, что оно не везде поддерживается оконными менеджерами, это уже не так важно. Узнаю знакомый подход.

SG_RENDER_LOOP=threaded). Который на самом деле просто тормозит GUI поток и ждет пока там отрисует фоновый. Что по факту просто медленнее чем нарисовать кадр синхронно из GUI потока.

Интересно,

This offers significant performance improvements, but imposes certain restrictions on where and when interaction with the scene graph can happen.

2. The render thread prepares to draw a new frame and initiates a block on the GUI thread.

4. GUI thread is blocked.

По факту оно предлагает существенное падение производительности :) Очень специфическое у кого-то в QT представление о параллелелизме. Выполняем поток, планируем вызов функции в другом потоке, а потом ждем в 1м пока второй поток не выполнит функцию. Это медленнее хотя бы за счет необходимости переключения контекста потока и синхронизации туда-сюда-обратно. Я бы еще понял, если бы scene graph рендерился параллельно в несколько потоков, или если бы GUI поток продолжал бы выполнение в процессе отрисовки, т.е. следующий кадр готовился бы, пока рисуется текущий. Но по факту ничего такого нет, это просто пыль в глаза. Типа вот, смотрите - у нас многопоточность!

Кажется, там все сложнее. И да, насколько помню, когда-то лимит был 30 фпс, потом 60, и уже надеюсь такой хардлимит убрали.
И разные платформы реагируют по-разному, обычно гуи и мейн тред совпадает, но бывает и нет. Но думаю есть идея, что блокировать мейн тред, когда гуи рисуется - это дизайн, и могут сказать, что не стоит расчитывать на ускорение рисования, переводя сам рендеринг в отдельный поток.

Я тоже думал что - ну не может же быть, нафига так делать, в чем вообще смысл. Но по факту я видел в отладчике именно это. Когда я понял что именно происходит, я был, так сказать, удивлен. У меня есть теория, что таким образом сделана изоляция состояния OpenGL, там она thread local. Не могли видимо, найти какой-нибудь глюк, состояние-то между вызовами отрисовки сохраняется. И таким вот образом запатчили - просто выкинули draw call'ы в фоновый поток. Но работает оно синхронно. Никакого профита по производительности такой подход дать в принципе не может.

Думаю тут стоит подчеркнуть,

я видел в отладчике именно это.

Это не совсем стандартная ситуация, когда кто-то дебажит код, чтобы понять в чем проблема. Если не сказать хуже...(всмысле это неправильно, и что-то тут уже не так)

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

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

Хочешь 100500 QQuickItem с автоматической обрезкой геометрии?

Это как?

 Неее, это тебе надо QGraphicsScene. Там тебе и BSP-дерево, и растровое кеширование, и шрифты без глюков на масштабе, отличном от 1:1 (ох уж этот distance field).

Это про то, что если много айтемов, то виджетам таке проще хендлить?

Ну ничего есть же QSGSimpleTextureNode

Всмысле, надо самому писать?

Ну, какую-нибудь диаграммку, например, нарисовать. Из блоков и связей. Например, из 100к блоков 100к связей. И блоки какие-нибудь не простые, а с текстом, заголовками, входами/выходами. Если перевести в полигоны - для OpenGL это семечки. Современные 3D модельки содержат на порядки больше геометрии. Но вот если это описывать через QQuickItem'ы.... Так что тут или glBegin и вперед низкоуровневые draw call'ы, или чего-нибудь другое. Смешно, что QGraphicsScene, будучи полностью software rendered, такое вывозит без труда. Но его напрямую вывести в QtQuick нельзя. Нужен вьюпорт (прямоугольник, ездящий по диаграмме - какую часть рисовать). А Flickable подсунуть Image - не выйдет. Растеризовать-то надо только часть. В общем, есть сложности стыковки.

 Так что тут или glBegin и вперед низкоуровневые draw call'ы, или чего-нибудь другое.

Думаю официальный ответ был бы таким, да. При специфической проблеме, это ваши проблемы. Мы когда-то делали форк Кюта и добавляли тыщи хаков поверх, без шансов на апстрим.

И да, проблемы с производительностью могут решаться годами, а костыли, распространяться по "закрытым" каналам связи.

А глюк c разваливающимся деревом...

При рендеринге? Каким деревом?

TreeView в QtQuickControls 1.0 - такое себе.

В общем, если бы у меня были злейшие враги, я бы от души пожелал им стать первоклассными разработчиками кроссплатформенных Desktop приложений на C++/Qt.

Ну, первоклассные....они даже не обидятся.

Особо умные разработчики решили, что это хорошая идея автоматом врубать "истинный" полноэкранный режим OpenGL когда геометрия клиентской части окна совпадает с геометрией экрана.

Это вроде прикол самого OpenGL. У меня в pet-проекте и без Qt то-же самое происходит

Может быть, может быть, я так глубоко в отладчике не закапывался. Но штука неприятная.

Sign up to leave a comment.

Articles