mirror of
https://github.com/kotatogram/kotatogram-desktop
synced 2025-09-05 00:55:12 +00:00
Use Media::Streaming in EditCaptionBox.
This commit is contained in:
@@ -22,13 +22,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_streaming.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "layout.h"
|
||||
#include "media/clip/media_clip_reader.h"
|
||||
#include "media/streaming/media_streaming_instance.h"
|
||||
#include "media/streaming/media_streaming_player.h"
|
||||
#include "media/streaming/media_streaming_document.h"
|
||||
#include "media/streaming/media_streaming_loader_local.h"
|
||||
#include "storage/localimageloader.h"
|
||||
#include "storage/storage_media_prepare.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
@@ -47,6 +52,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include <QtCore/QMimeData>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace ::Media::Streaming;
|
||||
|
||||
} // namespace
|
||||
|
||||
EditCaptionBox::EditCaptionBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionController*> controller,
|
||||
@@ -70,14 +81,13 @@ EditCaptionBox::EditCaptionBox(
|
||||
} else if (const auto document = media->document()) {
|
||||
_documentMedia = document->createMediaView();
|
||||
_documentMedia->thumbnailWanted(_msgId);
|
||||
// #TODO optimize + streamed GIF view
|
||||
image = _documentMedia->thumbnail();
|
||||
dimensions = image
|
||||
? image->size()
|
||||
: document->dimensions;
|
||||
if (document->isAnimation()) {
|
||||
_gifw = document->dimensions.width();
|
||||
_gifh = document->dimensions.height();
|
||||
_gifw = style::ConvertScale(document->dimensions.width());
|
||||
_gifh = style::ConvertScale(document->dimensions.height());
|
||||
_animated = true;
|
||||
} else if (document->isVideoFile()) {
|
||||
_animated = true;
|
||||
@@ -161,7 +171,7 @@ EditCaptionBox::EditCaptionBox(
|
||||
maxW,
|
||||
maxH);
|
||||
};
|
||||
prepareGifPreview();
|
||||
prepareStreamedPreview();
|
||||
} else {
|
||||
maxW = dimensions.width();
|
||||
maxH = dimensions.height();
|
||||
@@ -243,22 +253,25 @@ EditCaptionBox::EditCaptionBox(
|
||||
|
||||
_thumbnailImageLoaded = _thumbnailImage
|
||||
? _thumbnailImage->loaded()
|
||||
: _documentMedia
|
||||
? !_documentMedia->owner()->hasThumbnail()
|
||||
: true;
|
||||
subscribe(_controller->session().downloaderTaskFinished(), [=] {
|
||||
if (!_thumbnailImageLoaded
|
||||
&& _thumbnailImage
|
||||
&& _thumbnailImage->loaded()) {
|
||||
_thumbnailImageLoaded = true;
|
||||
_refreshThumbnail();
|
||||
update();
|
||||
}
|
||||
if (_documentMedia && _documentMedia->owner()->isAnimation()) {
|
||||
if (_documentMedia->loaded() && !_gifPreview) {
|
||||
prepareGifPreview();
|
||||
if (!_thumbnailImageLoaded) {
|
||||
subscribe(_controller->session().downloaderTaskFinished(), [=] {
|
||||
if (_thumbnailImageLoaded) {
|
||||
return;
|
||||
} else if (!_thumbnailImage
|
||||
&& _documentMedia
|
||||
&& _documentMedia->owner()->hasThumbnail()) {
|
||||
_thumbnailImage = _documentMedia->thumbnail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (_thumbnailImage && _thumbnailImage->loaded()) {
|
||||
_thumbnailImageLoaded = true;
|
||||
_refreshThumbnail();
|
||||
update();
|
||||
}
|
||||
});
|
||||
}
|
||||
_field.create(
|
||||
this,
|
||||
st::confirmCaptionArea,
|
||||
@@ -293,6 +306,8 @@ EditCaptionBox::EditCaptionBox(
|
||||
}, _wayWrap->lifetime());
|
||||
}
|
||||
|
||||
EditCaptionBox::~EditCaptionBox() = default;
|
||||
|
||||
void EditCaptionBox::emojiFilterForGeometry(not_null<QEvent*> event) {
|
||||
const auto type = event->type();
|
||||
if (type == QEvent::Move || type == QEvent::Resize) {
|
||||
@@ -311,78 +326,86 @@ void EditCaptionBox::updateEmojiPanelGeometry() {
|
||||
local.x() + _emojiToggle->width() * 3);
|
||||
}
|
||||
|
||||
void EditCaptionBox::prepareGifPreview() {
|
||||
void EditCaptionBox::prepareStreamedPreview() {
|
||||
const auto isListEmpty = _preparedList.files.empty();
|
||||
if (_gifPreview) {
|
||||
if (_streamed) {
|
||||
return;
|
||||
} else if (!_documentMedia && isListEmpty) {
|
||||
return;
|
||||
}
|
||||
const auto callback = [=](Media::Clip::Notification notification) {
|
||||
clipCallback(notification);
|
||||
};
|
||||
if (_documentMedia && _documentMedia->owner()->isAnimation()) {
|
||||
if (_documentMedia->loaded()) {
|
||||
_gifPreview = Media::Clip::MakeReader(
|
||||
_documentMedia.get(),
|
||||
_msgId,
|
||||
callback);
|
||||
}
|
||||
const auto document = _documentMedia
|
||||
? _documentMedia->owner().get()
|
||||
: nullptr;
|
||||
if (document && document->isAnimation()) {
|
||||
setupStreamedPreview(
|
||||
document->owner().streaming().sharedDocument(
|
||||
document,
|
||||
_msgId));
|
||||
} else if (!isListEmpty) {
|
||||
const auto file = &_preparedList.files.front();
|
||||
if (file->path.isEmpty()) {
|
||||
_gifPreview = Media::Clip::MakeReader(
|
||||
file->content,
|
||||
callback);
|
||||
} else {
|
||||
_gifPreview = Media::Clip::MakeReader(
|
||||
file->path,
|
||||
callback);
|
||||
}
|
||||
}
|
||||
if (_gifPreview) {
|
||||
_gifPreview->setAutoplay();
|
||||
auto loader = file->path.isEmpty()
|
||||
? MakeBytesLoader(file->content)
|
||||
: MakeFileLoader(file->path);
|
||||
setupStreamedPreview(std::make_shared<Document>(std::move(loader)));
|
||||
}
|
||||
}
|
||||
|
||||
void EditCaptionBox::clipCallback(Media::Clip::Notification notification) {
|
||||
using namespace Media::Clip;
|
||||
switch (notification) {
|
||||
case NotificationReinit: {
|
||||
if (_gifPreview && _gifPreview->state() == State::Error) {
|
||||
_gifPreview.setBad();
|
||||
}
|
||||
void EditCaptionBox::setupStreamedPreview(std::shared_ptr<Document> shared) {
|
||||
if (!shared) {
|
||||
return;
|
||||
}
|
||||
_streamed = std::make_unique<Instance>(
|
||||
std::move(shared),
|
||||
[=] { update(); });
|
||||
_streamed->lockPlayer();
|
||||
_streamed->player().updates(
|
||||
) | rpl::start_with_next_error([=](Update &&update) {
|
||||
handleStreamingUpdate(std::move(update));
|
||||
}, [=](Error &&error) {
|
||||
handleStreamingError(std::move(error));
|
||||
}, _streamed->lifetime());
|
||||
|
||||
if (_gifPreview && _gifPreview->ready() && !_gifPreview->started()) {
|
||||
const auto calculateGifDimensions = [&]() {
|
||||
const auto scaled = QSize(
|
||||
_gifPreview->width(),
|
||||
_gifPreview->height()).scaled(
|
||||
st::sendMediaPreviewSize * cIntRetinaFactor(),
|
||||
st::confirmMaxHeight * cIntRetinaFactor(),
|
||||
Qt::KeepAspectRatio);
|
||||
_thumbw = _gifw = scaled.width();
|
||||
_thumbh = _gifh = scaled.height();
|
||||
_thumbx = _gifx = (st::boxWideWidth - _gifw) / 2;
|
||||
updateBoxSize();
|
||||
};
|
||||
// If gif file is not mp4,
|
||||
// Its dimension values will be known only after reading.
|
||||
if (_gifw <= 0 || _gifh <= 0) {
|
||||
calculateGifDimensions();
|
||||
}
|
||||
const auto s = QSize(_gifw, _gifh);
|
||||
_gifPreview->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None);
|
||||
}
|
||||
if (_streamed->ready()) {
|
||||
streamingReady(base::duplicate(_streamed->info()));
|
||||
}
|
||||
checkStreamedIsStarted();
|
||||
}
|
||||
|
||||
update();
|
||||
} break;
|
||||
void EditCaptionBox::handleStreamingUpdate(Update &&update) {
|
||||
update.data.match([&](Information &update) {
|
||||
streamingReady(std::move(update));
|
||||
}, [&](const PreloadedVideo &update) {
|
||||
}, [&](const UpdateVideo &update) {
|
||||
this->update();
|
||||
}, [&](const PreloadedAudio &update) {
|
||||
}, [&](const UpdateAudio &update) {
|
||||
}, [&](const WaitingForData &update) {
|
||||
}, [&](MutedByOther) {
|
||||
}, [&](Finished) {
|
||||
});
|
||||
}
|
||||
|
||||
case NotificationRepaint: {
|
||||
if (_gifPreview && !_gifPreview->currentDisplayed()) {
|
||||
update();
|
||||
}
|
||||
} break;
|
||||
void EditCaptionBox::handleStreamingError(Error &&error) {
|
||||
}
|
||||
|
||||
void EditCaptionBox::streamingReady(Information &&info) {
|
||||
const auto calculateGifDimensions = [&]() {
|
||||
const auto scaled = QSize(
|
||||
info.video.size.width(),
|
||||
info.video.size.height()
|
||||
).scaled(
|
||||
st::sendMediaPreviewSize * cIntRetinaFactor(),
|
||||
st::confirmMaxHeight * cIntRetinaFactor(),
|
||||
Qt::KeepAspectRatio);
|
||||
_thumbw = _gifw = scaled.width();
|
||||
_thumbh = _gifh = scaled.height();
|
||||
_thumbx = _gifx = (st::boxWideWidth - _gifw) / 2;
|
||||
updateBoxSize();
|
||||
};
|
||||
// If gif file is not mp4,
|
||||
// Its dimension values will be known only after reading.
|
||||
if (_gifw <= 0 || _gifh <= 0) {
|
||||
calculateGifDimensions();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,7 +423,7 @@ void EditCaptionBox::updateEditPreview() {
|
||||
_animated = false;
|
||||
_photo = false;
|
||||
_doc = false;
|
||||
_gifPreview = nullptr;
|
||||
_streamed = nullptr;
|
||||
_thumbw = _thumbh = _thumbx = 0;
|
||||
_gifw = _gifh = _gifx = 0;
|
||||
|
||||
@@ -479,7 +502,7 @@ void EditCaptionBox::updateEditPreview() {
|
||||
_gifw = _thumbw;
|
||||
_gifh = _thumbh;
|
||||
_gifx = _thumbx;
|
||||
prepareGifPreview();
|
||||
prepareStreamedPreview();
|
||||
}
|
||||
}
|
||||
updateEditMediaButton();
|
||||
@@ -694,6 +717,31 @@ int EditCaptionBox::errorTopSkip() const {
|
||||
return (st::defaultBox.buttonPadding.top() / 2);
|
||||
}
|
||||
|
||||
void EditCaptionBox::checkStreamedIsStarted() {
|
||||
if (!_streamed) {
|
||||
return;
|
||||
}
|
||||
if (_streamed->paused()) {
|
||||
_streamed->resume();
|
||||
}
|
||||
if (!_streamed->active() && !_streamed->failed()) {
|
||||
startStreamedPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
void EditCaptionBox::startStreamedPlayer() {
|
||||
auto options = ::Media::Streaming::PlaybackOptions();
|
||||
options.audioId = _documentMedia
|
||||
? AudioMsgId(_documentMedia->owner(), _msgId)
|
||||
: AudioMsgId();
|
||||
options.waitForMarkAsShown = true;
|
||||
//if (!_streamed->withSound) {
|
||||
options.mode = ::Media::Streaming::Mode::Video;
|
||||
options.loop = true;
|
||||
//}
|
||||
_streamed->play(options);
|
||||
}
|
||||
|
||||
void EditCaptionBox::paintEvent(QPaintEvent *e) {
|
||||
BoxContent::paintEvent(e);
|
||||
|
||||
@@ -707,16 +755,27 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
|
||||
if (_thumbx + _thumbw < width() - st::boxPhotoPadding.right()) {
|
||||
p.fillRect(_thumbx + _thumbw, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _thumbx - _thumbw, th, st::confirmBg);
|
||||
}
|
||||
if (_gifPreview && _gifPreview->started()) {
|
||||
checkStreamedIsStarted();
|
||||
if (_streamed
|
||||
&& _streamed->player().ready()
|
||||
&& !_streamed->player().videoSize().isEmpty()) {
|
||||
const auto s = QSize(_gifw, _gifh);
|
||||
const auto paused = _controller->isGifPausedAtLeastFor(Window::GifPauseReason::Layer);
|
||||
const auto frame = _gifPreview->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None, paused ? 0 : crl::now());
|
||||
p.drawPixmap(_gifx, st::boxPhotoPadding.top(), frame);
|
||||
|
||||
auto request = ::Media::Streaming::FrameRequest();
|
||||
request.outer = s * cIntRetinaFactor();
|
||||
request.resize = s * cIntRetinaFactor();
|
||||
p.drawImage(
|
||||
QRect(_gifx, st::boxPhotoPadding.top(), _gifw, _gifh),
|
||||
_streamed->frame(request));
|
||||
if (!paused) {
|
||||
_streamed->markFrameShown();
|
||||
}
|
||||
} else {
|
||||
const auto offset = _gifh ? ((_gifh - _thumbh) / 2) : 0;
|
||||
p.drawPixmap(_thumbx, st::boxPhotoPadding.top() + offset, _thumb);
|
||||
}
|
||||
if (_animated && !_gifPreview) {
|
||||
if (_animated && !_streamed) {
|
||||
QRect inner(_thumbx + (_thumbw - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (th - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(st::msgDateImgBg);
|
||||
|
Reference in New Issue
Block a user