Улучшения в рендеринге пользовательских видеокадров в Qt6 QML Обновление 30 мая 2023 г.
Улучшения в рендеринге пользовательских видеокадров в Qt6 QML Обновление 30 мая 2023 г.

Недавно я обновляю Qt-версию аудио- и видеопроекта с 5.15.0 до 6.4.3 (то же самое относится и к 6.5). Помимо удаления некоторых элементов управления Qt Quick Controls 1 в некоторых QML, самое главное — это удаление некоторых элементов управления Qt Quick Controls 1 в некоторых QML. улучшение пользовательского рендеринга видео.

QAbstractVideoSurface становится QVideoSink

Qt5 Чжунцзай QML При рендеринге пользовательских видеокадров на C++ Layer реализует слой, полученный из QObject Подкласс, используемый внутри QAbstractVideoSurface Приди и отдай VideoOutput Предоставьте данные. Конкретный метод здесь обсуждаться не будет. Вы можете обратиться к статье,которую я написал ранее. Qt QML VideoOutput Показать индивидуальные YUV420P поток данных существовать Qt6 середина,QAbstractVideoSurface одеяло QVideoSink альтернатива, обеспечивающая более простой способ доставки QVideoFrame, пример кода выглядит следующим образом:

Язык кода:javascript
копировать
class FrameProvider : public QObject {
    Q_OBJECT
    Q_PROPERTY(QVideoSink* videoSink READ videoSink WRITE setVideoSink NOTIFY videoSinkChanged)

public:
    explicit FrameProvider(QObject* parent = nullptr);
    ~FrameProvider();

    QVideoSink* videoSink() const { return m_videoSink; }
    void setVideoSink(QVideoSink* videoSink);

signals:
    void videoSinkChanged();

public slots:
    void deliverFrame(const QVideoFrame& frame);

private:
    QPointer<QVideoSink> m_videoSink;
};

Класс объявляет функцию слота deliverFrame Предоставить видеокадр. Предоставить данные привязки модуля и кадра доставки. существовать cpp В реализации только при наличии нового видеопотока он вызывается напрямую m_videoSink из setVideoFrame Метод будет делать:

Язык кода:javascript
копировать
void FrameProvider::deliverFrame(const QVideoFrame& frame) {
    if (!m_videoSink)
        return;
    m_videoSink->setVideoFrame(frame);
}

Воля FrameProvider Следуйте тому же методу, который указан в статье выше, и зарегистрируйтесь, чтобы QML конец, с VideoOutput При совместном использовании есть некоторые небольшие изменения:

Язык кода:javascript
копировать
FrameProvider {
    id: frameProvider
    videoSink: videoContainer.videoSink
}
VideoOutput {
    id: videoContainer
    anchors.fill: parent
    fillMode: VideoOutput.PreserveAspectFit
}

так VideoOutput с новымиз FrameProvider Это делается при совместном использовании. Давайте поговорим об этом дальше. QVideoFrame изизменять:

Изменения в методе копирования данных QVideoFrame

существовать Qt5 например, копирование YUV данные поступают QVideoFrame очень жестокий, по videoFrame.bits() Получите адрес, вычислите местоположение и скопируйте его, не задумываясь:

Язык кода:javascript
копировать
int frameSize = static_cast<int>(frame.width * frame.height * frame.count / 2);
QVideoFrame videoFrame(frameSize, QSize(static_cast<int>(rotationWidth), static_cast<int>(rotationHeight)), static_cast<int>(rotationWidth),
                       QVideoFrame::Format_YUV420P);

