2015-05-14 10:46:28 +08:00
|
|
|
/*
|
2015-06-06 09:40:08 +08:00
|
|
|
Copyright © 2015 by The qTox Project
|
|
|
|
|
2015-05-14 10:46:28 +08:00
|
|
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
|
|
|
|
2015-06-06 09:40:08 +08:00
|
|
|
qTox is libre software: you can redistribute it and/or modify
|
2015-05-14 10:46:28 +08:00
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
2015-06-06 09:40:08 +08:00
|
|
|
|
|
|
|
qTox is distributed in the hope that it will be useful,
|
2015-05-14 10:46:28 +08:00
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2015-06-06 09:40:08 +08:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2015-05-14 10:46:28 +08:00
|
|
|
|
2015-06-06 09:40:08 +08:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
2015-05-14 10:46:28 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef CAMERA_H
|
|
|
|
#define CAMERA_H
|
|
|
|
|
|
|
|
#include <QHash>
|
|
|
|
#include <QString>
|
|
|
|
#include <QFuture>
|
|
|
|
#include <QVector>
|
|
|
|
#include <atomic>
|
|
|
|
#include "src/video/videosource.h"
|
2015-05-16 10:01:38 +08:00
|
|
|
#include "src/video/videomode.h"
|
2015-05-14 10:46:28 +08:00
|
|
|
|
|
|
|
class CameraDevice;
|
|
|
|
struct AVCodecContext;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This class is a wrapper to share a camera's captured video frames
|
|
|
|
* It allows objects to suscribe and unsuscribe to the stream, starting
|
|
|
|
* the camera and streaming new video frames only when needed.
|
2015-06-26 23:38:53 +08:00
|
|
|
* This is a singleton, since we can only capture from one
|
|
|
|
* camera at the same time without thread-safety issues.
|
|
|
|
* The source is lazy in the sense that it will only keep the video
|
|
|
|
* device open as long as there are subscribers, the source can be
|
|
|
|
* open but the device closed if there are zero subscribers.
|
2015-05-14 10:46:28 +08:00
|
|
|
**/
|
|
|
|
|
|
|
|
class CameraSource : public VideoSource
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
2015-10-11 14:38:44 +08:00
|
|
|
|
2015-05-14 10:46:28 +08:00
|
|
|
public:
|
2015-06-26 23:38:53 +08:00
|
|
|
static CameraSource& getInstance();
|
2015-06-27 01:04:53 +08:00
|
|
|
static void destroyInstance();
|
2015-06-26 23:38:53 +08:00
|
|
|
/// Opens the source for the camera device in argument, in the settings, or the system default
|
|
|
|
/// If a device is already open, the source will seamlessly switch to the new device
|
|
|
|
void open();
|
|
|
|
void open(const QString deviceName);
|
|
|
|
void open(const QString deviceName, VideoMode mode);
|
|
|
|
void close(); ///< Equivalent to opening the source with the video device "none". Stops streaming.
|
2015-09-28 07:04:39 +08:00
|
|
|
bool isOpen();
|
2015-05-14 10:46:28 +08:00
|
|
|
|
|
|
|
// VideoSource interface
|
|
|
|
virtual bool subscribe() override;
|
|
|
|
virtual void unsubscribe() override;
|
|
|
|
|
2015-07-22 02:38:43 +08:00
|
|
|
signals:
|
|
|
|
void deviceOpened();
|
|
|
|
|
2015-05-14 10:46:28 +08:00
|
|
|
private:
|
2015-06-26 23:38:53 +08:00
|
|
|
CameraSource();
|
|
|
|
~CameraSource();
|
2015-05-14 10:46:28 +08:00
|
|
|
/// Blocking. Decodes video stream and emits new frames.
|
|
|
|
/// Designed to run in its own thread.
|
|
|
|
void stream();
|
|
|
|
/// All VideoFrames must be deleted or released before we can close the device
|
|
|
|
/// or the device will forcibly free them, and then ~VideoFrame() will double free.
|
|
|
|
/// In theory very careful coding from our users could ensure all VideoFrames
|
|
|
|
/// die before unsubscribing, even the ones currently in flight in the metatype system.
|
|
|
|
/// But that's just asking for trouble and mysterious crashes, so we'll just
|
|
|
|
/// maintain a freelist and have all VideoFrames tell us when they die so we can forget them.
|
|
|
|
void freelistCallback(int freelistIndex);
|
|
|
|
/// Get the index of a free slot in the freelist
|
|
|
|
/// Callers must hold the freelistLock
|
|
|
|
int getFreelistSlotLockless();
|
2015-06-26 23:38:53 +08:00
|
|
|
bool openDevice(); ///< Callers must own the biglock. Actually opens the video device and starts streaming.
|
|
|
|
void closeDevice(); ///< Callers must own the biglock. Actually closes the video device and stops streaming.
|
2015-05-14 10:46:28 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
QVector<std::weak_ptr<VideoFrame>> freelist; ///< Frames that need freeing before we can safely close the device
|
|
|
|
QFuture<void> streamFuture; ///< Future of the streaming thread
|
2015-06-26 23:38:53 +08:00
|
|
|
QString deviceName; ///< Short name of the device for CameraDevice's open(QString)
|
|
|
|
CameraDevice* device; ///< Non-owning pointer to an open CameraDevice, or nullptr. Not atomic, synced with memfences when becomes null.
|
2015-05-16 10:01:38 +08:00
|
|
|
VideoMode mode; ///< What mode we tried to open the device in, all zeros means default mode
|
2015-05-14 10:46:28 +08:00
|
|
|
AVCodecContext* cctx, *cctxOrig; ///< Codec context of the camera's selected video stream
|
|
|
|
int videoStreamIndex; ///< A camera can have multiple streams, this is the one we're decoding
|
2015-10-10 07:24:04 +08:00
|
|
|
QMutex biglock, freelistLock; ///< True when locked. Faster than mutexes for video decoding.
|
2015-09-28 07:04:39 +08:00
|
|
|
std::atomic_bool _isOpen;
|
2015-10-24 11:19:23 +08:00
|
|
|
std::atomic_bool streamBlocker; ///< Holds the streaming thread still when true
|
2015-05-14 10:46:28 +08:00
|
|
|
std::atomic_int subscriptions; ///< Remember how many times we subscribed for RAII
|
2015-06-26 23:38:53 +08:00
|
|
|
|
|
|
|
static CameraSource* instance;
|
2015-05-14 10:46:28 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif // CAMERA_H
|