...
 
Commits (4)
......@@ -14,7 +14,7 @@ QT_BEGIN_NAMESPACE
UVCCameraService::UVCCameraService(QObject *parent):
QMediaService(parent)
, m_videoRenderer(NULL)
, m_videoRenderer(nullptr)
{
m_session = new UVCCameraSession(this);
m_control = new UVCCameraControl(m_session);
......@@ -61,14 +61,14 @@ QMediaControl* UVCCameraService::requestControl(const char *name)
if (qstrcmp(name, QCameraExposureControl_iid) == 0)
return m_cameraExposureControl;
return NULL;
return nullptr;
}
void UVCCameraService::releaseControl(QMediaControl *control)
{
if (control == m_videoRenderer) {
delete m_videoRenderer;
m_videoRenderer = NULL;
m_videoRenderer = nullptr;
return;
}
}
......
......@@ -12,13 +12,13 @@ QMutex UVCCameraSession::devicesMutex;
UVCCameraSession::UVCCameraSession(QObject *parent)
: QObject(parent),
m_surface(Q_NULLPTR),
streaming(false),
bandwidthFactor(1.3f),
interval(0),
ctx(NULL),
dev(NULL),
devh(NULL)
bandwidthFactor(1.3f),
m_surface(Q_NULLPTR),
ctx(nullptr),
dev(nullptr),
devh(nullptr)
{
DefaultParameters tmp;
......@@ -51,7 +51,7 @@ UVCCameraSession::UVCCameraSession(QObject *parent)
tmp.saturation = 0.46875;
tmp.white_balance = 0.486486;
tmp.sharpness = 0.333333;
tmp.backlight_compensation = 0.5;
tmp.backlight_compensation = 1.0;
tmp.gamma = 0.0654206;
tmp.gain = 0;
tmp.exposure_abs = 0.0312062;
......@@ -72,7 +72,7 @@ UVCCameraSession::UVCCameraSession(QObject *parent)
tmp.saturation = 0;
tmp.white_balance = 0.486486;
tmp.sharpness = 0.166667;
tmp.backlight_compensation = 40.3333;
tmp.backlight_compensation = 1.0;
tmp.gamma = 0.5;
tmp.gain = 0;
tmp.exposure_abs = 1;
......@@ -105,10 +105,10 @@ bool UVCCameraSession::setDevice(const QString &device)
uvc_error_t res;
if (!ctx) {
res = uvc_init(&ctx, NULL);
res = uvc_init(&ctx, nullptr);
if (res < 0) {
qWarning() << "uvc_init" << uvc_strerror(res);
ctx = NULL;
ctx = nullptr;
return false;
}
}
......@@ -126,7 +126,7 @@ bool UVCCameraSession::setDevice(const QString &device)
while (1) {
dev = devList[idx];
idx++;
if (dev == NULL)
if (dev == nullptr)
break;
uvc_device_descriptor_t *desc;
res = uvc_get_device_descriptor(dev, &desc);
......@@ -158,7 +158,38 @@ void UVCCameraSession::setSurface(QAbstractVideoSurface* surface)
void cb(uvc_frame_t *frame, void *ptr) { if (ptr && frame) static_cast<UVCCameraSession*>(ptr)->callback(frame); }
void UVCCameraSession::callback(uvc_frame_t *frame)
{
qreal t = frameReference.elapsed();
qreal t = 1e-6 * frameReference.nsecsElapsed();
sw.update(t);
hw.update(1e3*frame->capture_time.tv_sec + 1e-3*frame->capture_time.tv_usec); // use libuvc timestamp instead of our own
hybrid.update(t);
hybrid.correct(hw, settings.maximumFrameRate());
/* TODO:
*
* Consider changing the time reference here when hybrid has been tested.
* For now, we just export delta t (dt)
*
* 1) SW only.
* Pros: does not drift (same source as EyeRecToo).
* Cons: unprecise.
*
* t = sw.cur;
*
* 2) HW only.
* Pros: precise (after libuvc fix; seehttps://github.com/pupil-labs/libuvc/commit/ec5837e538aad0357c22a806eb8ea40ff73e6a33)
* Cons: drifts!
*
* t = hw.cur;
*
* 3) Hybrid.
* Pros: shouldn't drift, precise.
* Cons: Untested!
*
* t = hybrid.cur;
*
*/
if (!streaming)
return;
......@@ -168,20 +199,25 @@ void UVCCameraSession::callback(uvc_frame_t *frame)
QVideoFrame qFrame;
switch(frame->frame_format) {
case UVC_FRAME_FORMAT_MJPEG:
qFrame = QVideoFrame( (int) frame->data_bytes, QSize(frame->width, frame->height), 0, QVideoFrame::Format_Jpeg);
qFrame = QVideoFrame( static_cast<int>(frame->data_bytes), QSize(frame->width, frame->height), 0, QVideoFrame::Format_Jpeg);
qFrame.map(QAbstractVideoBuffer::WriteOnly);
memcpy( qFrame.bits(), frame->data, frame->data_bytes); // copied; safe to retun from callback now
qFrame.unmap();
break;
case UVC_FRAME_FORMAT_YUYV:
qFrame = QVideoFrame( (int) frame->data_bytes, QSize(frame->width, frame->height), 0, QVideoFrame::Format_YUYV);
qFrame = QVideoFrame( static_cast<int>(frame->data_bytes), QSize(frame->width, frame->height), 0, QVideoFrame::Format_YUYV);
qFrame.map(QAbstractVideoBuffer::WriteOnly);
memcpy( qFrame.bits(), frame->data, frame->data_bytes); // copied; safe to retun from callback now
qFrame.unmap();
break;
default:
return;
}
return;
}
// Meta data
qFrame.setMetaData("timestamp", t);
qFrame.setMetaData("dt", hybrid.isp);
#ifdef BLOCKING_FRAME_GRABBING
m_surface->present( qFrame );
#else
......@@ -192,12 +228,11 @@ void UVCCameraSession::callback(uvc_frame_t *frame)
void UVCCameraSession::presentFrame(QVideoFrame frame, const qreal t)
{
qreal latency = frameReference.elapsed() - t;
frame.setMetaData("timestamp", t);
if (latency <= MAX_LATENCY_MS && m_surface)
(void) t;
if (m_surface)
m_surface->present(frame);
//else
// qWarning() << "Dropping frame (" << latency << "ms old )";
//else
// qWarning() << "Dropping frame (" << latency << "ms old )";
}
template<typename T> bool set(const QSettings *settings, const QString key, T &v)
......@@ -222,7 +257,7 @@ bool UVCCameraSession::load()
res = uvc_open(dev, &devh);
if (res != UVC_SUCCESS) {
qWarning() << "uvc_open" << uvc_strerror(res);
devh = NULL;
devh = nullptr;
return false;
}
......@@ -242,7 +277,7 @@ bool UVCCameraSession::unload()
if (devh)
uvc_close(devh);
devh = NULL;
devh = nullptr;
m_supportedViewfinderSettings.clear();
return true;
......@@ -252,12 +287,12 @@ void concurrentCustomCallback(UVCCameraSession *session)
{
QMutexLocker getFrameLocker( &session->getFrameMutex );
while (session->streaming) {
if (session->strmh == NULL)
if (session->strmh == nullptr)
continue;
uvc_frame_t *frame = NULL;
uvc_frame_t *frame = nullptr;
uvc_error_t res;
res = uvc_stream_get_frame(session->strmh, &frame, 0);
if ( res == UVC_SUCCESS && frame != NULL)
if ( res == UVC_SUCCESS && frame != nullptr)
session->callback(frame);
else
if (res != UVC_ERROR_TIMEOUT)
......@@ -297,9 +332,9 @@ bool UVCCameraSession::startPreview()
}
#ifdef USE_CUSTOM_CALLBACK
res = uvc_stream_start(strmh, NULL, (void*) this, getBandwidthFactor(), 0);
res = uvc_stream_start(strmh, nullptr, (void*) this, getBandwidthFactor(), 0);
#else
res = uvc_stream_start(strmh, cb, (void*) this, getBandwidthFactor(), 0);
res = uvc_stream_start(strmh, cb, static_cast<void*>(this), getBandwidthFactor(), 0);
#endif
if (res != UVC_SUCCESS) {
qWarning() << "uvc_stream_start" << uvc_strerror(res);
......@@ -315,7 +350,7 @@ bool UVCCameraSession::startPreview()
return true;
}
double UVCCameraSession::getBandwidthFactor()
float UVCCameraSession::getBandwidthFactor()
{
switch(settings.pixelFormat()) {
// compressed; user can change it through the default settings
......@@ -348,19 +383,19 @@ void UVCCameraSession::updateSourceCapabilities()
return;
const uvc_format_desc_t* formatDesc = uvc_get_format_descs(devh);
while (formatDesc != NULL) {
while (formatDesc != nullptr) {
QVideoFrame::PixelFormat qFormat;
QString formatStr;
switch (formatDesc->bDescriptorSubtype) {
case UVC_VS_FORMAT_MJPEG:
qFormat = QVideoFrame::Format_Jpeg;
break;
case UVC_VS_FORMAT_UNCOMPRESSED:
qFormat = fourcc2PixelFormat(formatDesc->fourccFormat, QString());
qFormat = fourcc2PixelFormat(formatDesc->fourccFormat, formatStr);
if ( qFormat != QVideoFrame::Format_Invalid )
break;
default: // format not supported, next!
QString formatStr;
qFormat = fourcc2PixelFormat(formatDesc->fourccFormat, formatStr);
qInfo() << "UVCEngine: format not supported:" << formatDesc->bDescriptorSubtype << formatStr;
formatDesc = formatDesc->next;
......@@ -368,7 +403,7 @@ void UVCCameraSession::updateSourceCapabilities()
}
const uvc_frame_desc *frameDesc = formatDesc->frame_descs;
while (frameDesc!=NULL) {
while (frameDesc!=nullptr) {
QCameraViewfinderSettings settings;
settings.setResolution(frameDesc->wWidth, frameDesc->wHeight);
settings.setPixelAspectRatio(frameDesc->wWidth, frameDesc->wHeight);
......@@ -405,7 +440,7 @@ bool UVCCameraSession::stopPreview()
if (res != UVC_SUCCESS && res != UVC_ERROR_INVALID_PARAM)
qWarning() << "uvc_stream_stop" << uvc_strerror(res);
uvc_stream_close(strmh);
strmh = NULL;
strmh = nullptr;
frameReference.invalidate();
return true;
......@@ -651,16 +686,16 @@ void UVCCameraSession::setDefaultParameters()
settings.setValue("hue_auto", par.hue_auto);
// and set them to the device
uvc_set(devh, uvc_set_brightness, par.brightness, uvc_get_brightness);
uvc_set(devh, uvc_set_contrast, par.contrast, uvc_get_contrast);
uvc_set(devh, uvc_set_saturation, par.saturation, uvc_get_saturation);
uvc_set(devh, uvc_set_white_balance_temperature, par.white_balance, uvc_get_white_balance_temperature);
uvc_set(devh, uvc_set_sharpness, par.sharpness, uvc_get_sharpness);
uvc_set(devh, uvc_set_backlight_compensation, par.backlight_compensation, uvc_get_backlight_compensation);
uvc_set(devh, uvc_set_gamma, par.gamma, uvc_get_gamma);
uvc_set(devh, uvc_set_gain, par.gain, uvc_get_gain);
uvc_set(devh, uvc_set_exposure_abs, par.exposure_abs, uvc_get_exposure_abs);
uvc_set(devh, uvc_set_hue, par.hue, uvc_get_hue);
uvc_set(devh, uvc_set_brightness, par.brightness, uvc_get_brightness, "brightness");
uvc_set(devh, uvc_set_contrast, par.contrast, uvc_get_contrast, "contrast");
uvc_set(devh, uvc_set_saturation, par.saturation, uvc_get_saturation, "saturation");
uvc_set(devh, uvc_set_white_balance_temperature, par.white_balance, uvc_get_white_balance_temperature, "white_balance_temperature");
uvc_set(devh, uvc_set_sharpness, par.sharpness, uvc_get_sharpness, "sharpness");
uvc_set(devh, uvc_set_backlight_compensation, par.backlight_compensation, uvc_get_backlight_compensation, "backlight_compensation");
uvc_set(devh, uvc_set_gamma, par.gamma, uvc_get_gamma, "gamma");
uvc_set(devh, uvc_set_gain, par.gain, uvc_get_gain, "gain");
uvc_set(devh, uvc_set_exposure_abs, par.exposure_abs, uvc_get_exposure_abs, "exposure_abs");
uvc_set(devh, uvc_set_hue, par.hue, uvc_get_hue, "hue");
uvc_set_mode(devh, uvc_set_ae_mode, par.ae_mode);
uvc_set_mode(devh, uvc_set_ae_priority, par.ae_priority);
uvc_set_mode(devh, uvc_set_contrast_auto, par.contrast_auto);
......
......@@ -28,6 +28,34 @@ QT_BEGIN_NAMESPACE
// Maximum acceptable latency for calling the surface present method
#define MAX_LATENCY_MS 1.0e3/25
class Timing {
public:
Timing() :
cur(0),
prev(0),
isp(0)
{}
void update(const qreal &t) {
prev = cur;
cur = t;
isp = cur - prev;
}
void correct(const Timing &other, const qreal &fps) {
qreal period = 1.0e3 / fps;
qreal diff = isp - period;
qreal otherDiff = other.isp - period;
if ( qAbs(diff) > qAbs(otherDiff) ) {
cur += otherDiff - diff;
isp = cur - prev;
}
}
qreal cur; // current
qreal prev; // previous
qreal isp; // inter-sample period
};
struct DefaultParameters {
double bandwidthFactor;
double brightness;
......@@ -118,13 +146,15 @@ public:
void uvc_set( uvc_device_handle_t *devh,
uvc_error_t (*set)( uvc_device_handle_t *, T),
QVariant val,
uvc_error_t (*get)( uvc_device_handle_t *, T *, enum uvc_req_code)
uvc_error_t (*get)( uvc_device_handle_t *, T *, enum uvc_req_code),
const QString msg = ""
) {
T mn, mx;
get(devh, &mn, UVC_GET_MIN);
get(devh, &mx, UVC_GET_MAX);
double value = val.toDouble();
value = value * (mx - mn ) + mn;
//qDebug() << msg << mn << value << mx;
set(devh, static_cast<T>(value));
}
template<typename T>
......@@ -170,20 +200,24 @@ private:
QVideoFrame currentFrame;
unsigned char* yuvBuffer;
long unsigned int yuvBufferSize;
QElapsedTimer frameReference;
QElapsedTimer frameReference;
Timing sw;
Timing hw;
Timing hybrid;
// capabilities
QList<QCameraViewfinderSettings> m_supportedViewfinderSettings;
void updateSourceCapabilities();
QCameraViewfinderSettings settings;
bool qPixelFormat2UVCFrameFormat(const QVideoFrame::PixelFormat &qFormat, uvc_frame_format &uvcFormat);
double getBandwidthFactor();
float getBandwidthFactor();
static QMutex sessionMutex;
// device availability
static QMap<QString,bool> devices;
static QMutex UVCCameraSession::devicesMutex;
static QMutex devicesMutex;
bool acquire(const QString &device);
void release(const QString &device);
......@@ -192,10 +226,10 @@ private:
QVideoFrame::PixelFormat fourcc2PixelFormat(const uint8_t *fourcc, QString &str) {
str = QString("%1%2%3%4").arg(
(char) fourcc[0]).arg(
(char) fourcc[1]).arg(
(char) fourcc[2]).arg(
(char) fourcc[3]);
static_cast<char>(fourcc[0])).arg(
static_cast<char>(fourcc[1])).arg(
static_cast<char>(fourcc[2])).arg(
static_cast<char>(fourcc[3]));
if ( str.compare("yuyv", Qt::CaseInsensitive) == 0 )
return QVideoFrame::Format_YUYV;
if ( str.compare("yuy2", Qt::CaseInsensitive) == 0 ) // duplicate of yuyv http://www.fourcc.org/pixel-format/yuv-yuy2/
......
......@@ -105,3 +105,14 @@ unix:{
LIBS += -lpthread
LIBS += -lusb-1.0
}
system("git --version"):{
GIT_BRANCH=$$system(git rev-parse --abbrev-ref HEAD)
GIT_COMMIT_HASH=$$system(git rev-parse --short HEAD)
} else {
GIT_BRANCH="unknown"
GIT_COMMIT_HASH="unknown"
}
DEFINES += VERSION=\\\"$$VERSION\\\"
DEFINES += GIT_BRANCH=\\\"$$GIT_BRANCH\\\"
DEFINES += GIT_COMMIT_HASH=\\\"$$GIT_COMMIT_HASH\\\"
......@@ -2,9 +2,9 @@
QMediaService* UVCServicePlugin::create(const QString &key)
{
if (key == Q_MEDIASERVICE_CAMERA)
return new UVCCameraService();
return NULL;
if (key == Q_MEDIASERVICE_CAMERA)
return new UVCCameraService();
return nullptr;
}
void UVCServicePlugin::release(QMediaService *service)
......
......@@ -4,20 +4,19 @@ QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(QList<UVCVideoDeviceInfo>, deviceList)
bool UVCVideoDeviceControl::loaded = false;
bool UVCVideoDeviceControl::printVersion = true;
UVCVideoDeviceControl::UVCVideoDeviceControl(QObject *parent)
: QVideoDeviceSelectorControl(parent),
ctx(NULL),
selected(0)
selected(0),
ctx(nullptr)
{
if (printVersion) {
qInfo() << QString("uvcengine version: %1 %2").arg(GIT_BRANCH).arg(GIT_COMMIT_HASH);
printVersion = false;
}
m_session = qobject_cast<UVCCameraSession*>(parent);
updateDevices();
if (!loaded) {
loaded = true;
qInfo() << "Loaded uvcengine!";
}
}
UVCVideoDeviceControl::~UVCVideoDeviceControl()
......@@ -89,7 +88,7 @@ void UVCVideoDeviceControl::updateDevices()
uvc_error_t res;
uvc_context_t *ctx;
res = uvc_init(&ctx, NULL);
res = uvc_init(&ctx, nullptr);
if (res < 0) {
qWarning() << "uvc_init" << uvc_strerror(res);
return ;
......@@ -106,7 +105,7 @@ void UVCVideoDeviceControl::updateDevices()
while (1) {
uvc_device_t *dev = devList[idx];
idx++;
if (dev == NULL)
if (dev == nullptr)
break;
uvc_device_descriptor_t *desc;
res = uvc_get_device_descriptor(dev, &desc);
......
......@@ -33,12 +33,13 @@ public Q_SLOTS:
void setSelectedDevice(int index);
private:
static bool printVersion;
static void updateDevices();
UVCCameraSession* m_session;
int selected;
uvc_context_t* ctx;
static bool loaded;
};
QT_END_NAMESPACE
......
......@@ -4,7 +4,7 @@ QT_BEGIN_NAMESPACE
UVCVideoRendererControl::UVCVideoRendererControl(UVCCameraSession* session, QObject *parent)
:QVideoRendererControl(parent),
m_surface(NULL),
m_surface(nullptr),
m_session(session)
{
}
......