if (videoFrame.map(QAbstractVideoBuffer::WriteOnly)) {
    auto src = reinterpret_cast<uint8_t*>(frame.data);
    auto dest = reinterpret_cast<uint8_t*>(videoFrame.bits());

    libyuv::I420Rotate(src + frame.offset[0], static_cast<int>(frame.stride[0]),
                       src + frame.offset[1], static_cast<int>(frame.stride[1]),
                       src + frame.offset[2], static_cast<int>(frame.stride[2]),
                       dest, static_cast<int>(rotationWidth),
                       dest + rotationWidth * rotationHeight, rotationWidth / 2,
                       dest + rotationWidth * rotationHeight + rotationWidth * rotationHeight / 4, rotationWidth / 2,
                       static_cast<int>(frame.width), static_cast<int>(frame.height), rotate_mode);

    videoFrame.setStartTime(0);
    videoFrame.unmap();

    QSize size = QSize(static_cast<int>(rotationWidth), static_cast<int>(rotationHeight));
    emit VideoManager::m_videoFrameDelegate->receivedVideoFrame(QString::fromStdString(accountId), videoFrame, size, bSub);
}

но Qt6 Серьезные изменения произошли, прежде всего, в bits Функция требует передачи целевых данныхиз самолет, например Y plane для 0,U и V В свою очередь для 1 и 2. Это похоже на Qt5 Нет большой разницы, но если нажать bits(0)、bits(1)、bits(1) Когда адрес скопирован в соответствии с логикой оригинала, будет обнаружено, что изображение с некоторым разрешением будет рендериться. Это в основном потому, что для оригинала. YUV Ширина данных не 16 из кратных. и QVideoFrame Однажды позвонили map функция, то каждая plane из stride(существовать Qt второе имя для bytesPerLine) Волявстречада 16 из кратных, если вы скопируете исходные данные по ширине, изображение будет испорчено. Правильный способ сделать это — через QVideoFrame Предоставить из bytesPerLine() метод расчета конкретного plane изширина,Копирование по требованию,Реализация следующая:

Язык кода:javascript
копировать
QVideoFrameFormat format(QSize(rotationWidth, rotationHeight), QVideoFrameFormat::Format_YUV420P);
format.setViewport(QRect(0, 0, rotationWidth, rotationHeight));
QVideoFrame videoFrame(format);
if (videoFrame.map(QVideoFrame::WriteOnly)) {
    auto src = reinterpret_cast<uint8_t*>(frame.data);
    // If the aspect ratio of the original data is not a multiple of 16,
    // when mappedBytes(n) is called after frame mapping, the returned size will be expanded to the nearest multiple of 16.
    // When copying the data, bytesPerLine(n) should be used to get the actual stride that needs to be copied.
    libyuv::I420Rotate(src + frame.offset[0], frame.stride[0],
                       src + frame.offset[1], frame.stride[1],
                       src + frame.offset[2], frame.stride[2],
                       videoFrame.bits(0), videoFrame.bytesPerLine(0),
                       videoFrame.bits(1), videoFrame.bytesPerLine(1),
                       videoFrame.bits(2), videoFrame.bytesPerLine(2),
                       frame.width, frame.height, rotate_mode);
    videoFrame.setStartTime(0);
    videoFrame.unmap();
    QSize size = QSize(static_cast<int>(rotationWidth), static_cast<int>(rotationHeight));
    emit VideoManager::m_videoFrameDelegate->receivedVideoFrame(QString::fromStdString(accountId), videoFrame, size, bSub);
}

в frame.data да YUV из исходных данных. После прохождения изменений QVideoFrame API Мы видим, что Qt верновидеоиметь дело сданныеиз Требования ужесточаются,Хотя много времени было потрачено на решение проблемы,но Наконец-то подытожил ценный опыт.

Обновление 30 мая 2023 г.

Вышеупомянутый метод копирования следует использовать, когда Qt 6.x Если в версии по умолчанию используется механизм рендеринга (OpenGL), некоторые странные разрешения могут вызвать проблемы с размытием экрана. Исправлять Qt изрендеринг Engine для Каждый движок, специфичный для платформы, решает:

Язык кода:javascript
копировать
int main(int argc, char* argv[]) {
    QGuiApplication app(argc, argv);

#if defined(Q_OS_MACX)
    QQuickWindow::setGraphicsApi(QSGRendererInterface::Metal);
#else
    QQuickWindow::setGraphicsApi(QSGRendererInterface::Direct3D11);
#endif
    ..... other code
}
boy illustration
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода