2
0
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:
John Preston
2020-05-20 15:04:56 +04:00
parent 3d431a27cb
commit 581a21dbd9
15 changed files with 220 additions and 149 deletions

View File

@@ -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);