diff --git a/uvcengine/uvccameraservice.cpp b/uvcengine/uvccameraservice.cpp index 74effe2ba76145164a37bf685fbd1a8d50930a90..312d9102e91bc6f021cb7e7a9943d8837d000a4b 100644 --- a/uvcengine/uvccameraservice.cpp +++ b/uvcengine/uvccameraservice.cpp @@ -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; } } diff --git a/uvcengine/uvccamerasession.cpp b/uvcengine/uvccamerasession.cpp index 2730524f0568c0d8b155cc16bffb7fcb81858dbd..1e6df21023a8ed263322a5fbb6e91f3902df1f31 100644 --- a/uvcengine/uvccamerasession.cpp +++ b/uvcengine/uvccamerasession.cpp @@ -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; @@ -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,8 +158,13 @@ void UVCCameraSession::setSurface(QAbstractVideoSurface* surface) void cb(uvc_frame_t *frame, void *ptr) { if (ptr && frame) static_cast(ptr)->callback(frame); } void UVCCameraSession::callback(uvc_frame_t *frame) { - //qreal t = frameReference.elapsed(); - qreal t = 1e3*frame->capture_time.tv_sec + 1e-3*frame->capture_time.tv_usec; // use libuvc timestamp instead of our own + 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()); if (!streaming) return; @@ -169,19 +174,19 @@ 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(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(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; } #ifdef BLOCKING_FRAME_GRABBING m_surface->present( qFrame ); @@ -193,9 +198,8 @@ 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) + if (m_surface) m_surface->present(frame); //else // qWarning() << "Dropping frame (" << latency << "ms old )"; @@ -223,7 +227,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; } @@ -243,7 +247,7 @@ bool UVCCameraSession::unload() if (devh) uvc_close(devh); - devh = NULL; + devh = nullptr; m_supportedViewfinderSettings.clear(); return true; @@ -253,12 +257,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) @@ -298,9 +302,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(this), getBandwidthFactor(), 0); #endif if (res != UVC_SUCCESS) { qWarning() << "uvc_stream_start" << uvc_strerror(res); @@ -316,7 +320,7 @@ bool UVCCameraSession::startPreview() return true; } -double UVCCameraSession::getBandwidthFactor() +float UVCCameraSession::getBandwidthFactor() { switch(settings.pixelFormat()) { // compressed; user can change it through the default settings @@ -349,19 +353,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; @@ -369,7 +373,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); @@ -406,7 +410,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; diff --git a/uvcengine/uvccamerasession.h b/uvcengine/uvccamerasession.h index d5536337db1024777037d70c9300b1d1d79da3db..afb50a9f6931516b5475f5fc3534855c984c24a3 100644 --- a/uvcengine/uvccamerasession.h +++ b/uvcengine/uvccamerasession.h @@ -28,6 +28,28 @@ QT_BEGIN_NAMESPACE // Maximum acceptable latency for calling the surface present method #define MAX_LATENCY_MS 1.0e3/25 +class Timing { +public: + 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; @@ -172,20 +194,24 @@ private: QVideoFrame currentFrame; unsigned char* yuvBuffer; long unsigned int yuvBufferSize; - QElapsedTimer frameReference; + QElapsedTimer frameReference; + + Timing sw; + Timing hw; + Timing hybrid; // capabilities QList 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 devices; - static QMutex UVCCameraSession::devicesMutex; + static QMutex devicesMutex; bool acquire(const QString &device); void release(const QString &device); @@ -194,10 +220,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(fourcc[0])).arg( + static_cast(fourcc[1])).arg( + static_cast(fourcc[2])).arg( + static_cast(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/ diff --git a/uvcengine/uvcserviceplugin.cpp b/uvcengine/uvcserviceplugin.cpp index af4713d6da1d4a15c0ba326a12cce756c9b35042..0d0f00a238b73f40c3d72bf1823bde1674658e74 100644 --- a/uvcengine/uvcserviceplugin.cpp +++ b/uvcengine/uvcserviceplugin.cpp @@ -4,7 +4,7 @@ QMediaService* UVCServicePlugin::create(const QString &key) { if (key == Q_MEDIASERVICE_CAMERA) return new UVCCameraService(); - return NULL; + return nullptr; } void UVCServicePlugin::release(QMediaService *service) diff --git a/uvcengine/uvcvideodevicecontrol.cpp b/uvcengine/uvcvideodevicecontrol.cpp index 0981e7571eb63067ec626d687890c49d104af670..19787711a606403d6fb5f9b1c9c9feb182358ba0 100644 --- a/uvcengine/uvcvideodevicecontrol.cpp +++ b/uvcengine/uvcvideodevicecontrol.cpp @@ -8,7 +8,7 @@ bool UVCVideoDeviceControl::loaded = false; UVCVideoDeviceControl::UVCVideoDeviceControl(QObject *parent) : QVideoDeviceSelectorControl(parent), - ctx(NULL), + ctx(nullptr), selected(0) { m_session = qobject_cast(parent); @@ -89,7 +89,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 +106,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); diff --git a/uvcengine/uvcvideorenderercontrol.cpp b/uvcengine/uvcvideorenderercontrol.cpp index 644cf648a6210ab500fba78e7bddee422cd80d79..f11b6093ad422ccb5b8f4823048daada24d58d9d 100644 --- a/uvcengine/uvcvideorenderercontrol.cpp +++ b/uvcengine/uvcvideorenderercontrol.cpp @@ -4,7 +4,7 @@ QT_BEGIN_NAMESPACE UVCVideoRendererControl::UVCVideoRendererControl(UVCCameraSession* session, QObject *parent) :QVideoRendererControl(parent), - m_surface(NULL), + m_surface(nullptr), m_session(session) { }