mirror of
https://github.com/lubosz/overte.git
synced 2025-04-07 04:42:49 +02:00
Support writing a clip to a qbytearray
This commit is contained in:
parent
e6db72c887
commit
5adcbcaf5f
5 changed files with 90 additions and 72 deletions
|
@ -13,6 +13,11 @@
|
|||
#include "impl/FileClip.h"
|
||||
#include "impl/BufferClip.h"
|
||||
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
using namespace recording;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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() {
|
||||
return std::make_shared<BufferClip>();
|
||||
}
|
||||
|
@ -37,4 +51,70 @@ void Clip::seek(float offset) {
|
|||
|
||||
float Clip::position() const {
|
||||
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 addFrame(FrameConstPointer) = 0;
|
||||
|
||||
bool write(QIODevice& output);
|
||||
|
||||
static Pointer fromFile(const QString& filePath);
|
||||
static void toFile(const QString& filePath, const ConstPointer& clip);
|
||||
static QByteArray toBuffer(const ConstPointer& clip);
|
||||
static Pointer newClip();
|
||||
|
||||
static const QString FRAME_TYPE_MAP;
|
||||
static const QString FRAME_COMREPSSION_FLAG;
|
||||
|
||||
protected:
|
||||
friend class WrapperClip;
|
||||
using Mutex = std::recursive_mutex;
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
||||
#include <Finally.h>
|
||||
|
||||
|
@ -40,41 +38,7 @@ QString FileClip::getName() const {
|
|||
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) {
|
||||
// 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(); });
|
||||
{
|
||||
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;
|
||||
return clip->write(outputFile);
|
||||
}
|
||||
|
||||
FileClip::~FileClip() {
|
||||
|
|
|
@ -23,16 +23,13 @@
|
|||
|
||||
using namespace recording;
|
||||
|
||||
const QString PointerClip::FRAME_TYPE_MAP = QStringLiteral("frameTypes");
|
||||
const QString PointerClip::FRAME_COMREPSSION_FLAG = QStringLiteral("compressed");
|
||||
|
||||
using FrameTranslationMap = QMap<FrameType, FrameType>;
|
||||
|
||||
FrameTranslationMap parseTranslationMap(const QJsonDocument& doc) {
|
||||
FrameTranslationMap results;
|
||||
auto headerObj = doc.object();
|
||||
if (headerObj.contains(PointerClip::FRAME_TYPE_MAP)) {
|
||||
auto frameTypeObj = headerObj[PointerClip::FRAME_TYPE_MAP].toObject();
|
||||
if (headerObj.contains(Clip::FRAME_TYPE_MAP)) {
|
||||
auto frameTypeObj = headerObj[Clip::FRAME_TYPE_MAP].toObject();
|
||||
auto currentFrameTypes = Frame::getFrameTypes();
|
||||
for (auto frameTypeName : frameTypeObj.keys()) {
|
||||
qDebug() << frameTypeName;
|
||||
|
|
|
@ -44,9 +44,6 @@ public:
|
|||
|
||||
// FIXME move to frame?
|
||||
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:
|
||||
void reset();
|
||||
virtual FrameConstPointer readFrame(size_t index) const override;
|
||||
|
|
Loading…
Reference in a new issue