recorder_manager_finished

This commit is contained in:
Hiro Protagonist 2017-03-13 18:29:42 +13:00
parent 3c5dbaf409
commit 6650d9c80c
16 changed files with 749 additions and 6 deletions

View file

@ -23,14 +23,14 @@ DEFINES += QT_DEPRECATED_WARNINGS
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
linux {
LIBS += bin/libflycapture.so
LIBS += bin/libflycapture.so.2
}
SOURCES += src/main.cpp\
src/mainwindow.cpp
HEADERS += src/mainwindow.h\
include/flycapture2.h
include/flycapture/Flycapture2.h
FORMS += src/forms/mainwindow.ui

5
notes.md Normal file
View file

@ -0,0 +1,5 @@
Recorder:
- has default Framreate, Bitrate
- UI needs to ASK for them, or set them diffrently
Maybe Split Recorder and Manager UP -> DONE

0
notes.md~ Normal file
View file

View file

@ -3,4 +3,5 @@
-I/usr/include/qt/QtWidgets
-I/usr/include/qt/QtGui
-I/usr/include/qt/QtCore
--std=c++11
-I../include/flycapture
--std=c++11

5
src/camera.cpp~ Normal file
View file

@ -0,0 +1,5 @@
#include "camera.h"
using namespace FlyCapture2;
CameraManager::CameraManager(QObject *parent) : QObject(parent) {}

63
src/camera.h~ Normal file
View file

@ -0,0 +1,63 @@
#ifndef CAMERAMANAGER_H
#define CAMERAMANAGER_H
/*
This Class is an abstraction over the FlyCapture2 API for handeling the connection to the camera and
hiding the internals from the GUI code, to make reusability easier, although FlyCapture code is needed outside.
*/
// TODO: Exclude inline Implementation
#include <QObject>
#include "FlyCapture2.h"
class CameraManager : public QObject
{
Q_OBJECT
public:
explicit CameraManager(QObject *parent = 0);
~CameraManager();
// Pointer to the last image captured by the camera //TODO maybe obsolete
FlyCapture2::Image* lastImage;
// Starts capturing images. When an image has been captured, the signal frameCaptured is emited.
// returns an Error if starting the Capture goes wrong
FlyCapture2::Error StartCapture();
//TODO remove, if not needed
FlyCapture2::Camera* getCamera() {
return &camera;
};
bool isConnected() {
return camera.IsConnected();
}
// Get the number of connected cameras.
unsigned int numCameras() {
bus_mgr.GetNumOfCameras(&num_cameras);
return num_cameras;
};
FlyCapture2::Error selectCamera(unsigned int);
private:
FlyCapture2::Camera camera;
FlyCapture2::BusManager bus_mgr;
unsigned int num_cameras;
// GUID of the camera, which is currently being used
FlyCapture2::PGRGuid camera_guid;
private slots:
signals:
void frameCaptured(FlyCapture2::Image*);
};
#endif // CAMERAMANAGER_H

75
src/cameramanager.cpp Normal file
View file

@ -0,0 +1,75 @@
#include "cameramanager.h"
#include <QDebug>
using namespace FlyCapture2;
CameraManager::CameraManager(QObject *parent) : QObject(parent) {
}
void CameraManager::connectCamera(unsigned int index) {
// Don't connect twice.
if(camera_index == index)
return;
if(camera.IsConnected())
camera.Disconnect();
qDebug() << "Connecting to camera: " << index << '\n';
Error error; // general purpose error object
// get PGRGuid of the Camera
error = bus_mgr.GetCameraFromIndex(index, &camera_guid);
if(error != PGRERROR_OK) {
throw error;
return;
}
// connectCamera
error = camera.Connect(&camera_guid);
if(error != PGRERROR_OK) {
throw error;
return;
}
camera_index = index;
}
// The capture callback is a wrapper to emit the frameCaptured signal.
inline void CameraManager::captureCallback(FlyCapture2::Image* image, const void *camManager) {
if(camManager)
static_cast<const CameraManager*>(camManager)->frameCaptured(image);
}
void CameraManager::stopCapture() {
if(!is_capturing)
return;
Error error;
error = camera.StopCapture();
if(error != PGRERROR_OK) {
throw error;
return;
}
is_capturing = false;
}
void CameraManager::startCapture() {
// Don't capture twice!
if(is_capturing)
return;
// Just a wrapper for the PTGrey method. Let all the errors be generated by the FlyCapture method.
// TODO: Evtl try to connect to first camera...
Error error;
error = camera.StartCapture(captureCallback, this);
if(error != PGRERROR_OK) {
throw error;
return;
}
is_capturing = true;
}

