-
-
Save pauldotknopf/de3495a2581c65bac3cea2ddb8dc376c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "encoderbackend.h" | |
#include <QDebug> | |
#include <QThread> | |
#include <QAbstractVideoSurface> | |
#include <QVideoSurfaceFormat> | |
#include <QVideoFrame> | |
#include <private/qmemoryvideobuffer_p.h> | |
#include "encodermediaservice.h" | |
#include "encoderbackendasyncworker.h" | |
#include "encoderbackendcallbacks.h" | |
#include "encoderbackendplayer.h" | |
#include "mxencoder_internal.h" | |
#include "mxcommon.h" | |
#include "mxinputmanager.h" | |
EncoderBackend::EncoderBackend(QObject *parent) : | |
QObject(parent), | |
_signalPresent(false), | |
_isRecording(false), | |
encoder(NULL), | |
callbacks(new EncoderBackendCallbacks(this)), | |
player(new EncoderBackendPlayer(this)), | |
videoSurface(NULL), | |
currentSample(NULL), | |
currentStatus(new MxInputStatus) | |
{ | |
EncoderBackendAsyncWorker *worker = new EncoderBackendAsyncWorker(this); | |
worker->moveToThread(&workerThread); | |
connect(&workerThread, SIGNAL(finished()), worker, SLOT(deleteLater())); | |
connect(this, &EncoderBackend::captureStillEvent, worker, &EncoderBackendAsyncWorker::captureStill); | |
connect(this, &EncoderBackend::startRecordingEvent, worker, &EncoderBackendAsyncWorker::startRecording); | |
connect(this, &EncoderBackend::stopRecordingEvent, worker, &EncoderBackendAsyncWorker::stopRecording); | |
workerThread.start(); | |
} | |
EncoderBackend::~EncoderBackend() | |
{ | |
workerThread.quit(); | |
workerThread.wait(); | |
destroyEncoder(); | |
if (callbacks) | |
delete callbacks; | |
if (currentStatus) | |
delete currentStatus; | |
} | |
void EncoderBackend::startRecording(int bitrate) | |
{ | |
Q_EMIT startRecordingEvent(bitrate); | |
} | |
void EncoderBackend::_startRecording(Bitrate bitrate) | |
{ | |
encoder->StartRecording(bitrate); | |
} | |
void EncoderBackend::stopRecording() | |
{ | |
Q_EMIT stopRecordingEvent(); | |
} | |
void EncoderBackend::_stopRecording() | |
{ | |
encoder->StopRecording(); | |
} | |
void EncoderBackend::captureStill(int type) | |
{ | |
Q_EMIT captureStillEvent(type); | |
} | |
void EncoderBackend::_captureStill(StillCaptureType type) | |
{ | |
encoder->CaptureStill(type); | |
} | |
void EncoderBackend::presentFrame() | |
{ | |
QMutexLocker locker(&presentMutex); | |
if(!videoSurface) return; | |
if(!videoSurface->isActive()) return; | |
if(currentSample) | |
{ | |
EncoderSampleBuffer* sampleBuffer = NULL; | |
encoder_sample_get_buffer(currentSample, &sampleBuffer); | |
EncoderSampleBufferMap* sampleBufferMap = NULL; | |
encoder_sample_buffer_map(sampleBuffer, &sampleBufferMap); | |
unsigned char* data = NULL; | |
int size = 0; | |
encoder_sample_buffer_get_data(sampleBufferMap, &data, &size); | |
if(size > 0) { | |
QVideoFrame frame = QVideoFrame(new QMemoryVideoBuffer(reinterpret_cast<char*>(data), currentStatus->width), | |
QSize(currentStatus->width, currentStatus->height), | |
QVideoFrame::Format_YV12); | |
videoSurface->present(frame); | |
} | |
encoder_sample_buffer_unmap(sampleBuffer, sampleBufferMap); | |
encoder_sample_unref(currentSample); | |
currentSample = NULL; | |
} | |
} | |
void EncoderBackend::updateSignalStatus() { | |
QMutexLocker locker(&presentMutex); | |
if(currentStatus->status) { | |
// we have a signal | |
setSignalPresent(true); | |
if(videoSurface) { | |
if(videoSurface->isActive()) | |
videoSurface->stop(); | |
QVideoSurfaceFormat format(QSize(currentStatus->width, currentStatus->height), QVideoFrame::Format_YV12); | |
videoSurface->start(format); | |
} | |
} else { | |
// we have a signal | |
setSignalPresent(false); | |
if (videoSurface) { | |
if(videoSurface->isActive()) { | |
videoSurface->stop(); | |
} | |
} | |
} | |
} | |
bool EncoderBackend::signalPresent() | |
{ | |
return _signalPresent; | |
} | |
void EncoderBackend::setSignalPresent(bool signalPresent) | |
{ | |
_signalPresent = signalPresent; | |
Q_EMIT signalPresentChanged(); | |
} | |
bool EncoderBackend::isRecording() | |
{ | |
return _isRecording; | |
} | |
void EncoderBackend::setIsRecording(bool isRecording) | |
{ | |
_isRecording = isRecording; | |
Q_EMIT isRecordingChanged(); | |
} | |
void EncoderBackend::setSurface(QAbstractVideoSurface* surface) | |
{ | |
if(videoSurface) { | |
if(videoSurface->isActive()) | |
videoSurface->stop(); | |
videoSurface = NULL; | |
} | |
videoSurface = surface; | |
if(videoSurface) | |
updateSignalStatus(); | |
} | |
MediaInput *EncoderBackend::input() | |
{ | |
return _mediaInput; | |
} | |
void EncoderBackend::setInput(MediaInput *mediaInput) | |
{ | |
if (!mediaInput || !mediaInput->input()) | |
return; | |
if (encoder && mediaInput == _mediaInput) { | |
// normally, this should only return | |
// for now, this makes for a nice way to stop capturing | |
destroyEncoder(); | |
return; | |
} | |
destroyEncoder(); | |
// this can return NULL... | |
encoder = Encoder::fromMxInput(mediaInput->input(), callbacks, "/data/staging"); | |
if (encoder) | |
_mediaInput = mediaInput; | |
} | |
void EncoderBackend::RecordingStarted(std::string file) | |
{ | |
UNUSED(file); | |
setProperty("isRecording", true); | |
Q_EMIT recordingStarted(QString::fromStdString(file)); | |
} | |
void EncoderBackend::RecordingStopped(std::string file, bool wasSuccesful) | |
{ | |
UNUSED(wasSuccesful); | |
setProperty("isRecording", false); | |
Q_EMIT recordingStopped(QString::fromStdString(file)); | |
} | |
void EncoderBackend::SignalStatusChanged(const MxInputStatus &status) | |
{ | |
{ | |
QMutexLocker locker(&presentMutex); | |
*currentStatus = status; | |
if(currentSample != NULL) | |
{ | |
encoder_sample_unref(currentSample); | |
currentSample = NULL; | |
} | |
} | |
QMetaObject::invokeMethod(this, "updateSignalStatus", Qt::QueuedConnection); | |
} | |
void EncoderBackend::StillCaptured(std::string file, bool wasSuccesful) | |
{ | |
UNUSED(file); | |
UNUSED(wasSuccesful); | |
Q_EMIT stillCaptured(QString::fromStdString(file)); | |
} | |
void EncoderBackend::SampleArrived(EncoderSample* sample) | |
{ | |
{ | |
QMutexLocker locker(&presentMutex); | |
if(currentSample != NULL) | |
{ | |
encoder_sample_unref(currentSample); | |
currentSample = NULL; | |
} | |
currentSample = sample; | |
encoder_sample_ref(sample); | |
} | |
QMetaObject::invokeMethod(this, "presentFrame", Qt::QueuedConnection); | |
} | |
void EncoderBackend::destroyEncoder() | |
{ | |
if (!encoder) | |
return; | |
delete encoder; | |
encoder = NULL; | |
_mediaInput = NULL; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment