mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Play video userpics in photo change messages.
This commit is contained in:
parent
e363b254f6
commit
f99960e1f6
7 changed files with 212 additions and 46 deletions
|
@ -102,6 +102,30 @@ template <typename Data>
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Data>
|
||||||
|
void Streaming::keepAlive(
|
||||||
|
base::flat_map<not_null<Data*>, std::weak_ptr<Document>> &documents,
|
||||||
|
not_null<Data*> data) {
|
||||||
|
const auto i = documents.find(data);
|
||||||
|
if (i == end(documents)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto shared = i->second.lock();
|
||||||
|
if (!shared) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto till = crl::now() + kKeepAliveTimeout;
|
||||||
|
const auto j = _keptAlive.find(shared);
|
||||||
|
if (j != end(_keptAlive)) {
|
||||||
|
j->second = till;
|
||||||
|
} else {
|
||||||
|
_keptAlive.emplace(std::move(shared), till);
|
||||||
|
}
|
||||||
|
if (!_keptAliveTimer.isActive()) {
|
||||||
|
_keptAliveTimer.callOnce(kKeepAliveTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Streaming::Reader> Streaming::sharedReader(
|
std::shared_ptr<Streaming::Reader> Streaming::sharedReader(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
FileOrigin origin,
|
FileOrigin origin,
|
||||||
|
@ -129,24 +153,11 @@ std::shared_ptr<Streaming::Document> Streaming::sharedDocument(
|
||||||
}
|
}
|
||||||
|
|
||||||
void Streaming::keepAlive(not_null<DocumentData*> document) {
|
void Streaming::keepAlive(not_null<DocumentData*> document) {
|
||||||
const auto i = _fileDocuments.find(document);
|
keepAlive(_fileDocuments, document);
|
||||||
if (i == end(_fileDocuments)) {
|
}
|
||||||
return;
|
|
||||||
}
|
void Streaming::keepAlive(not_null<PhotoData*> photo) {
|
||||||
auto shared = i->second.lock();
|
keepAlive(_photoDocuments, photo);
|
||||||
if (!shared) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto till = crl::now() + kKeepAliveTimeout;
|
|
||||||
const auto j = _keptAlive.find(shared);
|
|
||||||
if (j != end(_keptAlive)) {
|
|
||||||
j->second = till;
|
|
||||||
} else {
|
|
||||||
_keptAlive.emplace(std::move(shared), till);
|
|
||||||
}
|
|
||||||
if (!_keptAliveTimer.isActive()) {
|
|
||||||
_keptAliveTimer.callOnce(kKeepAliveTimeout);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Streaming::clearKeptAlive() {
|
void Streaming::clearKeptAlive() {
|
||||||
|
|
|
@ -51,6 +51,7 @@ public:
|
||||||
FileOrigin origin);
|
FileOrigin origin);
|
||||||
|
|
||||||
void keepAlive(not_null<DocumentData*> document);
|
void keepAlive(not_null<DocumentData*> document);
|
||||||
|
void keepAlive(not_null<PhotoData*> photo);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void clearKeptAlive();
|
void clearKeptAlive();
|
||||||
|
@ -69,6 +70,11 @@ private:
|
||||||
not_null<Data*> data,
|
not_null<Data*> data,
|
||||||
FileOrigin origin);
|
FileOrigin origin);
|
||||||
|
|
||||||
|
template <typename Data>
|
||||||
|
void keepAlive(
|
||||||
|
base::flat_map<not_null<Data*>, std::weak_ptr<Document>> &documents,
|
||||||
|
not_null<Data*> data);
|
||||||
|
|
||||||
const not_null<Session*> _owner;
|
const not_null<Session*> _owner;
|
||||||
|
|
||||||
base::flat_map<
|
base::flat_map<
|
||||||
|
|
|
@ -99,8 +99,8 @@ Gif::~Gif() {
|
||||||
}
|
}
|
||||||
if (_dataMedia) {
|
if (_dataMedia) {
|
||||||
_data->owner().keepAlive(base::take(_dataMedia));
|
_data->owner().keepAlive(base::take(_dataMedia));
|
||||||
|
_parent->checkHeavyPart();
|
||||||
}
|
}
|
||||||
_parent->checkHeavyPart();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1464,8 +1464,8 @@ void Gif::repaintStreamedContent() {
|
||||||
const auto own = activeOwnStreamed();
|
const auto own = activeOwnStreamed();
|
||||||
if (own && !own->frozenFrame.isNull()) {
|
if (own && !own->frozenFrame.isNull()) {
|
||||||
return;
|
return;
|
||||||
}
|
} else if (_parent->delegate()->elementIsGifPaused()
|
||||||
if (_parent->delegate()->elementIsGifPaused() && !activeRoundStreamed()) {
|
&& !activeRoundStreamed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
history()->owner().requestViewRepaint(_parent);
|
history()->owner().requestViewRepaint(_parent);
|
||||||
|
|
|
@ -14,10 +14,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/view/history_view_element.h"
|
#include "history/view/history_view_element.h"
|
||||||
#include "history/view/history_view_cursor_state.h"
|
#include "history/view/history_view_cursor_state.h"
|
||||||
#include "history/view/media/history_view_media_common.h"
|
#include "history/view/media/history_view_media_common.h"
|
||||||
|
#include "media/streaming/media_streaming_instance.h"
|
||||||
|
#include "media/streaming/media_streaming_player.h"
|
||||||
|
#include "media/streaming/media_streaming_document.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "ui/grouped_layout.h"
|
#include "ui/grouped_layout.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_streaming.h"
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
#include "data/data_photo_media.h"
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
@ -54,9 +58,15 @@ Photo::Photo(
|
||||||
}
|
}
|
||||||
|
|
||||||
Photo::~Photo() {
|
Photo::~Photo() {
|
||||||
if (_dataMedia) {
|
if (_streamed || _dataMedia) {
|
||||||
_data->owner().keepAlive(base::take(_dataMedia));
|
if (_streamed) {
|
||||||
_parent->checkHeavyPart();
|
_data->owner().streaming().keepAlive(_data);
|
||||||
|
setStreamed(nullptr);
|
||||||
|
}
|
||||||
|
if (_dataMedia) {
|
||||||
|
_data->owner().keepAlive(base::take(_dataMedia));
|
||||||
|
_parent->checkHeavyPart();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,10 +103,11 @@ void Photo::dataMediaCreated() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Photo::hasHeavyPart() const {
|
bool Photo::hasHeavyPart() const {
|
||||||
return (_dataMedia != nullptr);
|
return _streamed || _dataMedia;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Photo::unloadHeavyPart() {
|
void Photo::unloadHeavyPart() {
|
||||||
|
setStreamed(nullptr);
|
||||||
_dataMedia = nullptr;
|
_dataMedia = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,22 +220,7 @@ void Photo::draw(Painter &p, const QRect &r, TextSelection selection, crl::time
|
||||||
|
|
||||||
auto rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
|
auto rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
|
||||||
if (_serviceWidth > 0) {
|
if (_serviceWidth > 0) {
|
||||||
const auto pix = [&] {
|
paintUserpicFrame(p, rthumb.topLeft());
|
||||||
if (const auto large = _dataMedia->image(PhotoSize::Large)) {
|
|
||||||
return large->pixCircled(_pixw, _pixh);
|
|
||||||
} else if (const auto thumbnail = _dataMedia->image(
|
|
||||||
PhotoSize::Thumbnail)) {
|
|
||||||
return thumbnail->pixBlurredCircled(_pixw, _pixh);
|
|
||||||
} else if (const auto small = _dataMedia->image(
|
|
||||||
PhotoSize::Small)) {
|
|
||||||
return small->pixBlurredCircled(_pixw, _pixh);
|
|
||||||
} else if (const auto blurred = _dataMedia->thumbnailInline()) {
|
|
||||||
return blurred->pixBlurredCircled(_pixw, _pixh);
|
|
||||||
} else {
|
|
||||||
return QPixmap();
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
p.drawPixmap(rthumb.topLeft(), pix);
|
|
||||||
} else {
|
} else {
|
||||||
if (bubble) {
|
if (bubble) {
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
|
@ -320,6 +316,42 @@ void Photo::draw(Painter &p, const QRect &r, TextSelection selection, crl::time
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Photo::paintUserpicFrame(Painter &p, QPoint photoPosition) const {
|
||||||
|
const_cast<Photo*>(this)->validateVideo();
|
||||||
|
|
||||||
|
if (_streamed
|
||||||
|
&& _streamed->player().ready()
|
||||||
|
&& !_streamed->player().videoSize().isEmpty()) {
|
||||||
|
const auto paused = _parent->delegate()->elementIsGifPaused();
|
||||||
|
auto request = ::Media::Streaming::FrameRequest();
|
||||||
|
auto size = QSize{ _pixw, _pixh };
|
||||||
|
request.outer = size * cIntRetinaFactor();
|
||||||
|
request.resize = size * cIntRetinaFactor();
|
||||||
|
request.radius = ImageRoundRadius::Ellipse;
|
||||||
|
p.drawImage(QRect(photoPosition, size), _streamed->frame(request));
|
||||||
|
if (!paused) {
|
||||||
|
_streamed->markFrameShown();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto pix = [&] {
|
||||||
|
if (const auto large = _dataMedia->image(PhotoSize::Large)) {
|
||||||
|
return large->pixCircled(_pixw, _pixh);
|
||||||
|
} else if (const auto thumbnail = _dataMedia->image(
|
||||||
|
PhotoSize::Thumbnail)) {
|
||||||
|
return thumbnail->pixBlurredCircled(_pixw, _pixh);
|
||||||
|
} else if (const auto small = _dataMedia->image(
|
||||||
|
PhotoSize::Small)) {
|
||||||
|
return small->pixBlurredCircled(_pixw, _pixh);
|
||||||
|
} else if (const auto blurred = _dataMedia->thumbnailInline()) {
|
||||||
|
return blurred->pixBlurredCircled(_pixw, _pixh);
|
||||||
|
} else {
|
||||||
|
return QPixmap();
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
p.drawPixmap(photoPosition, pix);
|
||||||
|
}
|
||||||
|
|
||||||
TextState Photo::textState(QPoint point, StateRequest request) const {
|
TextState Photo::textState(QPoint point, StateRequest request) const {
|
||||||
auto result = TextState(_parent);
|
auto result = TextState(_parent);
|
||||||
|
|
||||||
|
@ -580,6 +612,106 @@ void Photo::validateGroupedCache(
|
||||||
*cache = image->pixNoCache(pixWidth, pixHeight, options, width, height);
|
*cache = image->pixNoCache(pixWidth, pixHeight, options, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Photo::createStreamingObjects() {
|
||||||
|
using namespace ::Media::Streaming;
|
||||||
|
|
||||||
|
setStreamed(std::make_unique<Instance>(
|
||||||
|
history()->owner().streaming().sharedDocument(
|
||||||
|
_data,
|
||||||
|
_realParent->fullId()),
|
||||||
|
nullptr));
|
||||||
|
_streamed->player().updates(
|
||||||
|
) | rpl::start_with_next_error([=](Update &&update) {
|
||||||
|
handleStreamingUpdate(std::move(update));
|
||||||
|
}, [=](Error &&error) {
|
||||||
|
handleStreamingError(std::move(error));
|
||||||
|
}, _streamed->lifetime());
|
||||||
|
if (_streamed->ready()) {
|
||||||
|
streamingReady(base::duplicate(_streamed->info()));
|
||||||
|
}
|
||||||
|
if (!_streamed->valid()) {
|
||||||
|
setStreamed(nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Photo::setStreamed(std::unique_ptr<::Media::Streaming::Instance> value) {
|
||||||
|
const auto removed = (_streamed && !value);
|
||||||
|
const auto set = (!_streamed && value);
|
||||||
|
_streamed = std::move(value);
|
||||||
|
if (set) {
|
||||||
|
history()->owner().registerHeavyViewPart(_parent);
|
||||||
|
} else if (removed) {
|
||||||
|
_parent->checkHeavyPart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Photo::handleStreamingUpdate(::Media::Streaming::Update &&update) {
|
||||||
|
using namespace ::Media::Streaming;
|
||||||
|
|
||||||
|
update.data.match([&](Information &update) {
|
||||||
|
streamingReady(std::move(update));
|
||||||
|
}, [&](const PreloadedVideo &update) {
|
||||||
|
}, [&](const UpdateVideo &update) {
|
||||||
|
repaintStreamedContent();
|
||||||
|
}, [&](const PreloadedAudio &update) {
|
||||||
|
}, [&](const UpdateAudio &update) {
|
||||||
|
}, [&](const WaitingForData &update) {
|
||||||
|
}, [&](MutedByOther) {
|
||||||
|
}, [&](Finished) {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Photo::handleStreamingError(::Media::Streaming::Error &&error) {
|
||||||
|
_data->setVideoPlaybackFailed();
|
||||||
|
setStreamed(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Photo::repaintStreamedContent() {
|
||||||
|
/* const auto own = activeOwnStreamed();
|
||||||
|
if (own && !own->frozenFrame.isNull()) {
|
||||||
|
return;
|
||||||
|
} else */if (_parent->delegate()->elementIsGifPaused()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
history()->owner().requestViewRepaint(_parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Photo::streamingReady(::Media::Streaming::Information &&info) {
|
||||||
|
history()->owner().requestViewRepaint(_parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Photo::validateVideo() {
|
||||||
|
if (!_data->videoCanBePlayed()) {
|
||||||
|
setStreamed(nullptr);
|
||||||
|
return;
|
||||||
|
} else if (_streamed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!createStreamingObjects()) {
|
||||||
|
_data->setVideoPlaybackFailed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
checkStreamedIsStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Photo::checkStreamedIsStarted() {
|
||||||
|
if (!_streamed) {
|
||||||
|
return;
|
||||||
|
} else if (_streamed->paused()) {
|
||||||
|
_streamed->resume();
|
||||||
|
}
|
||||||
|
if (_streamed && !_streamed->active() && !_streamed->failed()) {
|
||||||
|
const auto position = _data->videoStartPosition();
|
||||||
|
auto options = ::Media::Streaming::PlaybackOptions();
|
||||||
|
options.position = position;
|
||||||
|
options.mode = ::Media::Streaming::Mode::Video;
|
||||||
|
options.loop = true;
|
||||||
|
_streamed->play(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TextForMimeData Photo::selectedText(TextSelection selection) const {
|
TextForMimeData Photo::selectedText(TextSelection selection) const {
|
||||||
return _caption.toTextForMimeData(selection);
|
return _caption.toTextForMimeData(selection);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,15 @@ namespace Data {
|
||||||
class PhotoMedia;
|
class PhotoMedia;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
|
namespace Media {
|
||||||
|
namespace Streaming {
|
||||||
|
class Instance;
|
||||||
|
struct Update;
|
||||||
|
enum class Error;
|
||||||
|
struct Information;
|
||||||
|
} // namespace Streaming
|
||||||
|
} // namespace Media
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
|
||||||
class Photo : public File {
|
class Photo : public File {
|
||||||
|
@ -104,12 +113,23 @@ private:
|
||||||
not_null<uint64*> cacheKey,
|
not_null<uint64*> cacheKey,
|
||||||
not_null<QPixmap*> cache) const;
|
not_null<QPixmap*> cache) const;
|
||||||
|
|
||||||
|
void validateVideo();
|
||||||
|
void setStreamed(std::unique_ptr<::Media::Streaming::Instance> value);
|
||||||
|
void repaintStreamedContent();
|
||||||
|
void checkStreamedIsStarted();
|
||||||
|
bool createStreamingObjects();
|
||||||
|
void handleStreamingUpdate(::Media::Streaming::Update &&update);
|
||||||
|
void handleStreamingError(::Media::Streaming::Error &&error);
|
||||||
|
void streamingReady(::Media::Streaming::Information &&info);
|
||||||
|
void paintUserpicFrame(Painter &p, QPoint photoPosition) const;
|
||||||
|
|
||||||
not_null<PhotoData*> _data;
|
not_null<PhotoData*> _data;
|
||||||
int _serviceWidth = 0;
|
int _serviceWidth = 0;
|
||||||
int _pixw = 1;
|
int _pixw = 1;
|
||||||
int _pixh = 1;
|
int _pixh = 1;
|
||||||
Ui::Text::String _caption;
|
Ui::Text::String _caption;
|
||||||
mutable std::shared_ptr<Data::PhotoMedia> _dataMedia;
|
mutable std::shared_ptr<Data::PhotoMedia> _dataMedia;
|
||||||
|
mutable std::unique_ptr<::Media::Streaming::Instance> _streamed;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -839,7 +839,7 @@ bool UserpicButton::createStreamingObjects(not_null<PhotoData*> photo) {
|
||||||
: Data::FileOrigin(Data::FileOriginPeerPhoto(_peer->id));
|
: Data::FileOrigin(Data::FileOriginPeerPhoto(_peer->id));
|
||||||
_streamed = std::make_unique<Instance>(
|
_streamed = std::make_unique<Instance>(
|
||||||
photo->owner().streaming().sharedDocument(photo, origin),
|
photo->owner().streaming().sharedDocument(photo, origin),
|
||||||
[=] { update(); });
|
nullptr);
|
||||||
_streamed->player().updates(
|
_streamed->player().updates(
|
||||||
) | rpl::start_with_next_error([=](Update &&update) {
|
) | rpl::start_with_next_error([=](Update &&update) {
|
||||||
handleStreamingUpdate(std::move(update));
|
handleStreamingUpdate(std::move(update));
|
||||||
|
@ -892,8 +892,6 @@ void UserpicButton::streamingReady(Media::Streaming::Information &&info) {
|
||||||
void UserpicButton::updateVideo() {
|
void UserpicButton::updateVideo() {
|
||||||
Expects(_role == Role::OpenPhoto);
|
Expects(_role == Role::OpenPhoto);
|
||||||
|
|
||||||
using namespace Media::Streaming;
|
|
||||||
|
|
||||||
const auto id = _peer->userpicPhotoId();
|
const auto id = _peer->userpicPhotoId();
|
||||||
if (!id) {
|
if (!id) {
|
||||||
clearStreaming();
|
clearStreaming();
|
||||||
|
|
|
@ -26,7 +26,6 @@ class SessionController;
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Streaming {
|
namespace Streaming {
|
||||||
class Instance;
|
class Instance;
|
||||||
class Document;
|
|
||||||
struct Update;
|
struct Update;
|
||||||
enum class Error;
|
enum class Error;
|
||||||
struct Information;
|
struct Information;
|
||||||
|
@ -222,13 +221,13 @@ private:
|
||||||
void setCursorInChangeOverlay(bool inOverlay);
|
void setCursorInChangeOverlay(bool inOverlay);
|
||||||
void updateCursor();
|
void updateCursor();
|
||||||
void updateVideo();
|
void updateVideo();
|
||||||
|
bool showSavedMessages() const;
|
||||||
void checkStreamedIsStarted();
|
void checkStreamedIsStarted();
|
||||||
bool createStreamingObjects(not_null<PhotoData*> photo);
|
bool createStreamingObjects(not_null<PhotoData*> photo);
|
||||||
void clearStreaming();
|
void clearStreaming();
|
||||||
void handleStreamingUpdate(Media::Streaming::Update &&update);
|
void handleStreamingUpdate(Media::Streaming::Update &&update);
|
||||||
void handleStreamingError(Media::Streaming::Error &&error);
|
void handleStreamingError(Media::Streaming::Error &&error);
|
||||||
void streamingReady(Media::Streaming::Information &&info);
|
void streamingReady(Media::Streaming::Information &&info);
|
||||||
bool showSavedMessages() const;
|
|
||||||
void paintUserpicFrame(Painter &p, QPoint photoPosition);
|
void paintUserpicFrame(Painter &p, QPoint photoPosition);
|
||||||
|
|
||||||
void grabOldUserpic();
|
void grabOldUserpic();
|
||||||
|
|
Loading…
Add table
Reference in a new issue