mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 15:30:38 +02:00
Merge pull request #6446 from jherico/rec4
Support writing a clip to a qbytearray
This commit is contained in:
commit
c22d632c3a
5 changed files with 90 additions and 72 deletions
|
@ -13,6 +13,11 @@
|
||||||
#include "impl/FileClip.h"
|
#include "impl/FileClip.h"
|
||||||
#include "impl/BufferClip.h"
|
#include "impl/BufferClip.h"
|
||||||
|
|
||||||
|
#include <QtCore/QJsonDocument>
|
||||||
|
#include <QtCore/QJsonObject>
|
||||||
|
#include <QtCore/QBuffer>
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
using namespace recording;
|
using namespace recording;
|
||||||
|
|
||||||
Clip::Pointer Clip::fromFile(const QString& filePath) {
|
Clip::Pointer Clip::fromFile(const QString& filePath) {
|
||||||
|
@ -27,6 +32,15 @@ void Clip::toFile(const QString& filePath, const Clip::ConstPointer& clip) {
|
||||||
FileClip::write(filePath, clip->duplicate());
|
FileClip::write(filePath, clip->duplicate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray Clip::toBuffer(const Clip::ConstPointer& clip) {
|
||||||
|
QBuffer buffer;
|
||||||
|
if (buffer.open(QFile::Truncate | QFile::WriteOnly)) {
|
||||||
|
clip->duplicate()->write(buffer);
|
||||||
|
buffer.close();
|
||||||
|
}
|
||||||
|
return buffer.data();
|
||||||
|
}
|
||||||
|
|
||||||
Clip::Pointer Clip::newClip() {
|
Clip::Pointer Clip::newClip() {
|
||||||
return std::make_shared<BufferClip>();
|
return std::make_shared<BufferClip>();
|
||||||
}
|
}
|
||||||
|
@ -37,4 +51,70 @@ void Clip::seek(float offset) {
|
||||||
|
|
||||||
float Clip::position() const {
|
float Clip::position() const {
|
||||||
return Frame::frameTimeToSeconds(positionFrameTime());
|
return Frame::frameTimeToSeconds(positionFrameTime());
|
||||||
};
|
}
|
||||||
|
|
||||||
|
// FIXME move to frame?
|
||||||
|
bool writeFrame(QIODevice& output, const Frame& frame, bool compressed = true) {
|
||||||
|
if (frame.type == Frame::TYPE_INVALID) {
|
||||||
|
qWarning() << "Attempting to write invalid frame";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto written = output.write((char*)&(frame.type), sizeof(FrameType));
|
||||||
|
if (written != sizeof(FrameType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//qDebug() << "Writing frame with time offset " << frame.timeOffset;
|
||||||
|
written = output.write((char*)&(frame.timeOffset), sizeof(Frame::Time));
|
||||||
|
if (written != sizeof(Frame::Time)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QByteArray frameData = frame.data;
|
||||||
|
if (compressed) {
|
||||||
|
frameData = qCompress(frameData);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t dataSize = frameData.size();
|
||||||
|
written = output.write((char*)&dataSize, sizeof(FrameSize));
|
||||||
|
if (written != sizeof(uint16_t)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataSize != 0) {
|
||||||
|
written = output.write(frameData);
|
||||||
|
if (written != dataSize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString Clip::FRAME_TYPE_MAP = QStringLiteral("frameTypes");
|
||||||
|
const QString Clip::FRAME_COMREPSSION_FLAG = QStringLiteral("compressed");
|
||||||
|
|
||||||
|
bool Clip::write(QIODevice& output) {
|
||||||
|
auto frameTypes = Frame::getFrameTypes();
|
||||||
|
QJsonObject frameTypeObj;
|
||||||
|
for (const auto& frameTypeName : frameTypes.keys()) {
|
||||||
|
frameTypeObj[frameTypeName] = frameTypes[frameTypeName];
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject rootObject;
|
||||||
|
rootObject.insert(FRAME_TYPE_MAP, frameTypeObj);
|
||||||
|
// Always mark new files as compressed
|
||||||
|
rootObject.insert(FRAME_COMREPSSION_FLAG, true);
|
||||||
|
QByteArray headerFrameData = QJsonDocument(rootObject).toBinaryData();
|
||||||
|
// Never compress the header frame
|
||||||
|
if (!writeFrame(output, Frame({ Frame::TYPE_HEADER, 0, headerFrameData }), false)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
seek(0);
|
||||||
|
|
||||||
|
for (auto frame = nextFrame(); frame; frame = nextFrame()) {
|
||||||
|
if (!writeFrame(output, *frame)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -47,10 +47,16 @@ public:
|
||||||
virtual void skipFrame() = 0;
|
virtual void skipFrame() = 0;
|
||||||
virtual void addFrame(FrameConstPointer) = 0;
|
virtual void addFrame(FrameConstPointer) = 0;
|
||||||
|
|
||||||
|
bool write(QIODevice& output);
|
||||||
|
|
||||||
static Pointer fromFile(const QString& filePath);
|
static Pointer fromFile(const QString& filePath);
|
||||||
static void toFile(const QString& filePath, const ConstPointer& clip);
|
static void toFile(const QString& filePath, const ConstPointer& clip);
|
||||||
|
static QByteArray toBuffer(const ConstPointer& clip);
|
||||||
static Pointer newClip();
|
static Pointer newClip();
|
||||||
|
|
||||||
|
static const QString FRAME_TYPE_MAP;
|
||||||
|
static const QString FRAME_COMREPSSION_FLAG;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class WrapperClip;
|
friend class WrapperClip;
|
||||||
using Mutex = std::recursive_mutex;
|
using Mutex = std::recursive_mutex;
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtCore/QJsonDocument>
|
|
||||||
#include <QtCore/QJsonObject>
|
|
||||||
|
|
||||||
#include <Finally.h>
|
#include <Finally.h>
|
||||||
|
|
||||||
|
@ -40,41 +38,7 @@ QString FileClip::getName() const {
|
||||||
return _file.fileName();
|
return _file.fileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME move to frame?
|
|
||||||
bool writeFrame(QIODevice& output, const Frame& frame, bool compressed = true) {
|
|
||||||
if (frame.type == Frame::TYPE_INVALID) {
|
|
||||||
qWarning() << "Attempting to write invalid frame";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto written = output.write((char*)&(frame.type), sizeof(FrameType));
|
|
||||||
if (written != sizeof(FrameType)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//qDebug() << "Writing frame with time offset " << frame.timeOffset;
|
|
||||||
written = output.write((char*)&(frame.timeOffset), sizeof(Frame::Time));
|
|
||||||
if (written != sizeof(Frame::Time)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QByteArray frameData = frame.data;
|
|
||||||
if (compressed) {
|
|
||||||
frameData = qCompress(frameData);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t dataSize = frameData.size();
|
|
||||||
written = output.write((char*)&dataSize, sizeof(FrameSize));
|
|
||||||
if (written != sizeof(uint16_t)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dataSize != 0) {
|
|
||||||
written = output.write(frameData);
|
|
||||||
if (written != dataSize) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FileClip::write(const QString& fileName, Clip::Pointer clip) {
|
bool FileClip::write(const QString& fileName, Clip::Pointer clip) {
|
||||||
// FIXME need to move this to a different thread
|
// FIXME need to move this to a different thread
|
||||||
|
@ -90,33 +54,7 @@ bool FileClip::write(const QString& fileName, Clip::Pointer clip) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Finally closer([&] { outputFile.close(); });
|
Finally closer([&] { outputFile.close(); });
|
||||||
{
|
return clip->write(outputFile);
|
||||||
auto frameTypes = Frame::getFrameTypes();
|
|
||||||
QJsonObject frameTypeObj;
|
|
||||||
for (const auto& frameTypeName : frameTypes.keys()) {
|
|
||||||
frameTypeObj[frameTypeName] = frameTypes[frameTypeName];
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject rootObject;
|
|
||||||
rootObject.insert(FRAME_TYPE_MAP, frameTypeObj);
|
|
||||||
// Always mark new files as compressed
|
|
||||||
rootObject.insert(FRAME_COMREPSSION_FLAG, true);
|
|
||||||
QByteArray headerFrameData = QJsonDocument(rootObject).toBinaryData();
|
|
||||||
// Never compress the header frame
|
|
||||||
if (!writeFrame(outputFile, Frame({ Frame::TYPE_HEADER, 0, headerFrameData }), false)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
clip->seek(0);
|
|
||||||
for (auto frame = clip->nextFrame(); frame; frame = clip->nextFrame()) {
|
|
||||||
if (!writeFrame(outputFile, *frame)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outputFile.close();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileClip::~FileClip() {
|
FileClip::~FileClip() {
|
||||||
|
|
|
@ -23,16 +23,13 @@
|
||||||
|
|
||||||
using namespace recording;
|
using namespace recording;
|
||||||
|
|
||||||
const QString PointerClip::FRAME_TYPE_MAP = QStringLiteral("frameTypes");
|
|
||||||
const QString PointerClip::FRAME_COMREPSSION_FLAG = QStringLiteral("compressed");
|
|
||||||
|
|
||||||
using FrameTranslationMap = QMap<FrameType, FrameType>;
|
using FrameTranslationMap = QMap<FrameType, FrameType>;
|
||||||
|
|
||||||
FrameTranslationMap parseTranslationMap(const QJsonDocument& doc) {
|
FrameTranslationMap parseTranslationMap(const QJsonDocument& doc) {
|
||||||
FrameTranslationMap results;
|
FrameTranslationMap results;
|
||||||
auto headerObj = doc.object();
|
auto headerObj = doc.object();
|
||||||
if (headerObj.contains(PointerClip::FRAME_TYPE_MAP)) {
|
if (headerObj.contains(Clip::FRAME_TYPE_MAP)) {
|
||||||
auto frameTypeObj = headerObj[PointerClip::FRAME_TYPE_MAP].toObject();
|
auto frameTypeObj = headerObj[Clip::FRAME_TYPE_MAP].toObject();
|
||||||
auto currentFrameTypes = Frame::getFrameTypes();
|
auto currentFrameTypes = Frame::getFrameTypes();
|
||||||
for (auto frameTypeName : frameTypeObj.keys()) {
|
for (auto frameTypeName : frameTypeObj.keys()) {
|
||||||
qDebug() << frameTypeName;
|
qDebug() << frameTypeName;
|
||||||
|
|
|
@ -44,9 +44,6 @@ public:
|
||||||
|
|
||||||
// FIXME move to frame?
|
// FIXME move to frame?
|
||||||
static const qint64 MINIMUM_FRAME_SIZE = sizeof(FrameType) + sizeof(Frame::Time) + sizeof(FrameSize);
|
static const qint64 MINIMUM_FRAME_SIZE = sizeof(FrameType) + sizeof(Frame::Time) + sizeof(FrameSize);
|
||||||
static const QString FRAME_TYPE_MAP;
|
|
||||||
static const QString FRAME_COMREPSSION_FLAG;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void reset();
|
void reset();
|
||||||
virtual FrameConstPointer readFrame(size_t index) const override;
|
virtual FrameConstPointer readFrame(size_t index) const override;
|
||||||
|
|
Loading…
Reference in a new issue