50
src/cameramanager.cpp~ Normal file
View file

@ -0,0 +1,50 @@
#include "cameramanager.h"
#include <QDebug>
using namespace FlyCapture2;
CameraManager::CameraManager(QObject *parent) : QObject(parent) {
// Select first camera by default.
if(numCameras() > 0)
connectCamera(0);
}
void CameraManager::connectCamera(unsigned int index) {
if(camera.IsConnected())
camera.Disconnect();
qDebug() << "Connecting to camera: " << index << '\n';
Error error; // general purpose error object
// get PGRGuid of the Camera
error = bus_mgr.GetCameraFromIndex(index, &camera_guid);
if(error != PGRERROR_OK) {
emit camError(error);
return;
}
// connectCamera
error = camera.Connect(&camera_guid);
if(error != PGRERROR_OK) {
emit camError(error);
return;
}
emit cameraConnected(&camera);
}
// The capture callback is a wrapper to emit the frameCaptured signal.
inline void CameraManager::captureCallback(FlyCapture2::Image* image, const void *camManager) {
if(camManager)
static_cast<const CameraManager*>(camManager)->frameCaptured(image);
}
void CameraManager::startCapture() {
// Just a wrapper for the PTGrey method. Let all the errors be generated by the PTGrey method.
// TODO: Evtl try to connect to first camera...
Error error;
error = camera.StartCapture(captureCallback, this);
}

77
src/cameramanager.h Normal file
View file

@ -0,0 +1,77 @@
#ifndef CAMERAMANAGER_H
#define CAMERAMANAGER_H
/*
This Class is an abstraction over the FlyCapture2 API for handeling the connection to the camera and
hiding the internals from the GUI code, to make reusability easier, although FlyCapture code is needed outside.
*/
// TODO: Exclude inline Implementation
#include <QObject>
#include "FlyCapture2.h"
class CameraManager : public QObject
{
Q_OBJECT
public:
explicit CameraManager(QObject *parent = 0);
~CameraManager();
// Pointer to the last image captured by the camera //TODO maybe obsolete
FlyCapture2::Image* lastImage;
// Starts capturing images. When an image has been captured, the signal frameCaptured is emited.
// Throws FlyCapture2::Error
void startCapture();
void stopCapture();
//TODO remove, if not needed
const FlyCapture2::Camera* getCamera() const {
return &camera;
};
bool isConnected() {
return camera.IsConnected();
}
// Get the number of connected cameras.
unsigned int numCameras() {
bus_mgr.GetNumOfCameras(&num_cameras);
return num_cameras;
};
// Connect camera from index. Once successfull it emits the cameraConnected signal.
// Emits Error signal in case of an error.
void connectCamera(unsigned int);
bool isCapturing() {
return is_capturing;
}
private:
FlyCapture2::Camera camera;
FlyCapture2::BusManager bus_mgr;
unsigned int num_cameras;
// GUID of the camera, which is currently being used
FlyCapture2::PGRGuid camera_guid;
// Index of the current camera
unsigned int camera_index;
// Just a littile wrapper function around the callback function for the camera capture to emit signals.
static inline void captureCallback(FlyCapture2::Image*, const void*);
// State Variable
bool is_capturing;
signals:
void frameCaptured(FlyCapture2::Image*) const;
};
#endif // CAMERAMANAGER_H

74
src/cameramanager.h~ Normal file
View file

