mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
New camera system, preparation for video
This commit is contained in:
parent
a2566d4183
commit
6ff776f345
246
toxgui.pro
246
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
|
||||
|
|
166
widget/camera.cpp
Normal file
166
widget/camera.cpp
Normal file
|
@ -0,0 +1,166 @@
|
|||
#include "camera.h"
|
||||
#include <QVideoSurfaceFormat>
|
||||
#include <QMessageBox>
|
||||
|
||||
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<QVideoFrame::PixelFormat> Camera::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
|
||||
{
|
||||
if (handleType == QAbstractVideoBuffer::NoHandle)
|
||||
return supportedFormats;
|
||||
else
|
||||
return QList<QVideoFrame::PixelFormat>();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
47
widget/camera.h
Normal file
47
widget/camera.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef CAMERA_H
|
||||
#define CAMERA_H
|
||||
|
||||
#include <QCamera>
|
||||
#include <QVideoFrame>
|
||||
#include <QAbstractVideoSurface>
|
||||
#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<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
|
||||
|
||||
private:
|
||||
int refcount; ///< Number of users suscribed to the camera
|
||||
QCamera *camera;
|
||||
QVideoFrame lastFrame;
|
||||
int frameFormat;
|
||||
QList<QVideoFrame::PixelFormat> supportedFormats;
|
||||
};
|
||||
|
||||
#endif // CAMERA_H
|
|
@ -1,4 +1,5 @@
|
|||
#include "settingsform.h"
|
||||
#include "widget/widget.h"
|
||||
#include <QFont>
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ private:
|
|||
QPushButton videoTest;
|
||||
QVBoxLayout layout, headLayout;
|
||||
QWidget *main, *head;
|
||||
SelfCamView* camview;
|
||||
|
||||
public:
|
||||
QLineEdit name, statusText;
|
||||
|
|
|
@ -3,78 +3,49 @@
|
|||
#include <QMessageBox>
|
||||
#include <QCloseEvent>
|
||||
#include <QShowEvent>
|
||||
#include <QVideoFrame>
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,37 +1,37 @@
|
|||
#ifndef SELFCAMVIEW_H
|
||||
#define SELFCAMVIEW_H
|
||||
|
||||
#include <QCamera>
|
||||
#include <QCameraImageCapture>
|
||||
#include <QMediaRecorder>
|
||||
#include <QWidget>
|
||||
#include <QVideoWidget>
|
||||
#include <QCameraViewfinder>
|
||||
#include <QHBoxLayout>
|
||||
#include <QTimer>
|
||||
#include <QLabel>
|
||||
#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
|
||||
|
|
87
widget/videosurface.cpp
Normal file
87
widget/videosurface.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
#include "videosurface.h"
|
||||
#include "core.h"
|
||||
#include <QVideoFrame>
|
||||
#include <QDebug>
|
||||
|
||||
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<QVideoFrame::PixelFormat> VideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
|
||||
{
|
||||
if (handleType == QAbstractVideoBuffer::NoHandle) {
|
||||
qDebug() << "Video: No handle";
|
||||
return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_YV12;
|
||||
} else {
|
||||
qDebug() << "Video: Handle type is not NoHandle";
|
||||
return QList<QVideoFrame::PixelFormat>();
|
||||
}
|
||||
}
|
26
widget/videosurface.h
Normal file
26
widget/videosurface.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef VIDEOSURFACE_H
|
||||
#define VIDEOSURFACE_H
|
||||
|
||||
#include <QAbstractVideoSurface>
|
||||
#include <QVideoSurfaceFormat>
|
||||
#include "vpx/vpx_image.h"
|
||||
|
||||
class VideoSurface : public QAbstractVideoSurface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
VideoSurface();
|
||||
bool start(const QVideoSurfaceFormat &format);
|
||||
bool present(const QVideoFrame &frame);
|
||||
QList<QVideoFrame::PixelFormat> 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
|
Loading…
Reference in New Issue
Block a user