From 6ff776f345007166e86a5ee97c5d198e0849d534 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sun, 29 Jun 2014 23:41:47 +0200 Subject: [PATCH] New camera system, preparation for video --- toxgui.pro | 246 ++++++++++++++++++----------------- widget/camera.cpp | 166 +++++++++++++++++++++++ widget/camera.h | 47 +++++++ widget/form/settingsform.cpp | 5 +- widget/form/settingsform.h | 1 - widget/selfcamview.cpp | 73 ++++------- widget/selfcamview.h | 24 ++-- widget/videosurface.cpp | 87 +++++++++++++ widget/videosurface.h | 26 ++++ 9 files changed, 487 insertions(+), 188 deletions(-) create mode 100644 widget/camera.cpp create mode 100644 widget/camera.h create mode 100644 widget/videosurface.cpp create mode 100644 widget/videosurface.h diff --git a/toxgui.pro b/toxgui.pro index fb184c2eb..83896902f 100644 --- a/toxgui.pro +++ b/toxgui.pro @@ -1,121 +1,125 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2014-06-22T14:07:35 -# -#------------------------------------------------- - -QT += core gui multimedia multimediawidgets - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -TARGET = toxgui -TEMPLATE = app - -HEADERS += widget/form/addfriendform.h \ - widget/form/chatform.h \ - widget/form/groupchatform.h \ - widget/form/settingsform.h \ - widget/tool/chattextedit.h \ - widget/tool/copyableelidelabel.h \ - widget/tool/editablelabelwidget.h \ - widget/tool/elidelabel.h \ - widget/tool/esclineedit.h \ - widget/tool/friendrequestdialog.h \ - widget/filetransfertwidget.h \ - widget/friendwidget.h \ - widget/groupwidget.h \ - widget/widget.h \ - friend.h \ - group.h \ - grouplist.h \ - settings.h \ - status.h \ - core.h \ - friendlist.h \ - cdata.h \ - cstring.h \ - audiobuffer.h \ - widget/selfcamview.h - -FORMS += widget.ui - -CONFIG += c++11 - -RESOURCES += \ - res.qrc - -LIBS += -ltoxcore -ltoxav -lsodium - -SOURCES += \ - widget/form/addfriendform.cpp \ - widget/form/chatform.cpp \ - widget/form/groupchatform.cpp \ - widget/form/settingsform.cpp \ - widget/tool/chattextedit.cpp \ - widget/tool/copyableelidelabel.cpp \ - widget/tool/editablelabelwidget.cpp \ - widget/tool/elidelabel.cpp \ - widget/tool/esclineedit.cpp \ - widget/tool/friendrequestdialog.cpp \ - widget/filetransfertwidget.cpp \ - widget/friendwidget.cpp \ - widget/groupwidget.cpp \ - widget/widget.cpp \ - core.cpp \ - friend.cpp \ - friendlist.cpp \ - group.cpp \ - grouplist.cpp \ - main.cpp \ - settings.cpp \ - status.cpp \ - cdata.cpp \ - cstring.cpp \ - audiobuffer.cpp \ - widget/selfcamview.cpp - - - -### EXAMPLE BUILD SETTINGS FOR WINDOWS -#win32: LIBS += -L$$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/ -ltoxcore - -#INCLUDEPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include -#DEPENDPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include - -#win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/toxcore.lib -#else:win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/libtoxcore.a - -#win32: LIBS += -L$$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/ -ltoxav - -#INCLUDEPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include -#DEPENDPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include - -#win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/toxav.lib -#else:win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/libtoxav.a - -#win32: LIBS += -L$$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/ -lvpx - -#INCLUDEPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include -#DEPENDPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include - -#win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/vpx.lib -#else:win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/libvpx.a - - -#win32: LIBS += -L$$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/ -lopus - -#INCLUDEPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include -#DEPENDPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include - -#win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/opus.lib -#else:win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/libopus.a - -#win32: LIBS += -lws2_32 - -#win32: LIBS += -L$$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/ -lsodium - -#INCLUDEPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include -#DEPENDPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include - -#win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/sodium.lib -#else:win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/libsodium.a +#------------------------------------------------- +# +# Project created by QtCreator 2014-06-22T14:07:35 +# +#------------------------------------------------- + +QT += core gui multimedia multimediawidgets + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = toxgui +TEMPLATE = app + +HEADERS += widget/form/addfriendform.h \ + widget/form/chatform.h \ + widget/form/groupchatform.h \ + widget/form/settingsform.h \ + widget/tool/chattextedit.h \ + widget/tool/copyableelidelabel.h \ + widget/tool/editablelabelwidget.h \ + widget/tool/elidelabel.h \ + widget/tool/esclineedit.h \ + widget/tool/friendrequestdialog.h \ + widget/filetransfertwidget.h \ + widget/friendwidget.h \ + widget/groupwidget.h \ + widget/widget.h \ + friend.h \ + group.h \ + grouplist.h \ + settings.h \ + status.h \ + core.h \ + friendlist.h \ + cdata.h \ + cstring.h \ + audiobuffer.h \ + widget/selfcamview.h \ + widget/videosurface.h \ + widget/camera.h + +FORMS += widget.ui + +CONFIG += c++11 + +RESOURCES += \ + res.qrc + +LIBS += -ltoxcore -ltoxav -lsodium -lvpx + +SOURCES += \ + widget/form/addfriendform.cpp \ + widget/form/chatform.cpp \ + widget/form/groupchatform.cpp \ + widget/form/settingsform.cpp \ + widget/tool/chattextedit.cpp \ + widget/tool/copyableelidelabel.cpp \ + widget/tool/editablelabelwidget.cpp \ + widget/tool/elidelabel.cpp \ + widget/tool/esclineedit.cpp \ + widget/tool/friendrequestdialog.cpp \ + widget/filetransfertwidget.cpp \ + widget/friendwidget.cpp \ + widget/groupwidget.cpp \ + widget/widget.cpp \ + core.cpp \ + friend.cpp \ + friendlist.cpp \ + group.cpp \ + grouplist.cpp \ + main.cpp \ + settings.cpp \ + status.cpp \ + cdata.cpp \ + cstring.cpp \ + audiobuffer.cpp \ + widget/selfcamview.cpp \ + widget/videosurface.cpp \ + widget/camera.cpp + + + +### EXAMPLE BUILD SETTINGS FOR WINDOWS +win32: LIBS += -L$$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/ -ltoxcore + +INCLUDEPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include +DEPENDPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include + +win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/toxcore.lib +else:win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/libtoxcore.a + +win32: LIBS += -L$$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/ -ltoxav + +INCLUDEPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include +DEPENDPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include + +win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/toxav.lib +else:win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/libtoxav.a + +win32: LIBS += -L$$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/ -lvpx + +INCLUDEPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include +DEPENDPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include + +win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/vpx.lib +else:win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/libvpx.a + + +win32: LIBS += -L$$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/ -lopus + +INCLUDEPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include +DEPENDPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include + +win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/opus.lib +else:win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/libopus.a + +win32: LIBS += -lws2_32 + +win32: LIBS += -L$$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/ -lsodium + +INCLUDEPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include +DEPENDPATH += $$PWD/../../../../Downloads/libtoxcore-win32-i686/include + +win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/sodium.lib +else:win32-g++: PRE_TARGETDEPS += $$PWD/../../../../Downloads/libtoxcore-win32-i686/lib/libsodium.a diff --git a/widget/camera.cpp b/widget/camera.cpp new file mode 100644 index 000000000..9aee81151 --- /dev/null +++ b/widget/camera.cpp @@ -0,0 +1,166 @@ +#include "camera.h" +#include +#include + +Camera::Camera() + : refcount{0}, camera{new QCamera} +{ + camera->setCaptureMode(QCamera::CaptureVideo); + camera->setViewfinder(this); + + connect(camera, SIGNAL(error(QCamera::Error)), this, SLOT(onCameraError(QCamera::Error))); + + supportedFormats << QVideoFrame::Format_YUV420P << QVideoFrame::Format_YV12 << QVideoFrame::Format_RGB32; +} + +void Camera::suscribe() +{ + if (refcount <= 0) + { + refcount = 1; + camera->start(); + } + else + refcount++; +} + +void Camera::unsuscribe() +{ + refcount--; + + if (refcount <= 0) + { + camera->stop(); + refcount = 0; + } +} + +QVideoFrame Camera::getLastFrame() +{ + return lastFrame; +} + +bool Camera::start(const QVideoSurfaceFormat &format) +{ + if(supportedFormats.contains(format.pixelFormat())) + { + frameFormat = format.pixelFormat(); + QAbstractVideoSurface::start(format); + return true; + } + else + { + QMessageBox::warning(0, "Camera error", "The camera only supports rare video formats, can't use it"); + return false; + } +} + +bool Camera::present(const QVideoFrame &frame) +{ + QVideoFrame frameMap(frame); // Basically a const_cast because shallow copies + frameMap.map(QAbstractVideoBuffer::ReadOnly); + int w = frameMap.width(), h = frameMap.height(); + int bpl = frameMap.bytesPerLine(), size = frameMap.mappedBytes(); + QVideoFrame frameCopy(size, QSize(w, h), bpl, frameMap.pixelFormat()); + frameCopy.map(QAbstractVideoBuffer::WriteOnly); + memcpy(frameCopy.bits(), frameMap.bits(), size); + frameCopy.unmap(); + lastFrame = frameCopy; + frameMap.unmap(); + return true; +} + +QList Camera::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const +{ + if (handleType == QAbstractVideoBuffer::NoHandle) + return supportedFormats; + else + return QList(); +} + +void Camera::onCameraError(QCamera::Error value) +{ + QMessageBox::warning(0,"Camera error",QString("Error %1 : %2") + .arg(value).arg(camera->errorString())); +} + +bool Camera::isFormatSupported(const QVideoSurfaceFormat& format) const +{ + if (format.pixelFormat() == 0) + { + //QMessageBox::warning(0, "Camera eror","The camera's video format is not supported !"); + return QAbstractVideoSurface::isFormatSupported(format); + } + else if(supportedFormats.contains(format.pixelFormat())) + { + return true; + } + else + { + QMessageBox::warning(0, "Camera eror", + QString("Camera format %1 not supported, can't use the camera") + .arg(format.pixelFormat())); + return false; + } +} + + +QImage Camera::getLastImage() +{ + lastFrame.map(QAbstractVideoBuffer::ReadOnly); + int w = lastFrame.width(), h = lastFrame.height(); + int bpl = lastFrame.bytesPerLine(), cxbpl = bpl/2; + QImage img(w, h, QImage::Format_RGB32); + + if (frameFormat == QVideoFrame::Format_YUV420P) + { + uint8_t* yData = lastFrame.bits(); + uint8_t* uData = yData + (bpl * h); + uint8_t* vData = uData + (bpl * h / 4); + for (int i = 0; i< h; i++) + { + uint32_t* scanline = (uint32_t*)img.scanLine(i); + for (int j=0; j < bpl; j++) + { + float Y = yData[i*bpl + j]; + float U = uData[i*cxbpl/2 + j/2]; + float V = vData[i*cxbpl/2 + j/2]; + + uint8_t R = qMax(qMin((int)(Y + 1.402 * (V - 128)),255),0); + uint8_t G = qMax(qMin((int)(Y - 0.344 * (U - 128) - 0.714 * (V - 128)),255),0); + uint8_t B = qMax(qMin((int)(Y + 1.772 * (U - 128)),255),0); + + scanline[j] = (0xFF<<24) + (R<<16) + (G<<8) + B; + } + } + } + else if (frameFormat == QVideoFrame::Format_YV12) + { + uint8_t* yData = lastFrame.bits(); + uint8_t* vData = yData + (bpl * h); + uint8_t* uData = vData + (bpl * h / 4); + for (int i = 0; i< h; i++) + { + uint32_t* scanline = (uint32_t*)img.scanLine(i); + for (int j=0; j < bpl; j++) + { + float Y = yData[i*bpl + j]; + float U = uData[i*cxbpl/2 + j/2]; + float V = vData[i*cxbpl/2 + j/2]; + + uint8_t R = qMax(qMin((int)(Y + 1.402 * (V - 128)),255),0); + uint8_t G = qMax(qMin((int)(Y - 0.344 * (U - 128) - 0.714 * (V - 128)),255),0); + uint8_t B = qMax(qMin((int)(Y + 1.772 * (U - 128)),255),0); + + scanline[j] = (0xFF<<24) + (R<<16) + (G<<8) + B; + } + } + } + else if (frameFormat == QVideoFrame::Format_RGB32) + { + memcpy(img.bits(), lastFrame.bits(), bpl*h); + } + + lastFrame.unmap(); + return img; +} diff --git a/widget/camera.h b/widget/camera.h new file mode 100644 index 000000000..8c51fa4c5 --- /dev/null +++ b/widget/camera.h @@ -0,0 +1,47 @@ +#ifndef CAMERA_H +#define CAMERA_H + +#include +#include +#include +#include "vpx/vpx_image.h" + +/** + * This class is a wrapper to share a camera's captured video frames + * In Qt cameras normally only send their frames to a single output at a time + * So you can't, for example, send the frames over the network + * and output them to a widget on the screen at the same time + * + * Instead this class allows objects to surscribe and unsuscribe, starting + * the camera only when needed, and giving access to the last frame + **/ + +class Camera : private QAbstractVideoSurface +{ + Q_OBJECT +public: + Camera(); + void suscribe(); ///< Call this once before trying to get frames + void unsuscribe(); ///< Call this once when you don't need frames anymore + QVideoFrame getLastFrame(); ///< Get the last captured frame + QImage getLastImage(); ///< Convert the last frame to a QImage (can be expensive !) + vpx_image getLastVPXImage(); ///< Convert the last frame to a vpx_image (can be expensive !) + bool isFormatSupported(const QVideoSurfaceFormat & format) const; + +private slots: + void onCameraError(QCamera::Error value); + +private: + bool start(const QVideoSurfaceFormat &format); + bool present(const QVideoFrame &frame); + QList supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const; + +private: + int refcount; ///< Number of users suscribed to the camera + QCamera *camera; + QVideoFrame lastFrame; + int frameFormat; + QList supportedFormats; +}; + +#endif // CAMERA_H diff --git a/widget/form/settingsform.cpp b/widget/form/settingsform.cpp index fec9b865e..e8a0150d5 100644 --- a/widget/form/settingsform.cpp +++ b/widget/form/settingsform.cpp @@ -1,4 +1,5 @@ #include "settingsform.h" +#include "widget/widget.h" #include SettingsForm::SettingsForm() @@ -17,7 +18,6 @@ SettingsForm::SettingsForm() id.setFont(small); id.setTextInteractionFlags(Qt::TextSelectableByMouse); - camview = new SelfCamView(); videoTest.setText("Test video"); main->setLayout(&layout); @@ -38,7 +38,6 @@ SettingsForm::SettingsForm() SettingsForm::~SettingsForm() { - delete camview; } void SettingsForm::setFriendAddress(const QString& friendAddress) @@ -58,5 +57,5 @@ void SettingsForm::show(Ui::Widget &ui) void SettingsForm::onTestVideoClicked() { - camview->show(); + Widget::getInstance()->showTestCamview(); } diff --git a/widget/form/settingsform.h b/widget/form/settingsform.h index fc10a4ecd..e9b2ffb10 100644 --- a/widget/form/settingsform.h +++ b/widget/form/settingsform.h @@ -30,7 +30,6 @@ private: QPushButton videoTest; QVBoxLayout layout, headLayout; QWidget *main, *head; - SelfCamView* camview; public: QLineEdit name, statusText; diff --git a/widget/selfcamview.cpp b/widget/selfcamview.cpp index 9ee317ba5..3ddaf8ff0 100644 --- a/widget/selfcamview.cpp +++ b/widget/selfcamview.cpp @@ -3,78 +3,49 @@ #include #include #include +#include -SelfCamView::SelfCamView(QWidget* parent) - : QWidget(parent), camera(nullptr), mainLayout{new QHBoxLayout()} +#include "videosurface.h" +#include "widget.h" + +SelfCamView::SelfCamView(Camera* Cam, QWidget* parent) + : QWidget(parent), displayLabel{new QLabel}, + mainLayout{new QHBoxLayout()}, cam(Cam) { setLayout(mainLayout); setWindowTitle("Tox video test"); setMinimumSize(320,240); - QByteArray cameraDevice; + updateDisplayTimer.setInterval(75); + updateDisplayTimer.setSingleShot(false); - /* - QActionGroup *videoDevicesGroup = new QActionGroup(this); - videoDevicesGroup->setExclusive(true); - foreach(const QByteArray &deviceName, QCamera::availableDevices()) { - QString description = camera->deviceDescription(deviceName); - QAction *videoDeviceAction = new QAction(description, videoDevicesGroup); - videoDeviceAction->setCheckable(true); - videoDeviceAction->setData(QVariant(deviceName)); - if (cameraDevice.isEmpty()) { - cameraDevice = deviceName; - videoDeviceAction->setChecked(true); - } - ui->menuDevices->addAction(videoDeviceAction); - } + displayLabel->setScaledContents(true); - connect(videoDevicesGroup, SIGNAL(triggered(QAction*)), SLOT(updateCameraDevice(QAction*))); - */ + mainLayout->addWidget(displayLabel); - viewfinder = new QCameraViewfinder(this); - mainLayout->addWidget(viewfinder); - viewfinder->show(); - - setCamera(cameraDevice); + connect(&updateDisplayTimer, SIGNAL(timeout()), this, SLOT(updateDisplay())); } SelfCamView::~SelfCamView() { - delete camera; -} - -void SelfCamView::setCamera(const QByteArray &cameraDevice) -{ - delete camera; - - if (cameraDevice.isEmpty()) - camera = new QCamera; - else - camera = new QCamera(cameraDevice); - - //connect(camera, SIGNAL(stateChanged(QCamera::State)), this, SLOT(updateCameraState(QCamera::State))); - connect(camera, SIGNAL(error(QCamera::Error)), this, SLOT(displayCameraError())); - - camera->setViewfinder(viewfinder); - - //updateCameraState(camera->state()); - - camera->setCaptureMode(QCamera::CaptureVideo); -} - -void SelfCamView::displayCameraError() -{ - QMessageBox::warning(this, tr("Camera error"), camera->errorString()); } void SelfCamView::closeEvent(QCloseEvent* event) { - camera->stop(); + cam->unsuscribe(); + updateDisplayTimer.stop(); event->accept(); } void SelfCamView::showEvent(QShowEvent* event) { - camera->start(); + cam->suscribe(); + updateDisplayTimer.start(); event->accept(); } + +void SelfCamView::updateDisplay() +{ + displayLabel->setPixmap(QPixmap::fromImage(cam->getLastImage())); +} + diff --git a/widget/selfcamview.h b/widget/selfcamview.h index 56649e3f1..b7adadedd 100644 --- a/widget/selfcamview.h +++ b/widget/selfcamview.h @@ -1,37 +1,37 @@ #ifndef SELFCAMVIEW_H #define SELFCAMVIEW_H -#include -#include -#include #include -#include -#include #include +#include +#include +#include "camera.h" class QCloseEvent; class QShowEvent; +class QPainter; class SelfCamView : public QWidget { Q_OBJECT public: - SelfCamView(QWidget *parent=0); + SelfCamView(Camera* Cam, QWidget *parent=0); ~SelfCamView(); +private slots: + void updateDisplay(); + private: void closeEvent(QCloseEvent*); void showEvent(QShowEvent*); - -private slots: - void setCamera(const QByteArray &cameraDevice); - void displayCameraError(); + void paint(QPainter *painter); private: - QCamera *camera; - QCameraViewfinder* viewfinder; + QLabel *displayLabel; QHBoxLayout* mainLayout; + Camera* cam; + QTimer updateDisplayTimer; }; #endif // SELFCAMVIEW_H diff --git a/widget/videosurface.cpp b/widget/videosurface.cpp new file mode 100644 index 000000000..4803452c2 --- /dev/null +++ b/widget/videosurface.cpp @@ -0,0 +1,87 @@ +#include "videosurface.h" +#include "core.h" +#include +#include + +VideoSurface::VideoSurface() + : QAbstractVideoSurface() +{ + vpx_img_alloc(&input, VPX_IMG_FMT_YV12, TOXAV_VIDEO_WIDTH, TOXAV_VIDEO_HEIGHT, 1); +} + +bool VideoSurface::start(const QVideoSurfaceFormat &format) +{ + mVideoFormat = format; + //start only if format is UYVY, dont handle other format now + if( format.pixelFormat() == QVideoFrame::Format_YV12 ){ + QAbstractVideoSurface::start(format); + return true; + } else { + return false; + } +} + +bool VideoSurface::present(const QVideoFrame &frame) +{ + /* + mFrame = frame; + + qDebug() << QString("Video: Frame format is %1").arg(mFrame.pixelFormat()); + + stop(); + + //this is necessary to get valid data from frame + mFrame.map(QAbstractVideoBuffer::ReadOnly); + + uchar* data = new uchar[frame.mappedBytes()]; + memcpy(data, frame.bits(), frame.mappedBytes()); + + input.planes[VPX_PLANE_Y] = data; + input.planes[VPX_PLANE_U] = data + (frame.bytesPerLine() * frame.height()); + input.planes[VPX_PLANE_V] = input.planes[VPX_PLANE_U] + (frame.bytesPerLine()/2 * frame.height()/2); + input.planes[VPX_PLANE_ALPHA] = nullptr; + + //qDebug() << QString("Got %1 bytes, first plane is %2 bytes long") + // .arg(frame.mappedBytes()).arg(frame.bytesPerLine() * frame.height()); + + // Slots MUST be called with a direct or blocking connection, or input may die before they return ! + emit videoFrameReady(input); + + + QImage lastImage( mFrame.size(), QImage::Format_RGB16); + const uchar *src = mFrame.bits(); + uchar *dst = lastImage.bits(); + const int srcLineStep = mFrame.bytesPerLine(); + const int dstLineStep = lastImage.bytesPerLine(); + const int h = mFrame.height(); + const int w = mFrame.width(); + + for (int y=0; y < h; y++) { + //this function you can find in qgraphicsvideoitem_maemo5.cpp, + //link is mentioned above + uyvy422_to_rgb16_line_neon(dst, src, w); + src += srcLineStep; + dst += dstLineStep; + } + + mLastFrame = QPixmap::fromImage(lastImage); + //emit signal, other can handle it and do necessary processing + emit frameUpdated(mLastFrame); + + delete[] data; + mFrame.unmap(); + +*/ + return true; +} + +QList VideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const +{ + if (handleType == QAbstractVideoBuffer::NoHandle) { + qDebug() << "Video: No handle"; + return QList() << QVideoFrame::Format_YV12; + } else { + qDebug() << "Video: Handle type is not NoHandle"; + return QList(); + } +} diff --git a/widget/videosurface.h b/widget/videosurface.h new file mode 100644 index 000000000..3e3a770d8 --- /dev/null +++ b/widget/videosurface.h @@ -0,0 +1,26 @@ +#ifndef VIDEOSURFACE_H +#define VIDEOSURFACE_H + +#include +#include +#include "vpx/vpx_image.h" + +class VideoSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + VideoSurface(); + bool start(const QVideoSurfaceFormat &format); + bool present(const QVideoFrame &frame); + QList supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const; + +signals: + // Slots MUST be called with a direct or blocking connection, or img may die before they return ! + void videoFrameReady(vpx_image img); + +private: + QVideoSurfaceFormat mVideoFormat; + vpx_image_t input; +}; + +#endif // VIDEOSURFACE_H