mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/telegramdesktop/tdesktop
synced 2026-09-21 00:23:56 +08:00
152 lines
3.5 KiB
C++
152 lines
3.5 KiB
C++
/*
|
|
This file is part of Telegram Desktop,
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
For license and copyright information please follow this link:
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
*/
|
|
#include "editor/scene/scene_item_video.h"
|
|
|
|
#include "ui/image/image_prepare.h"
|
|
#include "ui/rect.h"
|
|
|
|
#include <QtCore/QFile>
|
|
|
|
namespace Editor {
|
|
namespace {
|
|
|
|
constexpr auto kPlaybackFrameSide = 512;
|
|
|
|
[[nodiscard]] QSize FrameSizeFor(const QImage &thumbnail) {
|
|
const auto size = thumbnail.size();
|
|
if (size.isEmpty()) {
|
|
return Size(kPlaybackFrameSide);
|
|
} else if (size.width() <= kPlaybackFrameSide
|
|
&& size.height() <= kPlaybackFrameSide) {
|
|
return size;
|
|
}
|
|
return size.scaled(Size(kPlaybackFrameSide), Qt::KeepAspectRatio);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
ItemVideo::ItemVideo(std::shared_ptr<Source> source, ItemBase::Data data)
|
|
: ItemAnimated(std::move(data))
|
|
, _source(std::move(source))
|
|
, _frameSize(FrameSizeFor(_source->thumbnail))
|
|
, _image(_source->thumbnail) {
|
|
if (flipped()) {
|
|
performFlip();
|
|
}
|
|
setAspectRatio(_image.isNull()
|
|
? 1.
|
|
: (_image.height() / float64(_image.width())));
|
|
createPlayer();
|
|
}
|
|
|
|
void ItemVideo::createPlayer() {
|
|
if (!hasContent()) {
|
|
return;
|
|
}
|
|
const auto callback = [=](::Media::Clip::Notification value) {
|
|
clipCallback(value);
|
|
};
|
|
_reader = _source->path.isEmpty()
|
|
? ::Media::Clip::MakeReader(_source->content, callback)
|
|
: ::Media::Clip::MakeReader(_source->path, callback);
|
|
}
|
|
|
|
void ItemVideo::clipCallback(::Media::Clip::Notification notification) {
|
|
using namespace ::Media::Clip;
|
|
if (notification == Notification::Reinit) {
|
|
if (_reader && _reader->state() == State::Error) {
|
|
_reader.setBad();
|
|
} else if (_reader && _reader->ready() && !_reader->started()) {
|
|
_reader->start({ .frame = _frameSize });
|
|
}
|
|
}
|
|
update();
|
|
}
|
|
|
|
bool ItemVideo::animated() const {
|
|
return _reader.valid() || _releasedAnimation;
|
|
}
|
|
|
|
bool ItemVideo::hasContent() const {
|
|
return !_source->path.isEmpty() || !_source->content.isEmpty();
|
|
}
|
|
|
|
QByteArray ItemVideo::content() const {
|
|
if (_source->path.isEmpty()) {
|
|
return _source->content;
|
|
}
|
|
auto file = QFile(_source->path);
|
|
if (file.size() > Images::kReadBytesLimit
|
|
|| !file.open(QIODevice::ReadOnly)) {
|
|
return QByteArray();
|
|
}
|
|
return file.readAll();
|
|
}
|
|
|
|
crl::time ItemVideo::loopDuration() const {
|
|
return _source->duration;
|
|
}
|
|
|
|
void ItemVideo::releasePlayers() {
|
|
if (!animated()) {
|
|
return;
|
|
}
|
|
_releasedAnimation = true;
|
|
_pendingRecreate = true;
|
|
_reader.reset();
|
|
}
|
|
|
|
void ItemVideo::setStatus(Status status) {
|
|
if (status != Status::Normal) {
|
|
releasePlayers();
|
|
}
|
|
ItemBase::setStatus(status);
|
|
}
|
|
|
|
int ItemVideo::type() const {
|
|
return Type;
|
|
}
|
|
|
|
Media::Encode::AnimatedEntity::Kind ItemVideo::entityKind() const {
|
|
return Media::Encode::AnimatedEntity::Kind::Webm;
|
|
}
|
|
|
|
QImage ItemVideo::currentFrame() {
|
|
if (_reader && _reader->started()) {
|
|
auto result = _reader->current({ .frame = _frameSize }, crl::now());
|
|
if (!result.isNull()) {
|
|
return result;
|
|
}
|
|
}
|
|
return _image;
|
|
}
|
|
|
|
void ItemVideo::paint(
|
|
QPainter *p,
|
|
const QStyleOptionGraphicsItem *option,
|
|
QWidget *w) {
|
|
if (_pendingRecreate && w) {
|
|
_pendingRecreate = false;
|
|
createPlayer();
|
|
}
|
|
const auto live = _reader && _reader->started();
|
|
paintFrame(p, currentFrame(), live, live && flipped());
|
|
ItemBase::paint(p, option, w);
|
|
}
|
|
|
|
void ItemVideo::performFlip() {
|
|
_image = _image.transformed(QTransform().scale(-1, 1));
|
|
update();
|
|
}
|
|
|
|
std::shared_ptr<ItemBase> ItemVideo::duplicate(ItemBase::Data data) const {
|
|
return std::make_shared<ItemVideo>(_source, std::move(data));
|
|
}
|
|
|
|
} // namespace Editor
|