Модификация и отображение QVideoFrames, полученных в QAbstractVideoSurface

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

Я прочитал в http://doc.qt.io/qt-5/videooverview.html, что я могу получить доступ к каждому кадру с помощью подклассов QAbstractVideoSurface и поэтому я это делаю

class VideoSurface : public QAbstractVideoSurface {
    Q_OBJECT

    bool present(const QVideoFrame &frame) override {
        if (surfaceFormat().pixelFormat() != frame.pixelFormat()
                || surfaceFormat().frameSize() != frame.size()) {
            setError(IncorrectFormatError);
            stop();

            return false;
        } else {
            currentFrame = frame;

            return true;
        }
    }

    ...
}

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

Как я могу это сделать?

  1. Если мой VideoSurface класс содержит QWidget как член? или я должен подкласс QWidget который будет содержать VideoSurface?

  2. В обоих случаях, как я могу отобразить этот кадр? Должен ли я сначала преобразовать его в QImage и затем показать (это было бы удобно для меня, потому что моя система обнаружения работает с QImage, но будет ли это эффективно)? Я знаю, что я не могу рисовать снаружи события рисования, поэтому я не могу рисовать в present функция, так где именно должна быть эта функция рисования и как я могу ее вызвать?

  3. Где я должен обнаружить эти объекты и изменить кадр? В present функция, или в функции рисования?

1 ответ

Решение
  1. Это зависит от вас и зависит от того, как вы предпочитаете структурировать свои занятия. Я бы предпочел иметь отдельный виджет, который содержит указатель на ваш VideoSurface и рисует данные, которые возвращаются некоторой функцией-членом VideoSurface (зависит от вашего решения в 2.)

  2. a) QImage достаточно эффективен для некоторых целей, и если вы уже используете его в своем коде обнаружения, то у вас уже есть все в памяти и вы можете работать над этим. Как и в случае всех проблем, связанных с производительностью: проверьте и убедитесь, что производительность достаточно хороша для вас. Если это не так, вы, вероятно, также должны рассмотреть возможность обнаружения другим способом. Я работал над проектом, в котором мы обрабатывали изображения QI, преобразованные из аналогичного объекта VideoSurface в видеопотока камеры на мобильных устройствах (для изображений с относительно низким разрешением), и производительность была достаточно высокой, поэтому мы пока не удосужились использовать другие методы. Исходный код класса VideoSurface в этом проекте (Neuronify) размещен здесь. б) Ваш present() Функция может излучать сигнал, к которому вы можете подключиться, из других объектов, которые извлекают последние данные из VideoSurface и сохраняют их до тех пор, пока не будет вызвана их функция рисования. Или вы можете применить данные непосредственно к некоторому виджету, который принимает данные изображения. Посмотрите Использование QAbstractVideoSurface для примера этого.

  3. Опять же, это зависит от вас:) Однако, если вам нужно повысить производительность в какой-то момент, вы можете выполнить эту работу в другом потоке, чтобы избежать блокировки графического интерфейса пользователя во время обработки данных. И если вы это сделаете, вам нужно решить, нужно ли обрабатывать каждый кадр или некоторые кадры могут пропустить обработку, чтобы улучшить FPS воспроизведения. В последнем случае вам, вероятно, не следует делать это в present() функция, так как это, скорее всего, не даст медиаплееру возможности подавать вам больше кадров, пока вы обрабатываете старые кадры.

Другие вопросы по тегам