@ -0,0 +1,74 @@
#ifndef CAMERAMANAGER_H
#define CAMERAMANAGER_H
/*
This Class is an abstraction over the FlyCapture2 API for handeling the connection to the camera and
hiding the internals from the GUI code, to make reusability easier, although FlyCapture code is needed outside.
*/
// TODO: Exclude inline Implementation
#include <QObject>
#include "FlyCapture2.h"
class CameraManager : public QObject
{
Q_OBJECT
public:
explicit CameraManager(QObject *parent = 0);
~CameraManager();
// Pointer to the last image captured by the camera //TODO maybe obsolete
FlyCapture2::Image* lastImage;
// Starts capturing images. When an image has been captured, the signal frameCaptured is emited.
// Emits Error signal in case of an error.
void startCapture();
//TODO remove, if not needed
FlyCapture2::Camera* getCamera() {
return &camera;
};
bool isConnected() {
return camera.IsConnected();
}
// Get the number of connected cameras.
unsigned int numCameras() {
bus_mgr.GetNumOfCameras(&num_cameras);
return num_cameras;
};
// Connect camera from index. Once successfull it emits the cameraConnected signal.
// Emits Error signal in case of an error.
void connectCamera(unsigned int);
private:
FlyCapture2::Camera camera;
FlyCapture2::BusManager bus_mgr;
unsigned int num_cameras;
// GUID of the camera, which is currently being used
FlyCapture2::PGRGuid camera_guid;
// Just a littile wrapper function around the callback function for the camera capture to emit signals.
static inline void captureCallback(FlyCapture2::Image*, const void*);
private slots:
signals:
void frameCaptured(FlyCapture2::Image*) const;
void cameraConnected(FlyCapture2::Camera*);
//Error signal
void camError(FlyCapture2::Error);
};
#endif // CAMERAMANAGER_H

View file

@ -4,7 +4,10 @@
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
ui(new Ui::MainWindow),
cam_man(qobject_cast<QObject*>(this)),
recorder(qobject_cast<QObject*>(this))
{
ui->setupUi(this);
// Hide Preview Widget
@ -21,12 +24,17 @@ MainWindow::~MainWindow() {
// Show/Hide Preview
void MainWindow::toggle_preview(bool checked) {
if(checked)
if(checked) {
ui->preview_widget->setProperty("enabled", true);
ui->preview_widget->show();
else
} else {
ui->preview_widget->setProperty("enabled", false);
ui->preview_widget->hide();
}
adjustSize();
// Start Capturing for preview
}

View file

@ -1,6 +1,8 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "cameramanager.h"
#include "recorder.h"
#include <QMainWindow>
namespace Ui {
@ -17,6 +19,8 @@ public:
private:
Ui::MainWindow *ui;
CameraManager cam_man;
Recorder recorder;
private slots:
void toggle_preview(bool);

158
src/recorder.cpp Normal file
View file

@ -0,0 +1,158 @@
#include "recorder.h"
using namespace FlyCapture2;
Recorder::Recorder(QObject* parent) : QObject(parent) : frame_n {0}, time_c {0} {
// Initializing References
frame_number = frame_n:
time_captured = time_c;
// No Compression for frame_captures
frame_options.compression = frame_options.NONE;
};
void Recorder::newRecording(unsigned int framerate, QDir p_dir, QString r_name, bool cap_frames) {
stopRecording();
// check if directory is a directory and is writable
project_dir = p_dir;
QFileInfo pDirInfo(project_dir.path());
if(!pDirInfo.isDir() || !pDirInfo.isWritable()) {
throw RecorderError::INVALID_PROJECT_DIRECTORY;
return;
}
rec_name = r_name;
capture_frames = cap_frames;
// Verify Recdir... create directories...
QDir record_dir(project_dir.path() + rec_name);
RecorderError err = verifyRecDir();
if(err != RecorderError::OK) {
throw err;
return;
}
// get Status file
QFile stat_file(project_dir.path() + rec_name + ".stat");
if(!stat_file.open(QIODevice::ReadWrite | QIODevice::Text)) {
throw RecorderError::CANT_OPEN_STATFILE;
return;
}
// If append, figure out Frame count etc...
if(append) {
if(!restoreRecording()) {
throw RecorderError::STATFILE_ERROR;
return;
}
}
Error f_err;
// set recorder options
options.frameRate = framerate;
// open AVI in recorder
f_err = recorder.AVIOpen((record_dir.path() + rec_name).toStdString().c_str(), &options);
if (f_err != PGRERROR_OK)
{
throw f_err;
return;
}
is_recording = true;
};
bool Recorder::restoreRecording() {
bool ok;
frame_n = stat_file.readLine().toInt(&ok, 10);
return ok;
}
RecorderError Recorder::verifyRecDir() {
// check if project with same name exists and append to that
// TODO: chech if there is any option to append
// TODO: Check for special chars.
if(rec_name == "") {
return RecorderError::INVALID_RECORDING_NAME;
cleanup();
}
if(record_dir.exists()) {
QMessageBox msgBox;
msgBox.setText(tr("A recording with this name already exists. Which action should be taken?"));
void *appendButton = msgBox.addButton(tr("Append the recording."), QMessageBox::ActionRole);
void *removeButton = msgBox.addButton(tr("Overwrite recording."), QMessageBox::ActionRole);
void *abortButton = msgBox.addButton(QMessageBox::Abort);
msgBox.exec();
if (msgBox.clickedButton() == appendButton) {
append = true;
} else if (msgBox.clickedButton() == removeButton) {
record_dir.removeRecursively();
} else if (msgBox.clickedButton() == abortButton) {
return RecorderError::CANCELED;
}
}
project_dir.mkdir(rec_name);
if(capture_frames)
record_dir.mkdir("frames");
return RecorderError::OK;
}
void Recorder::stopRecording() {
if(is_recording) {
// Stop Recorder
Error err = recorder.AVIClose();
if(err != PGRERROR_OK) {
throw err;
return;
}
is_recording = false;
cleanup();
}
}
void Recorder::cleanup() {
// Reset Everything
if(!is_recording) {
frame_n = 0;
time_c = 0;
project_dir = "";
rec_name = "";
capture_frames = false;
append = false;
}
};
void Recorder::appendFrame(FlyCapture2::Image *image) {
// If not recording, just stop.
if(!is_recording)
return;
Error app_err = recorder.AVIAppend(image);
if(app_err != PGRERROR_OK) {
throw app_err;
return;
}
// save image as frame
if(capture_frames) {
app_err = image->Save((record_dir.path() + "frames/" + frame_n).toStdString().c_str(), &frame_options);
if(app_err != PGRERROR_OK) {
throw app_err;
return;
}
}
frame_n++;
time_c = frame_n / options.frameRate;
}

61
src/recorder.cpp~ Normal file
View file

@ -0,0 +1,61 @@
#include "recorder.h"
Recorder::Recorder(QObject* parent) : QObject(parent) {};
void Recorder::newRecording(unsigned int bitrate, unsigned int width, unsigned int height, QDir p_dir, QString r_name, bool cap_frames) {
if(is_recording)
stopRecording();
// check if directory is a directory and is writable
project_dir = p_dir;
QFileInfo pDirInfo(project_dir.path());
if(!pDirInfo.isDir() || !pDirInfo.isWritable()) {
throw RecorderError::INVALID_PROJECT_DIRECTORY;
return;
}
rec_name = r_name;
capture_frames = cap_frames;
verifyRecDir();
// create subdir for recording
project_dir.mkdir(const QString &dirName)
};
RecorderError Recorder::verifyRecDir() {
// check if project with same name exists and append to that
// TODO: chech if there is any option to append
// TODO: Check for special chars.
if(rec_name == "") {
return RecorderError::INVALID_RECORDING_NAME;
}
QDir rec_dir(project_dir.path() + rec_name);
if(rec_dir.exists()) {
QMessageBox msgBox;
msgBox.setText(tr("A recording with this name already exists. Which action should be taken?"));
void *appendButton = msgBox.addButton(tr("Append the recording."), QMessageBox::ActionRole);
void *removeButton = msgBox.addButton(tr("Overwrite recording."), QMessageBox::ActionRole);
void *abortButton = msgBox.addButton(QMessageBox::Abort);
msgBox.exec();
if (msgBox.clickedButton() == appendButton) {
// connect
} else if (msgBox.clickedButton() == abortButton) {
// abort
}
}
project_dir.mkdir(rec_name);
if(capture_frames)
rec_dir.mkdir("frames");
}

94
src/recorder.h Normal file
View file

@ -0,0 +1,94 @@
#ifndef RECORDER_H
#define RECORDER_H
#include <string>
#include <QObject>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QStandardPaths>
#include <QMessageBox>
#include <QAbstractButton>
#include "FlyCapture2.h"
/*
This class is a wrapper around the AVIRecorder from PTGrey to abstract and implement signals.
*/
enum class RecorderError {
INVALID_PROJECT_DIRECTORY,
INVALID_RECORDING_NAME,
CREATION_RECORD_DIRECTORY_FAILED,
CANCELED,
CANT_OPEN_STATFILE,
STATFILE_ERROR,
OK
};
class Recorder : QObject {
Q_OBJECT
public:
// Set bitrate to a default of 10Mbit.
Recorder(QObject *parent = 0);
~Recorder() = default;
// Start a recording. A recording directory with the avi files and evtl. a frame subfolder will be created. Throws RecorderError or FlyCapture2::Error
void newRecording(unsigned int framerate, QDir p_dir, QString r_name, bool capture_frames = false);
// Append a frame to the recording,
void appendFrame(FlyCapture2::Image *image);
// stops the recording, cleans up, throws FlyCapture2::Error
void stopRecording();
QString getRecordingFileName() {
return rec_name;
}
QString getRecName() {
return rec_name;
}
bool isRecording() {
return is_recording;
}
const unsigned int& frame_number;
const unsigned int& time_captured;
private:
FlyCapture2::AVIRecorder recorder;
FlyCapture2::AVIOption options;
FlyCapture2::TIFFOption frame_options;
// Basic state Variable, because AVIRecorder doesn't provide it.
bool is_recording;
// append to existing files
bool append;
// save individual frames as image files
bool capture_frames;
// number of frames captured
unsigned int frame_n;
double time_c;
QDir project_dir;
QDir record_dir;
QString rec_name;
// status file for frame count
QFile stat_file;
// Check if recording directory exists. If it does ask for Overwrite or cancelation.
RecorderError verifyRecDir();
// If appending, check if there are any information about existing frames...
bool restoreRecording();
// reset Status, only if not recording (is_recording == false).
void cleanup();
};
#endif //RECORDER_H

68
src/recorder.h~ Normal file
View file

@ -0,0 +1,68 @@
#ifndef RECORDER_H
#define RECORDER_H
#include <QObject>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QStandardPaths>
#include <QMessageBox>
#include <QAbstractButton>
#include "FlyCapture2.h"
/*
This class is a wrapper around the AVIRecorder from PTGrey to abstract and implement signals.
*/
enum class RecorderError {
INVALID_PROJECT_DIRECTORY,
INVALID_RECORDING_NAME,
CREATION_RECORD_DIRECTORY_FAILED,
CANCELED,
OK
};
class Recorder : QObject {
Q_OBJECT
public:
// Set bitrate to a default of 10Mbit.
Recorder(QObject *parent = 0);
~Recorder() = default;
// Start a recording. A recording directory with the avi files and evtl. a frame subfolder will be created.
void newRecording(unsigned int bitrate, unsigned int width, unsigned int height, QDir p_dir, QString r_name, bool capture_frames = false);
void stopRecording();
QString getRecordingFileName() {
return rec_name;
}
QString getRecName() {
return rec_name;
}
bool isRecording() {
return is_recording;
}
private:
FlyCapture2::AVIRecorder recorder;
FlyCapture2::H264Option options;
// Basic state Variable, because AVIRecorder doesn't provide it.
bool is_recording;
// append to existing files
bool append;
bool capture_frames;
QDir project_dir;
QString rec_name;
// Check if recording directory exists. If it does ask for Overwrite, New Name or Cancel. In case of cancel it returns false.
RecorderError verifyRecDir();
};
#endif //RECORDER_H