Support round video inline playback with sound.

This commit is contained in:
John Preston 2017-04-02 19:42:18 +03:00
parent cbf040b4dc
commit 5480a63beb
12 changed files with 122 additions and 50 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

View File

@ -418,3 +418,7 @@ msgWaveformBar: 2px;
msgWaveformSkip: 1px; msgWaveformSkip: 1px;
msgWaveformMin: 2px; msgWaveformMin: 2px;
msgWaveformMax: 20px; msgWaveformMax: 20px;
historyVideoMessageMute: icon {{ "volume_mute", historyFileThumbIconFg }};
historyVideoMessageMuteSelected: icon {{ "volume_mute", historyFileThumbIconFgSelected }};
historyVideoMessageMuteSize: 25px;

View File

@ -892,17 +892,20 @@ void HistoryItem::clipCallback(Media::Clip::Notification notification) {
switch (notification) { switch (notification) {
case NotificationReinit: { case NotificationReinit: {
bool stopped = false; auto stopped = false;
if (reader->autoPausedGif()) { if (reader->autoPausedGif()) {
if (MainWidget *m = App::main()) { if (auto m = App::main()) {
if (!m->isItemVisible(this)) { // stop animation if it is not visible if (!m->isItemVisible(this)) { // stop animation if it is not visible
media->stopInline(); media->stopInline();
if (DocumentData *document = media->getDocument()) { // forget data from memory if (auto document = media->getDocument()) { // forget data from memory
document->forget(); document->forget();
} }
stopped = true; stopped = true;
} }
} }
} else if (reader->mode() == Media::Clip::Reader::Mode::Video && reader->state() == Media::Clip::State::Finished) {
// Stop finished video message.
media->stopInline();
} }
if (!stopped) { if (!stopped) {
setPendingInitDimensions(); setPendingInitDimensions();

View File

@ -1653,7 +1653,7 @@ HistoryGif::HistoryGif(HistoryItem *parent, DocumentData *document, const QStrin
setStatusSize(FileStatusSizeReady); setStatusSize(FileStatusSizeReady);
if (!caption.isEmpty()) { if (!caption.isEmpty() && !_data->isRoundVideo()) {
_caption.setText(st::messageTextStyle, caption + _parent->skipBlock(), itemTextNoMonoOptions(_parent)); _caption.setText(st::messageTextStyle, caption + _parent->skipBlock(), itemTextNoMonoOptions(_parent));
} }
@ -1681,8 +1681,7 @@ void HistoryGif::initDimensions() {
if (!_gif->autoplay()) { if (!_gif->autoplay()) {
Ui::show(Box<InformBox>(lang(lng_gif_error))); Ui::show(Box<InformBox>(lang(lng_gif_error)));
} }
App::unregGifItem(_gif.get()); setClipReader(Media::Clip::ReaderPointer::Bad());
_gif.setBad();
} }
if (_gif && _gif->ready()) { if (_gif && _gif->ready()) {
@ -1797,10 +1796,12 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM
if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return;
_data->automaticLoad(_parent); _data->automaticLoad(_parent);
bool loaded = _data->loaded(), displayLoading = (_parent->id < 0) || _data->displayLoading(); auto loaded = _data->loaded();
bool selected = (selection == FullSelection); auto displayLoading = (_parent->id < 0) || _data->displayLoading();
auto selected = (selection == FullSelection);
if (loaded && !_gif && !_gif.isBad() && cAutoPlayGif()) { auto videoFinished = _gif && (_gif->mode() == Media::Clip::Reader::Mode::Video) && (_gif->state() == Media::Clip::State::Finished);
if (loaded && cAutoPlayGif() && ((!_gif && !_gif.isBad()) || videoFinished)) {
Ui::autoplayMediaInlineAsync(_parent->fullId()); Ui::autoplayMediaInlineAsync(_parent->fullId());
} }
@ -1811,6 +1812,7 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM
auto captionw = width - st::msgPadding.left() - st::msgPadding.right(); auto captionw = width - st::msgPadding.left() - st::msgPadding.right();
auto isRound = _data->isRoundVideo(); auto isRound = _data->isRoundVideo();
auto displayMute = false;
auto animating = (_gif && _gif->started()); auto animating = (_gif && _gif->started());
if (!animating || _parent->id < 0) { if (!animating || _parent->id < 0) {
@ -1848,6 +1850,13 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM
| ((isBubbleBottom() && _caption.isEmpty()) ? (ImageRoundCorner::BottomLeft | ImageRoundCorner::BottomRight) : ImageRoundCorner::None)); | ((isBubbleBottom() && _caption.isEmpty()) ? (ImageRoundCorner::BottomLeft | ImageRoundCorner::BottomRight) : ImageRoundCorner::None));
if (animating) { if (animating) {
auto paused = App::wnd()->controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Any); auto paused = App::wnd()->controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Any);
if (isRound) {
if (_gif->mode() == Media::Clip::Reader::Mode::Video) {
paused = false;
} else {
displayMute = true;
}
}
p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, roundRadius, roundCorners, paused ? 0 : ms)); p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, roundRadius, roundCorners, paused ? 0 : ms));
} else { } else {
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(_thumbw, _thumbh, width, height, roundRadius, roundCorners)); p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(_thumbw, _thumbh, width, height, roundRadius, roundCorners));
@ -1857,8 +1866,8 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM
} }
if (radial || _gif.isBad() || (!_gif && ((!loaded && !_data->loading()) || !cAutoPlayGif()))) { if (radial || _gif.isBad() || (!_gif && ((!loaded && !_data->loading()) || !cAutoPlayGif()))) {
float64 radialOpacity = (radial && loaded && _parent->id > 0) ? _animation->radial.opacity() : 1; auto radialOpacity = (radial && loaded && _parent->id > 0) ? _animation->radial.opacity() : 1.;
QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); auto inner = QRect(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
if (selected) { if (selected) {
p.setBrush(st::msgDateImgBgSelected); p.setBrush(st::msgDateImgBgSelected);
@ -1908,13 +1917,21 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM
p.drawTextLeft(statusX, statusY, _width, _statusText, statusW - 2 * st::msgDateImgPadding.x()); p.drawTextLeft(statusX, statusY, _width, _statusText, statusW - 2 * st::msgDateImgPadding.x());
} }
} }
if (displayMute) {
auto muteRect = rtlrect(rthumb.x() + (rthumb.width() - st::historyVideoMessageMuteSize) / 2, rthumb.y() + rthumb.height() - st::msgDateImgDelta - st::historyVideoMessageMuteSize, st::historyVideoMessageMuteSize, st::historyVideoMessageMuteSize, _width);
p.setPen(Qt::NoPen);
p.setBrush(selected ? st::msgDateImgBgSelected : st::msgDateImgBg);
PainterHighQualityEnabler hq(p);
p.drawEllipse(muteRect);
(selected ? st::historyVideoMessageMuteSelected : st::historyVideoMessageMute).paintInCenter(p, muteRect);
}
if (isRound) { if (isRound) {
auto mediaUnread = _parent->isMediaUnread(); auto mediaUnread = _parent->isMediaUnread();
auto statusW = st::normalFont->width(_statusText) + 2 * st::msgDateImgPadding.x(); auto statusW = st::normalFont->width(_statusText) + 2 * st::msgDateImgPadding.x();
auto statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y(); auto statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y();
auto statusX = skipx + st::msgDateImgDelta + st::msgDateImgPadding.x(); auto statusX = skipx + st::msgDateImgDelta + st::msgDateImgPadding.x();
auto statusY = skipy + height - st::msgDateImgDelta - statusH; auto statusY = skipy + height - st::msgDateImgDelta - statusH + st::msgDateImgPadding.y();
if (_parent->isMediaUnread()) { if (_parent->isMediaUnread()) {
statusW += st::mediaUnreadSkip + st::mediaUnreadSize; statusW += st::mediaUnreadSkip + st::mediaUnreadSize;
} }
@ -1970,7 +1987,7 @@ HistoryTextState HistoryGif::getState(int x, int y, HistoryStateRequest request)
if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) { if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) {
if (_data->uploading()) { if (_data->uploading()) {
result.link = _cancell; result.link = _cancell;
} else if (!_gif || !cAutoPlayGif()) { } else if (!_gif || !cAutoPlayGif() || _data->isRoundVideo()) {
result.link = _data->loaded() ? _openl : (_data->loading() ? _cancell : _savel); result.link = _data->loaded() ? _openl : (_data->loading() ? _cancell : _savel);
} }
if (_parent->getMedia() == this) { if (_parent->getMedia() == this) {
@ -2047,35 +2064,56 @@ ImagePtr HistoryGif::replyPreview() {
} }
bool HistoryGif::playInline(bool autoplay) { bool HistoryGif::playInline(bool autoplay) {
using Mode = Media::Clip::Reader::Mode;
if (_data->isRoundVideo() && _gif) {
// Stop autoplayed silent video when we start playback by click.
// Stop finished video message when autoplay starts.
if ((!autoplay && _gif->mode() == Mode::Gif)
|| (autoplay && _gif->mode() == Mode::Video && _gif->state() == Media::Clip::State::Finished)) {
stopInline();
}
}
if (_gif) { if (_gif) {
stopInline(); stopInline();
} else if (_data->loaded(DocumentData::FilePathResolveChecked)) { } else if (_data->loaded(DocumentData::FilePathResolveChecked)) {
if (!cAutoPlayGif()) { if (!cAutoPlayGif()) {
App::stopGifItems(); App::stopGifItems();
} }
_gif = Media::Clip::MakeReader(_data->location(), _data->data(), [this](Media::Clip::Notification notification) { auto mode = (!autoplay && _data->isRoundVideo()) ? Mode::Video : Mode::Gif;
setClipReader(Media::Clip::MakeReader(_data->location(), _data->data(), [this](Media::Clip::Notification notification) {
_parent->clipCallback(notification); _parent->clipCallback(notification);
}); }, mode));
App::regGifItem(_gif.get(), _parent); if (mode == Mode::Video) {
if (_gif) _gif->setAutoplay(); if (App::main()) {
App::main()->mediaMarkRead(_data);
}
}
if (_gif && autoplay) {
_gif->setAutoplay();
}
} }
return true; return true;
} }
void HistoryGif::stopInline() { void HistoryGif::stopInline() {
if (_gif) { clearClipReader();
App::unregGifItem(_gif.get());
}
_gif.reset();
_parent->setPendingInitDimensions(); _parent->setPendingInitDimensions();
Notify::historyItemLayoutChanged(_parent); Notify::historyItemLayoutChanged(_parent);
} }
HistoryGif::~HistoryGif() { void HistoryGif::setClipReader(Media::Clip::ReaderPointer gif) {
if (_gif) { if (_gif) {
App::unregGifItem(_gif.get()); App::unregGifItem(_gif.get());
} }
_gif = std::move(gif);
if (_gif) {
App::regGifItem(_gif.get(), _parent);
}
}
HistoryGif::~HistoryGif() {
clearClipReader();
} }
float64 HistoryGif::dataProgress() const { float64 HistoryGif::dataProgress() const {
@ -2099,10 +2137,6 @@ HistorySticker::HistorySticker(HistoryItem *parent, DocumentData *document) : Hi
} }
} }
class TestClickHandler : public ClickHandler {
};
void HistorySticker::initDimensions() { void HistorySticker::initDimensions() {
auto sticker = _data->sticker(); auto sticker = _data->sticker();

View File

@ -515,6 +515,9 @@ public:
return _caption.originalTextWithEntities(); return _caption.originalTextWithEntities();
} }
bool needsBubble() const override { bool needsBubble() const override {
if (_data->isRoundVideo()) {
return false;
}
if (!_caption.isEmpty()) { if (!_caption.isEmpty()) {
return true; return true;
} }
@ -546,6 +549,11 @@ protected:
bool dataFinished() const override; bool dataFinished() const override;
bool dataLoaded() const override; bool dataLoaded() const override;
void setClipReader(Media::Clip::ReaderPointer gif);
void clearClipReader() {
setClipReader(Media::Clip::ReaderPointer());
}
private: private:
gsl::not_null<DocumentData*> _data; gsl::not_null<DocumentData*> _data;
int32 _thumbw = 1; int32 _thumbw = 1;

View File

@ -54,7 +54,10 @@ MediaOverviewType messageMediaToOverviewType(HistoryMedia *media) {
case MediaTypeFile: return OverviewFiles; case MediaTypeFile: return OverviewFiles;
case MediaTypeMusicFile: return media->getDocument()->isMusic() ? OverviewMusicFiles : OverviewCount; case MediaTypeMusicFile: return media->getDocument()->isMusic() ? OverviewMusicFiles : OverviewCount;
case MediaTypeVoiceFile: return OverviewVoiceFiles; case MediaTypeVoiceFile: return OverviewVoiceFiles;
case MediaTypeGif: return media->getDocument()->isGifv() ? OverviewCount : OverviewFiles; case MediaTypeGif: {
auto document = media->getDocument();
return (document->isGifv() || document->isRoundVideo()) ? OverviewCount : OverviewFiles;
} break;
default: break; default: break;
} }
return OverviewCount; return OverviewCount;

View File

@ -338,8 +338,8 @@ void Gif::clipCallback(Media::Clip::Notification notification) {
_gif.setBad(); _gif.setBad();
getShownDocument()->forget(); getShownDocument()->forget();
} else if (_gif->ready() && !_gif->started()) { } else if (_gif->ready() && !_gif->started()) {
int32 height = st::inlineMediaHeight; auto height = st::inlineMediaHeight;
QSize frame = countFrameSize(); auto frame = countFrameSize();
_gif->start(frame.width(), frame.height(), _width, height, ImageRoundRadius::None, ImageRoundCorner::None); _gif->start(frame.width(), frame.height(), _width, height, ImageRoundRadius::None, ImageRoundCorner::None);
} else if (_gif->autoPausedGif() && !context()->inlineItemVisible(this)) { } else if (_gif->autoPausedGif() && !context()->inlineItemVisible(this)) {
_gif.reset(); _gif.reset();

View File

@ -222,11 +222,12 @@ bool MediaView::fileBubbleShown() const {
bool MediaView::gifShown() const { bool MediaView::gifShown() const {
if (_gif && _gif->ready()) { if (_gif && _gif->ready()) {
if (!_gif->started()) { if (!_gif->started()) {
if (_doc->isVideo() && _autoplayVideoDocument != _doc && !_gif->videoPaused()) { if ((_doc->isVideo() || _doc->isRoundVideo()) && _autoplayVideoDocument != _doc && !_gif->videoPaused()) {
_gif->pauseResumeVideo(); _gif->pauseResumeVideo();
const_cast<MediaView*>(this)->_videoPaused = _gif->videoPaused(); const_cast<MediaView*>(this)->_videoPaused = _gif->videoPaused();
} }
_gif->start(_gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), _gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), ImageRoundRadius::None, ImageRoundCorner::None); auto rounding = _doc->isRoundVideo() ? ImageRoundRadius::Ellipse : ImageRoundRadius::None;
_gif->start(_gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), _gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), rounding, ImageRoundCorner::All);
const_cast<MediaView*>(this)->_current = QPixmap(); const_cast<MediaView*>(this)->_current = QPixmap();
} }
return true;// _gif->state() != Media::Clip::State::Error; return true;// _gif->state() != Media::Clip::State::Error;
@ -522,7 +523,7 @@ void MediaView::step_radial(TimeMs ms, bool timer) {
update(radialRect()); update(radialRect());
} }
if (_doc && _doc->loaded() && _doc->size < App::kImageSizeLimit && (!_radial.animating() || _doc->isAnimation() || _doc->isVideo())) { if (_doc && _doc->loaded() && _doc->size < App::kImageSizeLimit && (!_radial.animating() || _doc->isAnimation() || _doc->isVideo())) {
if (_doc->isVideo()) { if (_doc->isVideo() || _doc->isRoundVideo()) {
_autoplayVideoDocument = _doc; _autoplayVideoDocument = _doc;
} }
if (!_doc->data().isEmpty() && (_doc->isAnimation() || _doc->isVideo())) { if (!_doc->data().isEmpty() && (_doc->isAnimation() || _doc->isVideo())) {
@ -828,7 +829,7 @@ void MediaView::clipCallback(Media::Clip::Notification notification) {
_videoStopped = true; _videoStopped = true;
updateSilentVideoPlaybackState(); updateSilentVideoPlaybackState();
} else { } else {
_videoIsSilent = _doc->isVideo() && !_gif->hasAudio(); _videoIsSilent = (_doc->isVideo() || _doc->isRoundVideo()) && !_gif->hasAudio();
_videoDurationMs = _gif->getDurationMs(); _videoDurationMs = _gif->getDurationMs();
_videoPositionMs = _gif->getPositionMs(); _videoPositionMs = _gif->getPositionMs();
if (_videoIsSilent) { if (_videoIsSilent) {
@ -1140,7 +1141,7 @@ void MediaView::showDocument(DocumentData *doc, HistoryItem *context) {
_overview = doc->isVideo() ? OverviewVideos : OverviewFiles; _overview = doc->isVideo() ? OverviewVideos : OverviewFiles;
findCurrent(); findCurrent();
} }
if (doc->isVideo()) { if (doc->isVideo() || doc->isRoundVideo()) {
_autoplayVideoDocument = doc; _autoplayVideoDocument = doc;
} }
displayDocument(doc, context); displayDocument(doc, context);
@ -1383,6 +1384,14 @@ void MediaView::displayFinished() {
} }
} }
Images::Options MediaView::videoThumbOptions() const {
auto options = Images::Option::Smooth | Images::Option::Blurred;
if (_doc->isRoundVideo()) {
options |= Images::Option::Circled;
}
return options;
}
void MediaView::initAnimation() { void MediaView::initAnimation() {
Expects(_doc != nullptr); Expects(_doc != nullptr);
Expects(_doc->isAnimation() || _doc->isVideo()); Expects(_doc->isAnimation() || _doc->isVideo());
@ -1394,12 +1403,12 @@ void MediaView::initAnimation() {
createClipReader(); createClipReader();
location.accessDisable(); location.accessDisable();
} else if (_doc->dimensions.width() && _doc->dimensions.height()) { } else if (_doc->dimensions.width() && _doc->dimensions.height()) {
int w = _doc->dimensions.width(); auto w = _doc->dimensions.width();
int h = _doc->dimensions.height(); auto h = _doc->dimensions.height();
_current = _doc->thumb->pixNoCache(w, h, Images::Option::Smooth | Images::Option::Blurred, w / cIntRetinaFactor(), h / cIntRetinaFactor()); _current = _doc->thumb->pixNoCache(w, h, videoThumbOptions(), w / cIntRetinaFactor(), h / cIntRetinaFactor());
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
} else { } else {
_current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), Images::Option::Smooth | Images::Option::Blurred, st::mediaviewFileIconSize, st::mediaviewFileIconSize); _current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), videoThumbOptions(), st::mediaviewFileIconSize, st::mediaviewFileIconSize);
} }
} }
@ -1412,12 +1421,12 @@ void MediaView::createClipReader() {
if (_doc->dimensions.width() && _doc->dimensions.height()) { if (_doc->dimensions.width() && _doc->dimensions.height()) {
int w = _doc->dimensions.width(); int w = _doc->dimensions.width();
int h = _doc->dimensions.height(); int h = _doc->dimensions.height();
_current = _doc->thumb->pixNoCache(w, h, Images::Option::Smooth | Images::Option::Blurred, w / cIntRetinaFactor(), h / cIntRetinaFactor()); _current = _doc->thumb->pixNoCache(w, h, videoThumbOptions(), w / cIntRetinaFactor(), h / cIntRetinaFactor());
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
} else { } else {
_current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), Images::Option::Smooth | Images::Option::Blurred, st::mediaviewFileIconSize, st::mediaviewFileIconSize); _current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), videoThumbOptions(), st::mediaviewFileIconSize, st::mediaviewFileIconSize);
} }
auto mode = _doc->isVideo() ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif; auto mode = (_doc->isVideo() || _doc->isRoundVideo()) ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif;
_gif = std::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) { _gif = std::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) {
clipCallback(notification); clipCallback(notification);
}, mode); }, mode);
@ -1475,7 +1484,7 @@ void MediaView::initThemePreview() {
} }
void MediaView::createClipController() { void MediaView::createClipController() {
if (!_doc->isVideo()) return; if (!_doc->isVideo() && !_doc->isRoundVideo()) return;
_clipController.create(this); _clipController.create(this);
setClipControllerGeometry(); setClipControllerGeometry();
@ -1530,7 +1539,8 @@ void MediaView::restartVideoAtSeekPosition(TimeMs positionMs) {
_autoplayVideoDocument = _doc; _autoplayVideoDocument = _doc;
if (_current.isNull()) { if (_current.isNull()) {
_current = _gif->current(_gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), _gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), ImageRoundRadius::None, ImageRoundCorner::None, getms()); auto rounding = _doc->isRoundVideo() ? ImageRoundRadius::Ellipse : ImageRoundRadius::None;
_current = _gif->current(_gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), _gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), rounding, ImageRoundCorner::All, getms());
} }
_gif = std::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) { _gif = std::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) {
clipCallback(notification); clipCallback(notification);
@ -1638,6 +1648,9 @@ void MediaView::paintEvent(QPaintEvent *e) {
for (int i = 0, l = region.rectCount(); i < l; ++i) { for (int i = 0, l = region.rectCount(); i < l; ++i) {
p.fillRect(rs.at(i), st::mediaviewVideoBg); p.fillRect(rs.at(i), st::mediaviewVideoBg);
} }
if (_doc->isRoundVideo()) {
p.setCompositionMode(m);
}
} else { } else {
for (int i = 0, l = region.rectCount(); i < l; ++i) { for (int i = 0, l = region.rectCount(); i < l; ++i) {
p.fillRect(rs.at(i), st::mediaviewBg); p.fillRect(rs.at(i), st::mediaviewBg);
@ -1670,7 +1683,8 @@ void MediaView::paintEvent(QPaintEvent *e) {
if (_photo || fileShown()) { if (_photo || fileShown()) {
QRect imgRect(_x, _y, _w, _h); QRect imgRect(_x, _y, _w, _h);
if (imgRect.intersects(r)) { if (imgRect.intersects(r)) {
auto toDraw = _current.isNull() ? _gif->current(_gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), _gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), ImageRoundRadius::None, ImageRoundCorner::None, ms) : _current; auto rounding = _doc->isRoundVideo() ? ImageRoundRadius::Ellipse : ImageRoundRadius::None;
auto toDraw = _current.isNull() ? _gif->current(_gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), _gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), rounding, ImageRoundCorner::None, ms) : _current;
if (!_gif && (!_doc || !_doc->sticker() || _doc->sticker()->img->isNull()) && toDraw.hasAlpha()) { if (!_gif && (!_doc || !_doc->sticker() || _doc->sticker()->img->isNull()) && toDraw.hasAlpha()) {
p.fillRect(imgRect, _transparentBrush); p.fillRect(imgRect, _transparentBrush);
} }
@ -2011,7 +2025,7 @@ void MediaView::keyPressEvent(QKeyEvent *e) {
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return || e->key() == Qt::Key_Space) { } else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return || e->key() == Qt::Key_Space) {
if (_doc && !_doc->loading() && (fileBubbleShown() || !_doc->loaded())) { if (_doc && !_doc->loading() && (fileBubbleShown() || !_doc->loaded())) {
onDocClick(); onDocClick();
} else if (_doc && _doc->isVideo()) { } else if (_doc && (_doc->isVideo() || _doc->isRoundVideo())) {
onVideoPauseResume(); onVideoPauseResume();
} }
} else if (e->key() == Qt::Key_Left) { } else if (e->key() == Qt::Key_Left) {
@ -2463,7 +2477,7 @@ void MediaView::updateOver(QPoint pos) {
} else if (_closeNav.contains(pos)) { } else if (_closeNav.contains(pos)) {
updateOverState(OverClose); updateOverState(OverClose);
} else if (_doc && fileShown() && QRect(_x, _y, _w, _h).contains(pos)) { } else if (_doc && fileShown() && QRect(_x, _y, _w, _h).contains(pos)) {
if (_doc->isVideo() && _gif) { if ((_doc->isVideo() || _doc->isRoundVideo()) && _gif) {
updateOverState(OverVideo); updateOverState(OverVideo);
} else if (!_doc->loaded()) { } else if (!_doc->loaded()) {
updateOverState(OverIcon); updateOverState(OverIcon);

View File

@ -178,6 +178,7 @@ private:
void initAnimation(); void initAnimation();
void createClipReader(); void createClipReader();
Images::Options videoThumbOptions() const;
void initThemePreview(); void initThemePreview();
void destroyThemePreview(); void destroyThemePreview();

View File

@ -1205,14 +1205,14 @@ void DocumentOpenClickHandler::doOpen(DocumentData *data, HistoryItem *context,
} else if (data->size < App::kImageSizeLimit) { } else if (data->size < App::kImageSizeLimit) {
if (!data->data().isEmpty() && playAnimation) { if (!data->data().isEmpty() && playAnimation) {
if (action == ActionOnLoadPlayInline && context && context->getMedia()) { if (action == ActionOnLoadPlayInline && context && context->getMedia()) {
context->getMedia()->playInline(context); context->getMedia()->playInline();
} else { } else {
App::wnd()->showDocument(data, context); App::wnd()->showDocument(data, context);
} }
} else if (location.accessEnable()) { } else if (location.accessEnable()) {
if (data->isAnimation() || QImageReader(location.name()).canRead()) { if (data->isAnimation() || QImageReader(location.name()).canRead()) {
if (action == ActionOnLoadPlayInline && context && context->getMedia()) { if (action == ActionOnLoadPlayInline && context && context->getMedia()) {
context->getMedia()->playInline(context); context->getMedia()->playInline();
} else { } else {
App::wnd()->showDocument(data, context); App::wnd()->showDocument(data, context);
} }
@ -1485,7 +1485,7 @@ void DocumentData::performActionOnLoad() {
} else if (playAnimation) { } else if (playAnimation) {
if (loaded()) { if (loaded()) {
if (_actionOnLoad == ActionOnLoadPlayInline && item->getMedia()) { if (_actionOnLoad == ActionOnLoadPlayInline && item->getMedia()) {
item->getMedia()->playInline(item); item->getMedia()->playInline();
} else { } else {
App::wnd()->showDocument(this, item); App::wnd()->showDocument(this, item);
} }
@ -1504,7 +1504,7 @@ void DocumentData::performActionOnLoad() {
} else if (loc.accessEnable()) { } else if (loc.accessEnable()) {
if (showImage && QImageReader(loc.name()).canRead()) { if (showImage && QImageReader(loc.name()).canRead()) {
if (_actionOnLoad == ActionOnLoadPlayInline && item && item->getMedia()) { if (_actionOnLoad == ActionOnLoadPlayInline && item && item->getMedia()) {
item->getMedia()->playInline(item); item->getMedia()->playInline();
} else { } else {
App::wnd()->showDocument(this, item); App::wnd()->showDocument(this, item);
} }

View File

@ -68,6 +68,11 @@ public:
explicit operator bool() const { explicit operator bool() const {
return valid(); return valid();
} }
static inline ReaderPointer Bad() {
ReaderPointer result;
result.setBad();
return result;
}
~ReaderPointer(); ~ReaderPointer();
private: private: