Add duration and resolution to files
This commit is contained in:
parent
d3471a1097
commit
fd83858715
@ -376,6 +376,7 @@ Item {
|
|||||||
required property string filesize
|
required property string filesize
|
||||||
required property string url
|
required property string url
|
||||||
required property string thumbnailUrl
|
required property string thumbnailUrl
|
||||||
|
required property string duration
|
||||||
required property bool isOnlyEmoji
|
required property bool isOnlyEmoji
|
||||||
required property bool isSender
|
required property bool isSender
|
||||||
required property bool isEncrypted
|
required property bool isEncrypted
|
||||||
@ -492,6 +493,7 @@ Item {
|
|||||||
filesize: wrapper.filesize
|
filesize: wrapper.filesize
|
||||||
url: wrapper.url
|
url: wrapper.url
|
||||||
thumbnailUrl: wrapper.thumbnailUrl
|
thumbnailUrl: wrapper.thumbnailUrl
|
||||||
|
duration: wrapper.duration
|
||||||
isOnlyEmoji: wrapper.isOnlyEmoji
|
isOnlyEmoji: wrapper.isOnlyEmoji
|
||||||
isSender: wrapper.isSender
|
isSender: wrapper.isSender
|
||||||
isEncrypted: wrapper.isEncrypted
|
isEncrypted: wrapper.isEncrypted
|
||||||
|
@ -41,6 +41,7 @@ Item {
|
|||||||
required property var reactions
|
required property var reactions
|
||||||
required property int trustlevel
|
required property int trustlevel
|
||||||
required property int encryptionError
|
required property int encryptionError
|
||||||
|
required property int duration
|
||||||
required property var timestamp
|
required property var timestamp
|
||||||
required property int status
|
required property int status
|
||||||
required property int relatedEventCacheBuster
|
required property int relatedEventCacheBuster
|
||||||
@ -128,6 +129,7 @@ Item {
|
|||||||
userId: r.relatedEventCacheBuster, fromModel(Room.UserId) ?? ""
|
userId: r.relatedEventCacheBuster, fromModel(Room.UserId) ?? ""
|
||||||
userName: r.relatedEventCacheBuster, fromModel(Room.UserName) ?? ""
|
userName: r.relatedEventCacheBuster, fromModel(Room.UserName) ?? ""
|
||||||
thumbnailUrl: r.relatedEventCacheBuster, fromModel(Room.ThumbnailUrl) ?? ""
|
thumbnailUrl: r.relatedEventCacheBuster, fromModel(Room.ThumbnailUrl) ?? ""
|
||||||
|
duration: r.relatedEventCacheBuster, fromModel(Room.Duration) ?? ""
|
||||||
roomTopic: r.relatedEventCacheBuster, fromModel(Room.RoomTopic) ?? ""
|
roomTopic: r.relatedEventCacheBuster, fromModel(Room.RoomTopic) ?? ""
|
||||||
roomName: r.relatedEventCacheBuster, fromModel(Room.RoomName) ?? ""
|
roomName: r.relatedEventCacheBuster, fromModel(Room.RoomName) ?? ""
|
||||||
callType: r.relatedEventCacheBuster, fromModel(Room.CallType) ?? ""
|
callType: r.relatedEventCacheBuster, fromModel(Room.CallType) ?? ""
|
||||||
@ -154,6 +156,7 @@ Item {
|
|||||||
typeString: r.typeString ?? ""
|
typeString: r.typeString ?? ""
|
||||||
url: r.url
|
url: r.url
|
||||||
thumbnailUrl: r.thumbnailUrl
|
thumbnailUrl: r.thumbnailUrl
|
||||||
|
duration: r.duration
|
||||||
originalWidth: r.originalWidth
|
originalWidth: r.originalWidth
|
||||||
isOnlyEmoji: r.isOnlyEmoji
|
isOnlyEmoji: r.isOnlyEmoji
|
||||||
isStateEvent: r.isStateEvent
|
isStateEvent: r.isStateEvent
|
||||||
|
@ -18,6 +18,7 @@ Item {
|
|||||||
required property int type
|
required property int type
|
||||||
required property string typeString
|
required property string typeString
|
||||||
required property int originalWidth
|
required property int originalWidth
|
||||||
|
required property int duration
|
||||||
required property string blurhash
|
required property string blurhash
|
||||||
required property string body
|
required property string body
|
||||||
required property string formattedBody
|
required property string formattedBody
|
||||||
@ -161,6 +162,7 @@ Item {
|
|||||||
url: d.url
|
url: d.url
|
||||||
body: d.body
|
body: d.body
|
||||||
filesize: d.filesize
|
filesize: d.filesize
|
||||||
|
duration: d.duration
|
||||||
metadataWidth: d.metadataWidth
|
metadataWidth: d.metadataWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,6 +180,7 @@ Item {
|
|||||||
url: d.url
|
url: d.url
|
||||||
body: d.body
|
body: d.body
|
||||||
filesize: d.filesize
|
filesize: d.filesize
|
||||||
|
duration: d.duration
|
||||||
metadataWidth: d.metadataWidth
|
metadataWidth: d.metadataWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ Item {
|
|||||||
required property double proportionalHeight
|
required property double proportionalHeight
|
||||||
required property int type
|
required property int type
|
||||||
required property int originalWidth
|
required property int originalWidth
|
||||||
|
required property int duration
|
||||||
required property string thumbnailUrl
|
required property string thumbnailUrl
|
||||||
required property string eventId
|
required property string eventId
|
||||||
required property string url
|
required property string url
|
||||||
@ -85,7 +86,7 @@ Item {
|
|||||||
anchors.bottom: fileInfoLabel.top
|
anchors.bottom: fileInfoLabel.top
|
||||||
playingVideo: type == MtxEvent.VideoMessage
|
playingVideo: type == MtxEvent.VideoMessage
|
||||||
positionValue: mxcmedia.position
|
positionValue: mxcmedia.position
|
||||||
duration: mxcmedia.duration
|
duration: mediaLoaded ? mxcmedia.duration : content.duration
|
||||||
mediaLoaded: mxcmedia.loaded
|
mediaLoaded: mxcmedia.loaded
|
||||||
mediaState: mxcmedia.state
|
mediaState: mxcmedia.state
|
||||||
onPositionChanged: mxcmedia.position = position
|
onPositionChanged: mxcmedia.position = position
|
||||||
|
@ -34,6 +34,7 @@ Item {
|
|||||||
property string roomTopic
|
property string roomTopic
|
||||||
property string roomName
|
property string roomName
|
||||||
property string callType
|
property string callType
|
||||||
|
property int duration
|
||||||
property int encryptionError
|
property int encryptionError
|
||||||
property int relatedEventCacheBuster
|
property int relatedEventCacheBuster
|
||||||
property int maxWidth
|
property int maxWidth
|
||||||
@ -112,6 +113,7 @@ Item {
|
|||||||
typeString: r.typeString ?? ""
|
typeString: r.typeString ?? ""
|
||||||
url: r.url
|
url: r.url
|
||||||
thumbnailUrl: r.thumbnailUrl
|
thumbnailUrl: r.thumbnailUrl
|
||||||
|
duration: r.duration
|
||||||
originalWidth: r.originalWidth
|
originalWidth: r.originalWidth
|
||||||
isOnlyEmoji: r.isOnlyEmoji
|
isOnlyEmoji: r.isOnlyEmoji
|
||||||
isStateEvent: r.isStateEvent
|
isStateEvent: r.isStateEvent
|
||||||
|
@ -214,7 +214,7 @@ Rectangle {
|
|||||||
|
|
||||||
Label {
|
Label {
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
text: (!control.mediaLoaded) ? "-- / --" : (durationToString(control.positionValue) + " / " + durationToString(control.duration))
|
text: (!control.mediaLoaded ? "-- " : durationToString(control.positionValue)) + " / " + durationToString(control.duration)
|
||||||
color: Nheko.colors.text
|
color: Nheko.colors.text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,6 +169,20 @@ struct EventThumbnailUrl
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct EventDuration
|
||||||
|
{
|
||||||
|
template<class Content>
|
||||||
|
using thumbnail_url_t = decltype(Content::info.duration);
|
||||||
|
template<class T>
|
||||||
|
uint64_t operator()(const mtx::events::Event<T> &e)
|
||||||
|
{
|
||||||
|
if constexpr (is_detected<thumbnail_url_t, T>::value) {
|
||||||
|
return e.content.info.duration;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct EventBlurhash
|
struct EventBlurhash
|
||||||
{
|
{
|
||||||
template<class Content>
|
template<class Content>
|
||||||
@ -420,6 +434,11 @@ mtx::accessors::thumbnail_url(const mtx::events::collections::TimelineEvents &ev
|
|||||||
{
|
{
|
||||||
return std::visit(EventThumbnailUrl{}, event);
|
return std::visit(EventThumbnailUrl{}, event);
|
||||||
}
|
}
|
||||||
|
uint64_t
|
||||||
|
mtx::accessors::duration(const mtx::events::collections::TimelineEvents &event)
|
||||||
|
{
|
||||||
|
return std::visit(EventDuration{}, event);
|
||||||
|
}
|
||||||
std::string
|
std::string
|
||||||
mtx::accessors::blurhash(const mtx::events::collections::TimelineEvents &event)
|
mtx::accessors::blurhash(const mtx::events::collections::TimelineEvents &event)
|
||||||
{
|
{
|
||||||
|
@ -83,6 +83,8 @@ std::string
|
|||||||
url(const mtx::events::collections::TimelineEvents &event);
|
url(const mtx::events::collections::TimelineEvents &event);
|
||||||
std::string
|
std::string
|
||||||
thumbnail_url(const mtx::events::collections::TimelineEvents &event);
|
thumbnail_url(const mtx::events::collections::TimelineEvents &event);
|
||||||
|
uint64_t
|
||||||
|
duration(const mtx::events::collections::TimelineEvents &event);
|
||||||
std::string
|
std::string
|
||||||
blurhash(const mtx::events::collections::TimelineEvents &event);
|
blurhash(const mtx::events::collections::TimelineEvents &event);
|
||||||
std::string
|
std::string
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QInputMethod>
|
#include <QInputMethod>
|
||||||
|
#include <QMediaMetaData>
|
||||||
|
#include <QMediaPlayer>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QMimeDatabase>
|
#include <QMimeDatabase>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
@ -452,7 +454,8 @@ InputBar::audio(const QString &filename,
|
|||||||
const std::optional<mtx::crypto::EncryptedFile> &file,
|
const std::optional<mtx::crypto::EncryptedFile> &file,
|
||||||
const QString &url,
|
const QString &url,
|
||||||
const QString &mime,
|
const QString &mime,
|
||||||
uint64_t dsize)
|
uint64_t dsize,
|
||||||
|
uint64_t duration)
|
||||||
{
|
{
|
||||||
mtx::events::msg::Audio audio;
|
mtx::events::msg::Audio audio;
|
||||||
audio.info.mimetype = mime.toStdString();
|
audio.info.mimetype = mime.toStdString();
|
||||||
@ -460,6 +463,9 @@ InputBar::audio(const QString &filename,
|
|||||||
audio.body = filename.toStdString();
|
audio.body = filename.toStdString();
|
||||||
audio.url = url.toStdString();
|
audio.url = url.toStdString();
|
||||||
|
|
||||||
|
if (duration > 0)
|
||||||
|
audio.info.duration = duration;
|
||||||
|
|
||||||
if (file)
|
if (file)
|
||||||
audio.file = file;
|
audio.file = file;
|
||||||
else
|
else
|
||||||
@ -482,13 +488,22 @@ InputBar::video(const QString &filename,
|
|||||||
const std::optional<mtx::crypto::EncryptedFile> &file,
|
const std::optional<mtx::crypto::EncryptedFile> &file,
|
||||||
const QString &url,
|
const QString &url,
|
||||||
const QString &mime,
|
const QString &mime,
|
||||||
uint64_t dsize)
|
uint64_t dsize,
|
||||||
|
uint64_t duration,
|
||||||
|
const QSize &dimensions)
|
||||||
{
|
{
|
||||||
mtx::events::msg::Video video;
|
mtx::events::msg::Video video;
|
||||||
video.info.mimetype = mime.toStdString();
|
video.info.mimetype = mime.toStdString();
|
||||||
video.info.size = dsize;
|
video.info.size = dsize;
|
||||||
video.body = filename.toStdString();
|
video.body = filename.toStdString();
|
||||||
|
|
||||||
|
if (duration > 0)
|
||||||
|
video.info.duration = duration;
|
||||||
|
if (dimensions.isValid()) {
|
||||||
|
video.info.h = dimensions.height();
|
||||||
|
video.info.w = dimensions.width();
|
||||||
|
}
|
||||||
|
|
||||||
if (file)
|
if (file)
|
||||||
video.file = file;
|
video.file = file;
|
||||||
else
|
else
|
||||||
@ -645,6 +660,7 @@ MediaUpload::MediaUpload(std::unique_ptr<QIODevice> source_,
|
|||||||
source->open(QIODevice::ReadOnly);
|
source->open(QIODevice::ReadOnly);
|
||||||
|
|
||||||
data = source->readAll();
|
data = source->readAll();
|
||||||
|
source->reset();
|
||||||
|
|
||||||
if (!data.size()) {
|
if (!data.size()) {
|
||||||
nhlog::ui()->warn("Attempted to upload zero-byte file?! Mimetype {}, filename {}",
|
nhlog::ui()->warn("Attempted to upload zero-byte file?! Mimetype {}, filename {}",
|
||||||
@ -657,6 +673,8 @@ MediaUpload::MediaUpload(std::unique_ptr<QIODevice> source_,
|
|||||||
nhlog::ui()->debug("Mime: {}", mimetype_.toStdString());
|
nhlog::ui()->debug("Mime: {}", mimetype_.toStdString());
|
||||||
if (mimeClass_ == u"image") {
|
if (mimeClass_ == u"image") {
|
||||||
QImage img = utils::readImage(data);
|
QImage img = utils::readImage(data);
|
||||||
|
setThumbnail(img.scaled(
|
||||||
|
std::min(800, img.width()), std::min(800, img.height()), Qt::KeepAspectRatioByExpanding));
|
||||||
|
|
||||||
dimensions_ = img.size();
|
dimensions_ = img.size();
|
||||||
if (img.height() > 200 && img.width() > 360)
|
if (img.height() > 200 && img.width() > 360)
|
||||||
@ -672,6 +690,78 @@ MediaUpload::MediaUpload(std::unique_ptr<QIODevice> source_,
|
|||||||
}
|
}
|
||||||
blurhash_ =
|
blurhash_ =
|
||||||
QString::fromStdString(blurhash::encode(data_.data(), img.width(), img.height(), 4, 3));
|
QString::fromStdString(blurhash::encode(data_.data(), img.width(), img.height(), 4, 3));
|
||||||
|
} else if (mimeClass_ == u"video" || mimeClass_ == u"audio") {
|
||||||
|
auto mediaPlayer = new QMediaPlayer(
|
||||||
|
this,
|
||||||
|
mimeClass_ == u"video" ? QFlags{QMediaPlayer::StreamPlayback, QMediaPlayer::VideoSurface}
|
||||||
|
: QFlags{QMediaPlayer::StreamPlayback});
|
||||||
|
mediaPlayer->setMuted(true);
|
||||||
|
|
||||||
|
if (mimeClass_ == u"video") {
|
||||||
|
auto newSurface = new InputVideoSurface(this);
|
||||||
|
connect(
|
||||||
|
newSurface, &InputVideoSurface::newImage, this, [this, mediaPlayer](QImage img) {
|
||||||
|
mediaPlayer->stop();
|
||||||
|
|
||||||
|
nhlog::ui()->debug("Got image {}x{}", img.width(), img.height());
|
||||||
|
|
||||||
|
this->setThumbnail(img);
|
||||||
|
|
||||||
|
if (!dimensions_.isValid())
|
||||||
|
this->dimensions_ = img.size();
|
||||||
|
|
||||||
|
if (img.height() > 200 && img.width() > 360)
|
||||||
|
img = img.scaled(360, 200, Qt::KeepAspectRatioByExpanding);
|
||||||
|
std::vector<unsigned char> data_;
|
||||||
|
for (int y = 0; y < img.height(); y++) {
|
||||||
|
for (int x = 0; x < img.width(); x++) {
|
||||||
|
auto p = img.pixel(x, y);
|
||||||
|
data_.push_back(static_cast<unsigned char>(qRed(p)));
|
||||||
|
data_.push_back(static_cast<unsigned char>(qGreen(p)));
|
||||||
|
data_.push_back(static_cast<unsigned char>(qBlue(p)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blurhash_ = QString::fromStdString(
|
||||||
|
blurhash::encode(data_.data(), img.width(), img.height(), 4, 3));
|
||||||
|
});
|
||||||
|
mediaPlayer->setVideoOutput(newSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(mediaPlayer,
|
||||||
|
qOverload<QMediaPlayer::Error>(&QMediaPlayer::error),
|
||||||
|
this,
|
||||||
|
[this, mediaPlayer](QMediaPlayer::Error error) {
|
||||||
|
nhlog::ui()->info("Media player error {} and errorStr {}",
|
||||||
|
error,
|
||||||
|
mediaPlayer->errorString().toStdString());
|
||||||
|
});
|
||||||
|
connect(mediaPlayer,
|
||||||
|
&QMediaPlayer::mediaStatusChanged,
|
||||||
|
[this, mediaPlayer](QMediaPlayer::MediaStatus status) {
|
||||||
|
nhlog::ui()->info(
|
||||||
|
"Media player status {} and error {}", status, mediaPlayer->error());
|
||||||
|
});
|
||||||
|
connect(mediaPlayer,
|
||||||
|
qOverload<const QString &, const QVariant &>(&QMediaPlayer::metaDataChanged),
|
||||||
|
[this, mediaPlayer](QString t, QVariant) {
|
||||||
|
nhlog::ui()->info("Got metadata {}", t.toStdString());
|
||||||
|
|
||||||
|
if (mediaPlayer->duration() > 0)
|
||||||
|
this->duration_ = mediaPlayer->duration();
|
||||||
|
|
||||||
|
dimensions_ = mediaPlayer->metaData(QMediaMetaData::Resolution).toSize();
|
||||||
|
auto orientation = mediaPlayer->metaData(QMediaMetaData::Orientation).toInt();
|
||||||
|
if (orientation == 90 || orientation == 270) {
|
||||||
|
dimensions_.transpose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
connect(mediaPlayer, &QMediaPlayer::durationChanged, [this, mediaPlayer](qint64 duration) {
|
||||||
|
if (duration > 0)
|
||||||
|
this->duration_ = mediaPlayer->duration();
|
||||||
|
nhlog::ui()->info("Duration changed {}", duration);
|
||||||
|
});
|
||||||
|
mediaPlayer->setMedia(QMediaContent(originalFilename_), source.get());
|
||||||
|
mediaPlayer->play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -721,9 +811,9 @@ InputBar::finalizeUpload(MediaUpload *upload, QString url)
|
|||||||
if (mimeClass == u"image")
|
if (mimeClass == u"image")
|
||||||
image(filename, encryptedFile, url, mime, size, upload->dimensions(), upload->blurhash());
|
image(filename, encryptedFile, url, mime, size, upload->dimensions(), upload->blurhash());
|
||||||
else if (mimeClass == u"audio")
|
else if (mimeClass == u"audio")
|
||||||
audio(filename, encryptedFile, url, mime, size);
|
audio(filename, encryptedFile, url, mime, size, upload->duration());
|
||||||
else if (mimeClass == u"video")
|
else if (mimeClass == u"video")
|
||||||
video(filename, encryptedFile, url, mime, size);
|
video(filename, encryptedFile, url, mime, size, upload->duration(), upload->dimensions());
|
||||||
else
|
else
|
||||||
file(filename, encryptedFile, url, mime, size);
|
file(filename, encryptedFile, url, mime, size);
|
||||||
|
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QAbstractVideoSurface>
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
|
#include <QImage>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
@ -29,6 +31,90 @@ enum class MarkdownOverride
|
|||||||
OFF,
|
OFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class InputVideoSurface : public QAbstractVideoSurface
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
InputVideoSurface(QObject *parent)
|
||||||
|
: QAbstractVideoSurface(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool present(const QVideoFrame &frame) override
|
||||||
|
{
|
||||||
|
QImage::Format format = QImage::Format_Invalid;
|
||||||
|
|
||||||
|
switch (frame.pixelFormat()) {
|
||||||
|
case QVideoFrame::Format_ARGB32:
|
||||||
|
format = QImage::Format_ARGB32;
|
||||||
|
break;
|
||||||
|
case QVideoFrame::Format_ARGB32_Premultiplied:
|
||||||
|
format = QImage::Format_ARGB32_Premultiplied;
|
||||||
|
break;
|
||||||
|
case QVideoFrame::Format_RGB24:
|
||||||
|
format = QImage::Format_RGB888;
|
||||||
|
break;
|
||||||
|
case QVideoFrame::Format_BGR24:
|
||||||
|
format = QImage::Format_BGR888;
|
||||||
|
break;
|
||||||
|
case QVideoFrame::Format_RGB32:
|
||||||
|
format = QImage::Format_RGB32;
|
||||||
|
break;
|
||||||
|
case QVideoFrame::Format_RGB565:
|
||||||
|
format = QImage::Format_RGB16;
|
||||||
|
break;
|
||||||
|
case QVideoFrame::Format_RGB555:
|
||||||
|
format = QImage::Format_RGB555;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
format = QImage::Format_Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format == QImage::Format_Invalid) {
|
||||||
|
emit newImage({});
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
QVideoFrame frametodraw(frame);
|
||||||
|
|
||||||
|
if (!frametodraw.map(QAbstractVideoBuffer::ReadOnly)) {
|
||||||
|
emit newImage({});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is a shallow operation. it just refer the frame buffer
|
||||||
|
QImage image(frametodraw.bits(),
|
||||||
|
frametodraw.width(),
|
||||||
|
frametodraw.height(),
|
||||||
|
frametodraw.bytesPerLine(),
|
||||||
|
QImage::Format_RGB444);
|
||||||
|
|
||||||
|
emit newImage(std::move(image));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QVideoFrame::PixelFormat>
|
||||||
|
supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const override
|
||||||
|
{
|
||||||
|
if (type == QAbstractVideoBuffer::NoHandle) {
|
||||||
|
return {
|
||||||
|
QVideoFrame::Format_ARGB32,
|
||||||
|
QVideoFrame::Format_ARGB32_Premultiplied,
|
||||||
|
QVideoFrame::Format_RGB24,
|
||||||
|
QVideoFrame::Format_BGR24,
|
||||||
|
QVideoFrame::Format_RGB32,
|
||||||
|
QVideoFrame::Format_RGB565,
|
||||||
|
QVideoFrame::Format_RGB555,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void newImage(QImage img);
|
||||||
|
};
|
||||||
|
|
||||||
class MediaUpload : public QObject
|
class MediaUpload : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -67,6 +153,7 @@ public:
|
|||||||
[[nodiscard]] QString filename() const { return originalFilename_; }
|
[[nodiscard]] QString filename() const { return originalFilename_; }
|
||||||
[[nodiscard]] QString blurhash() const { return blurhash_; }
|
[[nodiscard]] QString blurhash() const { return blurhash_; }
|
||||||
[[nodiscard]] uint64_t size() const { return size_; }
|
[[nodiscard]] uint64_t size() const { return size_; }
|
||||||
|
[[nodiscard]] uint64_t duration() const { return duration_; }
|
||||||
[[nodiscard]] std::optional<mtx::crypto::EncryptedFile> encryptedFile_()
|
[[nodiscard]] std::optional<mtx::crypto::EncryptedFile> encryptedFile_()
|
||||||
{
|
{
|
||||||
return encryptedFile;
|
return encryptedFile;
|
||||||
@ -82,6 +169,7 @@ public slots:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updateThumbnailUrl(QString url) { this->thumbnailUrl_ = std::move(url); }
|
void updateThumbnailUrl(QString url) { this->thumbnailUrl_ = std::move(url); }
|
||||||
|
void setThumbnail(QImage img) { this->thumbnail_ = std::move(img); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// void uploadThumbnail(QImage img);
|
// void uploadThumbnail(QImage img);
|
||||||
@ -96,8 +184,11 @@ public:
|
|||||||
QString url_;
|
QString url_;
|
||||||
std::optional<mtx::crypto::EncryptedFile> encryptedFile;
|
std::optional<mtx::crypto::EncryptedFile> encryptedFile;
|
||||||
|
|
||||||
|
QImage thumbnail_;
|
||||||
|
|
||||||
QSize dimensions_;
|
QSize dimensions_;
|
||||||
uint64_t size_ = 0;
|
uint64_t size_ = 0;
|
||||||
|
uint64_t duration_ = 0;
|
||||||
bool encrypt_;
|
bool encrypt_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -181,12 +272,15 @@ private:
|
|||||||
const std::optional<mtx::crypto::EncryptedFile> &file,
|
const std::optional<mtx::crypto::EncryptedFile> &file,
|
||||||
const QString &url,
|
const QString &url,
|
||||||
const QString &mime,
|
const QString &mime,
|
||||||
uint64_t dsize);
|
uint64_t dsize,
|
||||||
|
uint64_t duration);
|
||||||
void video(const QString &filename,
|
void video(const QString &filename,
|
||||||
const std::optional<mtx::crypto::EncryptedFile> &file,
|
const std::optional<mtx::crypto::EncryptedFile> &file,
|
||||||
const QString &url,
|
const QString &url,
|
||||||
const QString &mime,
|
const QString &mime,
|
||||||
uint64_t dsize);
|
uint64_t dsize,
|
||||||
|
uint64_t duration,
|
||||||
|
const QSize &dimensions);
|
||||||
|
|
||||||
void startUploadFromPath(const QString &path);
|
void startUploadFromPath(const QString &path);
|
||||||
void startUploadFromMimeData(const QMimeData &source, const QString &format);
|
void startUploadFromMimeData(const QMimeData &source, const QString &format);
|
||||||
|
@ -474,6 +474,7 @@ TimelineModel::roleNames() const
|
|||||||
{Timestamp, "timestamp"},
|
{Timestamp, "timestamp"},
|
||||||
{Url, "url"},
|
{Url, "url"},
|
||||||
{ThumbnailUrl, "thumbnailUrl"},
|
{ThumbnailUrl, "thumbnailUrl"},
|
||||||
|
{Duration, "duration"},
|
||||||
{Blurhash, "blurhash"},
|
{Blurhash, "blurhash"},
|
||||||
{Filename, "filename"},
|
{Filename, "filename"},
|
||||||
{Filesize, "filesize"},
|
{Filesize, "filesize"},
|
||||||
@ -627,6 +628,8 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
|
|||||||
return QVariant(QString::fromStdString(url(event)));
|
return QVariant(QString::fromStdString(url(event)));
|
||||||
case ThumbnailUrl:
|
case ThumbnailUrl:
|
||||||
return QVariant(QString::fromStdString(thumbnail_url(event)));
|
return QVariant(QString::fromStdString(thumbnail_url(event)));
|
||||||
|
case Duration:
|
||||||
|
return QVariant(static_cast<qulonglong>(duration(event)));
|
||||||
case Blurhash:
|
case Blurhash:
|
||||||
return QVariant(QString::fromStdString(blurhash(event)));
|
return QVariant(QString::fromStdString(blurhash(event)));
|
||||||
case Filename:
|
case Filename:
|
||||||
@ -739,6 +742,7 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
|
|||||||
m.insert(names[Timestamp], data(event, static_cast<int>(Timestamp)));
|
m.insert(names[Timestamp], data(event, static_cast<int>(Timestamp)));
|
||||||
m.insert(names[Url], data(event, static_cast<int>(Url)));
|
m.insert(names[Url], data(event, static_cast<int>(Url)));
|
||||||
m.insert(names[ThumbnailUrl], data(event, static_cast<int>(ThumbnailUrl)));
|
m.insert(names[ThumbnailUrl], data(event, static_cast<int>(ThumbnailUrl)));
|
||||||
|
m.insert(names[Duration], data(event, static_cast<int>(Duration)));
|
||||||
m.insert(names[Blurhash], data(event, static_cast<int>(Blurhash)));
|
m.insert(names[Blurhash], data(event, static_cast<int>(Blurhash)));
|
||||||
m.insert(names[Filename], data(event, static_cast<int>(Filename)));
|
m.insert(names[Filename], data(event, static_cast<int>(Filename)));
|
||||||
m.insert(names[Filesize], data(event, static_cast<int>(Filesize)));
|
m.insert(names[Filesize], data(event, static_cast<int>(Filesize)));
|
||||||
|
@ -215,6 +215,7 @@ public:
|
|||||||
Timestamp,
|
Timestamp,
|
||||||
Url,
|
Url,
|
||||||
ThumbnailUrl,
|
ThumbnailUrl,
|
||||||
|
Duration,
|
||||||
Blurhash,
|
Blurhash,
|
||||||
Filename,
|
Filename,
|
||||||
Filesize,
|
Filesize,
|
||||||
|
Loading…
Reference in New Issue
Block a user