|
Модератор
|
||||||
Воспроизведение видео15.02.2021, 22:46. Показов 4403. Ответов 34
Давно уже были мысли создать тему про это, но только сейчас дошли руки. Собственно сам вопрос, как правильно воспроизводить видео с использованием opengl? Знаю про pbo, но с ним надо мапить буфер а сам этот процесс довольно затратный. Пока сделал тупо в лоб, рисую прямоугольник с текстурой на весь экран, две текстуры, одну рисую, другую заполняю через glTextureSubImage2D декодированными данными в том же кадре.
На fullhd видео у меня выдает в среднем 60 фпс (+- 1 крайне редко 2), в 4к все похуже, в среднем около 22 (+- 5) фпс Форматы и размер видео не влияют на фпс, по крайней мере я не заметил. Видео декодирую через ffmeg (думаю в идеале нужно остановиться на одном формате, а то +15мб к весу как-то не очень, другой вопрос какой формат, но сейчас не об этом). Так как движок игровой куча форматов не нужны и буду видео подгонять к нужному фреймрейту, а то сейчас у меня всегда стремится к 60 не взирая на фпс самого видео)) Звук не реализовывал, будет думаю отдельно и через openal Есть у кого опыт в данном вопросе? Точно ли будет выигрыш от pbo и стоит ли его использовать? В сети не нахожу понятных примеров использования pbo, особенно с dsa. И везде советуют заполнять буфер после мэппинга в другом потоке, а с потоками я совсем не разбираюсь. Знаю что нельзя использовать один контекст в разных потоках и можно расшаривать ресурсы, не проблема, в glfw создать еще одно окно как дочернее от основного и ресурсы будут общими. Думаю для меня важнее неблокируемый запись данных в текстуру, но можно ли это сделать в одном потоке. Ведь декодирование и конвертирование видео из YUV в RGBA тоже процесс не быстрый и блокирующий основной поток. В данный момент так рисую
OpenGL_VideoPlayer.7z
0
|
||||||
| 15.02.2021, 22:46 | |
|
Ответы с готовыми решениями:
34
Воспроизведение видео-файлов DirectShow воспроизведение видео из буфера в ОЗУ Воспроизведение видео .h264 без сторонних кодеков |
|
Модератор
|
||||||||||||||||
| 16.02.2021, 11:42 [ТС] | ||||||||||||||||
|
Немного поменял код, добавил pbo (надеюсь правильно), работать работает, но вот фпс не поменялся...
Было
Только теперь начал плеваться нотификациями
0
|
||||||||||||||||
|
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
|
|
| 16.02.2021, 17:29 | |
|
alecss131, для начала, вместо glMapNamedBuffer используй glMapBufferRange с флагами GL_MAP_WRITE_BIT и GL_MAP_INVALIDATE_BUFFER_BIT.
А вообще это делается с помощью техники стриминга. Создаёшь буфер, размером на N кадров, кадр размером frameSize(только размер данных одного кадра следует округлить в большую сторону, кратное выравниванию, которое подобрать опытным путём, что бы давало лучшую производительность, но минимальное возьми не меньше 4, дальше степени двойки, т.е. 8, 16, 32, 64 ...). Условно устанавливаешь указатель(offset) на начало буфера (0). Мэпишь диапазон offset + frameSize (с флагами GL_MAP_WRITE_BIT, GL_MAP_UNSYNCHRONIZED_BIT и GL_MAP_INVALIDATE_RANGE_BIT), загружаешь туда данные, анмэпишь, данный участок буфера можно использовать для последующего трансфера пикселей в текстуру. Сам указатель инкрементируешь(offset = offset + frameSize) и повторяешь загрузку, только в следующий участок. Когда дойдёшь до конца буфера, то ставишь указатель на начало(0), только мэпишь первый участок с инвалидацией всего буфера(GL_MAP_INVALIDATE_BUFFER_BIT, это аллоцирует новое хранилище), и продолжаешь как обычно. В итоге, пока ты загружаешь очередной кадр, предыдущий может использоваться GL. Получается асинхронно. Вместо реаллокации всего буфера, когда он заполнен(что может быть затратно по памати), можно каждому из N участков сопоставить объект синхронизации (glFenceSync), что бы узнать, что данные этого участка уже были загружены в текстуру. Тогда после заполнения и перехода указателя на первый участок, перед тем как его мэпить, ждёшь объект синхронизации. Если памяти много, и можешь позволить буфер под много кадров, то скорее всего ожидания объекта синхронизации не будет, т.к. он уже был использован N кадров назад. Так же один буфер можно заменить на несколько. Данный подход асинхронен, хотя тут размен - память vs скорость.
1
|
|
|
Модератор
|
|
| 16.02.2021, 21:13 [ТС] | |
|
zayats80888, спасибо, но возникли новые вопросы на основе вашего ответа))
сначала небольшое исправление, не glMapBufferRange а glMapNamedBufferRange ведь использую dsa и зачем лишние бинды) теперь пару слов про то как это работает: с помощью ffmpeg читаю из видеопотока кадр (frame), который представляет из себя три однобайтных чб картинки по одной на канал (вроде идущие в памяти последовательно) размером с видео потом с помощью функции sws_scale (из той же библиотеки) преобразую эти 3 картинки в нужный RGBA8 формат и масштабирую к нужному размеру, в итоге получается новый кадр (dframe) который и использую надеюсь узкое место не здесь и не будет здесь, ведь в случае с 4к видео у меня frame 4к, а dframe уже fullhd. откуда возникает первый вопрос, где лучше менять размер, масштабировать dframe или оставлять исходный размер и использовать эту текстуру в opengl для отрисовки более маленького прямоугольника? в любом случае будет смена формата, только с или без изменения размера хоть у меня монитор и не 4к, но на компе попались видео этого размера, fullhd кадр в rgba8 весит почти 8мб, а 4к в том же формате почти 32мб, в планах делать разрешение рендера больше fullhd нету и в этом разрешении любой способ дает у меня стабильные 60 фпс (интересно проверить на других компах это) теперь следующий вопрос, зачем надо делать invalidate буферу? ведь его же просто перезаписываем новыми данными, на что это влияет? важен ли порядок действий? я про обновление текстуры из прошлого шага, заполнение буфера и отрисовку кадра, как понимаю заполнение буфера с его полной инвалидацией должно быть перед обновлением текстуры, а если частично то не понимаю выравнивание для меня не очень приятная вещь, еще помню намучился с ним когда использовал glBindBufferRange, там нужно конкретное выравнивание было, а тут размер кадра почти 8 мб еще не понимаю откуда тут асинхронность, ведь все в одном потоке и вызовы к видеокарте будут тормозиться обработкой видеопотока. за один шаг главного цикла по одному действию каждого вида, а то боюсь подготовка новых кадров видео тут самое затратное и долгое и можно не уложиться в 60 фпс, значит буфер более чем на 2 кадра не очень актуален синхронизация для меня вообще темный лес, хотя и полезно было бы разобраться, ведь хочу потом освоить вулкан а там без ручной синхронизации не обойтись у меня сейчас цель просто получить стабильные 60 фпс при проигрывании видео из 4к потока, это в идеале, план минимум fullhd поток, что уже есть, но надо улучшить)) по хорошему надо еще заняться синхронизацией фпс видео и фпс программы, но уж лучше к движку рендерить видео с нужным фпс, ведь я не видеоплеер пишу, а так же звуком, но звук сейчас последнее что интересно)))
0
|
|
|
с++
1282 / 523 / 225
Регистрация: 15.07.2015
Сообщений: 2,562
|
|
| 16.02.2021, 21:22 | |
|
а почему нельзя использовать квадрат и на нем отображать видео, зачем все то что вы хотите использовать?
0
|
|
|
с++
1282 / 523 / 225
Регистрация: 15.07.2015
Сообщений: 2,562
|
|
| 16.02.2021, 21:42 | |
|
0
|
|
|
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
|
||||
| 16.02.2021, 21:50 | ||||
|
Если ты про GL_MAP_INVALIDATE_RANGE_BIT, то это подсказка по оптимизации, мы обещаем переписать все данные диапазона, старые нам не нужны, а значит можно их не загружать. , не до этого сейчас).
0
|
||||
|
Модератор
|
|||||||||||
| 16.02.2021, 22:32 [ТС] | |||||||||||
|
Antikl, там по сути мой первый вариант и есть, каждый кадр заполнять текстуру через glTexSubImage2D который у меня для 4к 60 фпс видео дает в лучшем случае 27 фпс и в среднем 22 фпс
тем более тот код написан с использованием deprecated функций ffmpeg и не собирается, я руками переводил свой код на свежую версию Добавлено через 36 минут Сделал код с буфером удвоенного размера и биндом по частям, ничего не поменялось. Единственное отличие только в том если открывать файл fullhd то спамит нотификациями каждый кадр, а если 4к, то выводит всего по 1 разу и все Размер буфера и так кратный 4, так как 4 канала в картинке Вот код декодера заголовок
zayats80888, Я флаги там где нужно указал? Пока без инвалидации всего буфера, только частями. Ведь маплю буфер с флагом GL_MAP_UNSYNCHRONIZED_BIT а в нотификациях про синхронизацию, если этот флаг поместить в 10 строчку то не создается буфер
0
|
|||||||||||
|
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
|
|||||||
| 16.02.2021, 23:00 | |||||||
|
2) Флаги: GL_MAP_WRITE_BIT (и, возможно, GL_CLIENT_STORAGE_BIT). GL_DYNAMIC_STORAGE_BIT тут не нужен, ты не используешь функции GL для загрузки. 3) Ты не синхронизируешь, когда возвращаешься в начало буфера. Примерная логика:
0
|
|||||||
| 16.02.2021, 23:24 | |
|
0
|
|
|
Модератор
|
||||||
| 16.02.2021, 23:38 [ТС] | ||||||
|
Меня примерный код больше запутал, мне нужно в dframe.data[0] положить указатель куда будут писаться данные
И если сделать GL_MAP_INVALIDATE_BUFFER_BIT то последующий glTextureSubImage2D сработает? ведь запрос будет отправлен после, а не до
0
|
||||||
|
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
|
|||
| 17.02.2021, 00:16 | |||
|
--- И ещё, запроси glGetIntegerv(GL_MIN_MAP_BUFFER_ALIGNMEN T, ...), что бы подогнать stride.
0
|
|||
|
Модератор
|
|||||||||||||||||
| 17.02.2021, 12:38 [ТС] | |||||||||||||||||
|
Переписал код вот так
заголовок
Странно... мой первый вариант открывал все видео
0
|
|||||||||||||||||
|
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
|
||
| 17.02.2021, 13:56 | ||
|
Ну и узкое место ты нашел? У тебя же студия, покажи профилировку.
0
|
||
|
Модератор
|
||||||||
| 17.02.2021, 16:47 [ТС] | ||||||||
|
zayats80888, переписал вот так, видео стало воспроизводиться
Добавлено через 1 час 0 минут Хм, странно, отключил вертикалку теперь 92 фпс, а если вывести фпс из ffmpeg то показывает в том же видео 25, в fullhd файлах фпс так вообще 200+ Надо будет на момент видео отключать вертикалку и ограничивать таймером
0
|
||||||||
|
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
|
|||
| 17.02.2021, 17:12 | |||
, опять, если кадр не запишется в mapped буфер, то ты впустую отправишь невалидные данные в текстуру. Мэпить нужно только когда кадр готов.
0
|
|||
|
Модератор
|
||||||||||||
| 17.02.2021, 22:42 [ТС] | ||||||||||||
0
|
||||||||||||
|
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
|
||||||
| 17.02.2021, 23:45 | ||||||
|
alecss131, читай доки. Я с ffmpeg не работал, но вкратце глянул, там каждый кадр сопровождается метками времени.Судя по тому, что фпс проседает при синхронизации - основной тормоз, это декодирование видео(хотя профилировку ты так и не показал).
Я бы сделал так: В главном потоке создал бы экземпляр класса, поставляющего кадр(текстуру) для рендера, с примерно таким функционалом(!псевдокод!):
правильным управлением ресурсами и разделением обязанностей.
0
|
||||||
| 17.02.2021, 23:45 | |
|
Помогаю со студенческими работами здесь
20
Наложить видео с альфа каналом поверх картинки с камеры, чтобы видео не перекрывало картинку Воспроизведение видео воспроизведение видео на пк Воспроизведение видео Воспроизведение видео Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
| Опции темы | |
|
|
Новые блоги и статьи
|
|||
|
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . .
а удачный момент так и не приходит.
|
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица.
Задача: зафиксировать три левых колонки в отчете.
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
/ / . . .
|
Настройки VS Code
Loafer 13.04.2026
{
"cmake. configureOnOpen": false,
"diffEditor. ignoreTrimWhitespace": true,
"editor. guides. bracketPairs": "active",
"extensions. ignoreRecommendations": true,
. . .
|
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2.
Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива.
Было так:. . .
|
|
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2.
Задача: реализовать контроль корректности заполнения дат назначения. . .
|
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html
Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
|
Подстановка значения реквизита справочника в табличную часть документа
Maks 10.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2.
Задача: при выборе сотрудника (справочник Сотрудники) в ТЧ документа. . .
|
Очистка реквизитов документа при копировании
Maks 09.04.2026
Алгоритм из решения ниже применим как для типовых, так и для нетиповых документов на самых различных конфигурациях.
Задача: при копировании документа очищать определенные реквизиты и табличную. . .
|