|
Модератор
|
||||||
Воспроизведение видео15.02.2021, 22:46. Показов 4053. Ответов 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
Наложить видео с альфа каналом поверх картинки с камеры, чтобы видео не перекрывало картинку Воспроизведение видео воспроизведение видео на пк Воспроизведение видео Воспроизведение видео Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
||||
|
Новый ноутбук
volvo 07.12.2025
Всем привет.
По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне:
Ryzen 5 7533HS
64 Gb DDR5
1Tb NVMe
16" Full HD Display
Win11 Pro
|
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
|
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
|
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов
На странице:
https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/
нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
|
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов.
. . .
|
|
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
|
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
|
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут.
В век Веб все очень привыкли к дизайну Single-Page-Application .
Быстренько разберем подход "на фреймах".
Мы делаем одну. . .
|
Фото: Daniel Greenwood
kumehtar 13.11.2025
|
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга,
Ты же видел моря и метели.
Как сменялись короны и стяги,
Как эпохи стрелою летели.
- Этот мир — это крылья и горы,
Снег и пламя, любовь и тревоги,
И бескрайние. . .
|