From 207981b8c47fffd957beb64a75315ed3502f90d4 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 19 Jul 2016 13:54:43 +0300 Subject: [PATCH] Sync video to audio stream fixed. Cute video download inside MediaView. Small round radius in webpage photo / doc nested attachments. --- Telegram/SourceFiles/app.cpp | 1 + Telegram/SourceFiles/history.cpp | 10 +- .../inline_bot_layout_internal.cpp | 2 +- Telegram/SourceFiles/layerwidget.cpp | 2 +- Telegram/SourceFiles/media/media_audio.cpp | 12 +- .../SourceFiles/media/media_clip_reader.cpp | 11 +- .../SourceFiles/media/media_clip_reader.h | 4 +- Telegram/SourceFiles/mediaview.cpp | 136 ++++++++++-------- Telegram/SourceFiles/mediaview.h | 5 +- Telegram/SourceFiles/ui/images.h | 1 + 10 files changed, 107 insertions(+), 77 deletions(-) diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index f1f396e4e..7ee4b9b66 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -2605,6 +2605,7 @@ namespace { switch (radius) { case ImageRoundRadius::Small: prepareCorners(SmallMaskCorners, st::buttonRadius, bg, nullptr, images); break; case ImageRoundRadius::Large: prepareCorners(LargeMaskCorners, st::msgRadius, bg, nullptr, images); break; + default: p.fillRect(x, y, w, h, bg); return; } CornersPixmaps pixmaps; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 2813792d5..7f47a5220 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -3408,11 +3408,13 @@ void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, uin App::roundShadow(p, 0, 0, width, height, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); } + auto inWebPage = (_parent->getMedia() != this); + auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; QPixmap pix; if (loaded) { - pix = _data->full->pixSingle(ImageRoundRadius::Large, _pixw, _pixh, width, height); + pix = _data->full->pixSingle(roundRadius, _pixw, _pixh, width, height); } else { - pix = _data->thumb->pixBlurredSingle(ImageRoundRadius::Large, _pixw, _pixh, width, height); + pix = _data->thumb->pixBlurredSingle(roundRadius, _pixw, _pixh, width, height); } QRect rthumb(rtlrect(skipx, skipy, width, height, _width)); p.drawPixmap(rthumb.topLeft(), pix); @@ -4621,7 +4623,9 @@ int HistoryGif::resizeGetHeight(int width) { _width = qMax(_width, _parent->infoWidth() + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x())); if (gif() && _gif->ready()) { if (!_gif->started()) { - _gif->start(_thumbw, _thumbh, _width, _height, true); + auto inWebPage = (_parent->getMedia() != this); + auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; + _gif->start(_thumbw, _thumbh, _width, _height, roundRadius); } } else { _width = qMax(_width, gifMaxStatusWidth(_data) + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x())); diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index 7683ea23b..06b1e07be 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -339,7 +339,7 @@ void Gif::clipCallback(Media::Clip::Notification notification) { } else if (_gif->ready() && !_gif->started()) { int32 height = st::inlineMediaHeight; QSize frame = countFrameSize(); - _gif->start(frame.width(), frame.height(), _width, height, false); + _gif->start(frame.width(), frame.height(), _width, height, ImageRoundRadius::None); } else if (_gif->autoPausedGif() && !Ui::isInlineItemVisible(this)) { delete _gif; _gif = nullptr; diff --git a/Telegram/SourceFiles/layerwidget.cpp b/Telegram/SourceFiles/layerwidget.cpp index 08f840da6..602921043 100644 --- a/Telegram/SourceFiles/layerwidget.cpp +++ b/Telegram/SourceFiles/layerwidget.cpp @@ -397,7 +397,7 @@ void MediaPreviewWidget::clipCallback(Media::Clip::Notification notification) { if (gif() && _gif->ready() && !_gif->started()) { QSize s = currentDimensions(); - _gif->start(s.width(), s.height(), s.width(), s.height(), false); + _gif->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None); } update(); diff --git a/Telegram/SourceFiles/media/media_audio.cpp b/Telegram/SourceFiles/media/media_audio.cpp index 127282dd4..799c3511a 100644 --- a/Telegram/SourceFiles/media/media_audio.cpp +++ b/Telegram/SourceFiles/media/media_audio.cpp @@ -581,6 +581,12 @@ void AudioPlayer::pauseFromVideo(uint64 videoPlayId) { } break; } emit faderOnTimer(); + + QMutexLocker videoLock(&_lastVideoMutex); + if (_lastVideoPlayId == videoPlayId) { + _lastVideoPlaybackWhen = 0; + _lastVideoPlaybackCorrectedMs = 0; + } } if (current) emit updated(current); } @@ -663,8 +669,10 @@ void AudioPlayer::videoSoundProgress(const AudioMsgId &audio) { t_assert(current != nullptr); if (current->videoPlayId == _lastVideoPlayId && current->playbackState.duration && current->playbackState.frequency) { - _lastVideoPlaybackWhen = getms(); - _lastVideoPlaybackCorrectedMs = (current->playbackState.position * 1000ULL) / current->playbackState.frequency; + if (current->playbackState.state == AudioPlayerPlaying) { + _lastVideoPlaybackWhen = getms(); + _lastVideoPlaybackCorrectedMs = (current->playbackState.position * 1000ULL) / current->playbackState.frequency; + } } } diff --git a/Telegram/SourceFiles/media/media_clip_reader.cpp b/Telegram/SourceFiles/media/media_clip_reader.cpp index fee4786aa..0795ada90 100644 --- a/Telegram/SourceFiles/media/media_clip_reader.cpp +++ b/Telegram/SourceFiles/media/media_clip_reader.cpp @@ -43,7 +43,7 @@ QVector managers; QPixmap _prepareFrame(const FrameRequest &request, const QImage &original, bool hasAlpha, QImage &cache) { bool badSize = (original.width() != request.framew) || (original.height() != request.frameh); bool needOuter = (request.outerw != request.framew) || (request.outerh != request.frameh); - if (badSize || needOuter || hasAlpha || request.rounded) { + if (badSize || needOuter || hasAlpha || request.radius != ImageRoundRadius::None) { int32 factor(request.factor); bool newcache = (cache.width() != request.outerw || cache.height() != request.outerh); if (newcache) { @@ -75,8 +75,8 @@ QPixmap _prepareFrame(const FrameRequest &request, const QImage &original, bool p.drawImage(position, original); } } - if (request.rounded) { - imageRound(cache, ImageRoundRadius::Large); + if (request.radius != ImageRoundRadius::None) { + imageRound(cache, request.radius); } return QPixmap::fromImage(cache, Qt::ColorOnly); } @@ -185,7 +185,7 @@ void Reader::callback(Reader *reader, int32 threadIndex, Notification notificati } } -void Reader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, bool rounded) { +void Reader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, ImageRoundRadius radius) { if (managers.size() <= _threadIndex) error(); if (_state == State::Error) return; @@ -197,7 +197,7 @@ void Reader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, bool request.frameh = frameh * factor; request.outerw = outerw * factor; request.outerh = outerh * factor; - request.rounded = rounded; + request.radius = radius; _frames[0].request = _frames[1].request = _frames[2].request = request; moveToNextShow(); managers.at(_threadIndex)->start(this); @@ -489,6 +489,7 @@ public: int64 delta = static_cast(ms) - static_cast(_videoPausedAtMs); _animationStarted += delta; _nextFrameWhen += delta; + LOG(("RESUME VIDEO: next when: %1, started: %2, delta: %3").arg(_nextFrameWhen).arg(_animationStarted).arg(delta)); _videoPausedAtMs = 0; _implementation->resumeAudio(); diff --git a/Telegram/SourceFiles/media/media_clip_reader.h b/Telegram/SourceFiles/media/media_clip_reader.h index c4620a2c1..d2a3f7be6 100644 --- a/Telegram/SourceFiles/media/media_clip_reader.h +++ b/Telegram/SourceFiles/media/media_clip_reader.h @@ -40,7 +40,7 @@ struct FrameRequest { int frameh = 0; int outerw = 0; int outerh = 0; - bool rounded = false; + ImageRoundRadius radius = ImageRoundRadius::None; }; enum ReaderSteps { @@ -75,7 +75,7 @@ public: return _seekPositionMs; } - void start(int framew, int frameh, int outerw, int outerh, bool rounded); + void start(int framew, int frameh, int outerw, int outerh, ImageRoundRadius radius); QPixmap current(int framew, int frameh, int outerw, int outerh, uint64 ms); QPixmap frameOriginal() const { Frame *frame = frameToShow(); diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 1f07a9fc9..98d4883d4 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -226,7 +226,7 @@ bool MediaView::gifShown() const { _gif->pauseResumeVideo(); const_cast(this)->_videoPaused = _gif->videoPaused(); } - _gif->start(_gif->width(), _gif->height(), _gif->width(), _gif->height(), false); + _gif->start(_gif->width(), _gif->height(), _gif->width(), _gif->height(), ImageRoundRadius::None); const_cast(this)->_current = QPixmap(); } return true;// _gif->state() != Media::Clip::State::Error; @@ -500,6 +500,9 @@ void MediaView::step_radial(uint64 ms, bool timer) { update(radialRect()); } if (_doc && _doc->loaded() && _doc->size < MediaViewImageSizeLimit && (!_radial.animating() || _doc->isAnimation() || _doc->isVideo())) { + if (_doc->isVideo()) { + _autoplayVideoDocument = _doc; + } if (!_doc->data().isEmpty() && (_doc->isAnimation() || _doc->isVideo())) { displayDocument(_doc, App::histItemById(_msgmigrated ? 0 : _channel, _msgid)); } else { @@ -1149,6 +1152,7 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty } } + _docIconRect = QRect((width() - st::mvDocIconSize) / 2, (height() - st::mvDocIconSize) / 2, st::mvDocIconSize, st::mvDocIconSize); if (!fileShown()) { if (!_doc || _doc->thumb->isNull()) { int32 colorIndex = documentColorIndex(_doc, _docExt); @@ -1262,6 +1266,8 @@ void MediaView::initAnimation() { } else if (location.accessEnable()) { createClipReader(); location.accessDisable(); + } else { + _current = _doc->thumb->pixNoCache(_doc->dimensions.width(), _doc->dimensions.height(), ImagePixSmooth | ImagePixBlurred, _doc->dimensions.width(), _doc->dimensions.height()); } } @@ -1322,6 +1328,8 @@ void MediaView::setClipControllerGeometry() { } void MediaView::onVideoPauseResume() { + if (!_gif) return; + if (auto item = App::histItemById(_msgmigrated ? 0 : _channel, _msgid)) { if (_gif->state() == Media::Clip::State::Error) { displayDocument(_doc, item); @@ -1440,7 +1448,7 @@ void MediaView::paintEvent(QPaintEvent *e) { Painter p(this); - bool name = false, icon = false; + bool name = false; p.setClipRegion(region); @@ -1504,19 +1512,24 @@ void MediaView::paintEvent(QPaintEvent *e) { radial = _radial.animating(); radialOpacity = _radial.opacity(); } - if (radial) { - QRect inner(QPoint(_photoRadialRect.x(), _photoRadialRect.y()), st::radialSize); - p.setPen(Qt::NoPen); - p.setBrush(st::black); - p.setOpacity(radialOpacity * st::radialBgOpacity); + if (_photo) { + if (radial) { + auto inner = radialRect(); - p.setRenderHint(QPainter::HighQualityAntialiasing); - p.drawEllipse(inner); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); + p.setPen(Qt::NoPen); + p.setBrush(st::black); + p.setOpacity(radialOpacity * st::radialBgOpacity); - p.setOpacity(1); - QRect arc(inner.marginsRemoved(QMargins(st::radialLine, st::radialLine, st::radialLine, st::radialLine))); - _radial.draw(p, arc, st::radialLine, st::white); + p.setRenderHint(QPainter::HighQualityAntialiasing); + p.drawEllipse(inner); + p.setRenderHint(QPainter::HighQualityAntialiasing, false); + + p.setOpacity(1); + QRect arc(inner.marginsRemoved(QMargins(st::radialLine, st::radialLine, st::radialLine, st::radialLine))); + _radial.draw(p, arc, st::radialLine, st::white); + } + } else if (_doc) { + paintDocRadialLoading(p, radial, radialOpacity); } if (_saveMsgStarted) { @@ -1559,7 +1572,6 @@ void MediaView::paintEvent(QPaintEvent *e) { radial = _radial.animating(); radialOpacity = _radial.opacity(); } - icon = true; if (!_doc || _doc->thumb->isNull()) { p.fillRect(_docIconRect, _docIconColor->b); if ((!_doc || _doc->loaded()) && (!radial || radialOpacity < 1)) { @@ -1575,42 +1587,17 @@ void MediaView::paintEvent(QPaintEvent *e) { p.drawPixmap(_docIconRect.topLeft(), _doc->thumb->pix(_docThumbw), QRect(_docThumbx * rf, _docThumby * rf, st::mvDocIconSize * rf, st::mvDocIconSize * rf)); } - float64 o = overLevel(OverIcon); - if (radial) { - if (!_doc->loaded() && radialOpacity < 1) { - p.setOpacity((o * 1. + (1 - o) * st::radialDownloadOpacity) * (1 - radialOpacity)); - p.drawSpriteCenter(_docIconRect, st::radialDownload); - } - - QRect inner(QPoint(_docIconRect.x() + ((_docIconRect.width() - st::radialSize.width()) / 2), _docIconRect.y() + ((_docIconRect.height() - st::radialSize.height()) / 2)), st::radialSize); - p.setPen(Qt::NoPen); - p.setBrush(st::black); - p.setOpacity(radialOpacity * st::radialBgOpacity); - - p.setRenderHint(QPainter::HighQualityAntialiasing); - p.drawEllipse(inner); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); - - p.setOpacity((o * 1. + (1 - o) * st::radialCancelOpacity) * radialOpacity); - p.drawSpriteCenter(_docIconRect, st::radialCancel); - p.setOpacity(1); - - QRect arc(inner.marginsRemoved(QMargins(st::radialLine, st::radialLine, st::radialLine, st::radialLine))); - _radial.draw(p, arc, st::radialLine, st::white); - } else if (_doc && !_doc->loaded()) { - p.setOpacity((o * 1. + (1 - o) * st::radialDownloadOpacity)); - p.drawSpriteCenter(_docIconRect, st::radialDownload); - } + paintDocRadialLoading(p, radial, radialOpacity); } if (!_docIconRect.contains(r)) { name = true; - p.setPen(st::mvDocNameColor->p); - p.setFont(st::mvDocNameFont->f); + p.setPen(st::mvDocNameColor); + p.setFont(st::mvDocNameFont); p.drawTextLeft(_docRect.x() + 2 * st::mvDocPadding + st::mvDocIconSize, _docRect.y() + st::mvDocPadding + st::mvDocNameTop, width(), _docName, _docNameWidth); - p.setPen(st::mvDocSizeColor->p); - p.setFont(st::mvFont->f); + p.setPen(st::mvDocSizeColor); + p.setFont(st::mvFont); p.drawTextLeft(_docRect.x() + 2 * st::mvDocPadding + st::mvDocIconSize, _docRect.y() + st::mvDocPadding + st::mvDocSizeTop, width(), _docSize, _docSizeWidth); } } @@ -1740,6 +1727,35 @@ void MediaView::paintEvent(QPaintEvent *e) { } } +void MediaView::paintDocRadialLoading(Painter &p, bool radial, float64 radialOpacity) { + float64 o = overLevel(OverIcon); + if (radial) { + if (!_doc->loaded() && radialOpacity < 1) { + p.setOpacity((o * 1. + (1 - o) * st::radialDownloadOpacity) * (1 - radialOpacity)); + p.drawSpriteCenter(_docIconRect, st::radialDownload); + } + + QRect inner(QPoint(_docIconRect.x() + ((_docIconRect.width() - st::radialSize.width()) / 2), _docIconRect.y() + ((_docIconRect.height() - st::radialSize.height()) / 2)), st::radialSize); + p.setPen(Qt::NoPen); + p.setBrush(st::black); + p.setOpacity(radialOpacity * st::radialBgOpacity); + + p.setRenderHint(QPainter::HighQualityAntialiasing); + p.drawEllipse(inner); + p.setRenderHint(QPainter::HighQualityAntialiasing, false); + + p.setOpacity((o * 1. + (1 - o) * st::radialCancelOpacity) * radialOpacity); + p.drawSpriteCenter(_docIconRect, st::radialCancel); + p.setOpacity(1); + + QRect arc(inner.marginsRemoved(QMargins(st::radialLine, st::radialLine, st::radialLine, st::radialLine))); + _radial.draw(p, arc, st::radialLine, st::white); + } else if (_doc && !_doc->loaded()) { + p.setOpacity((o * 1. + (1 - o) * st::radialDownloadOpacity)); + p.drawSpriteCenter(_docIconRect, st::radialDownload); + } +} + void MediaView::keyPressEvent(QKeyEvent *e) { if (_clipController) { auto toggle1 = (e->key() == Qt::Key_F && e->modifiers().testFlag(Qt::ControlModifier)); @@ -1758,13 +1774,17 @@ void MediaView::keyPressEvent(QKeyEvent *e) { } } if (!_menu && e->key() == Qt::Key_Escape) { - close(); + if (_doc && _doc->loading()) { + onDocClick(); + } else { + close(); + } } else if (e == QKeySequence::Save || e == QKeySequence::SaveAs) { onSaveAs(); } else if (e->key() == Qt::Key_Copy || (e->key() == Qt::Key_C && e->modifiers().testFlag(Qt::ControlModifier))) { onCopy(); } else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return || e->key() == Qt::Key_Space) { - if (_doc && !_doc->loading() && !fileShown()) { + if (_doc && !_doc->loading() && (!fileShown() || !_doc->loaded())) { onDocClick(); } else if (_doc->isVideo()) { onVideoPauseResume(); @@ -2229,8 +2249,14 @@ void MediaView::updateOver(QPoint pos) { updateOverState(OverMore); } else if (_closeNav.contains(pos)) { updateOverState(OverClose); - } else if (_doc && _doc->isVideo() && _gif && QRect(_x, _y, _w, _h).contains(pos)) { - updateOverState(OverVideo); + } else if (_doc && fileShown() && QRect(_x, _y, _w, _h).contains(pos)) { + if (_doc->isVideo() && _gif) { + updateOverState(OverVideo); + } else if (!_doc->loaded()) { + updateOverState(OverIcon); + } else if (_over != OverNone) { + updateOverState(OverNone); + } } else if (_over != OverNone) { updateOverState(OverNone); } @@ -2645,19 +2671,7 @@ void MediaView::updateHeader() { _headerNav = myrtlrect(st::mvTextLeft, height() - st::mvHeaderTop, hwidth, st::mvThickFont->height); } -QColor MediaView::overColor(const QColor &a, float64 ca, const QColor &b, float64 cb) { - QColor res; - float64 o = a.alphaF() * ca + b.alphaF() * cb - a.alphaF() * ca * b.alphaF() * cb; - float64 ka = (o > 0.001) ? (a.alphaF() * ca * (1 - (b.alphaF() * cb)) / o) : 0; - float64 kb = (o > 0.001) ? (b.alphaF() * cb / o) : 0; - res.setRedF(a.redF() * ka + b.redF() * kb); - res.setGreenF(a.greenF() * ka + b.greenF() * kb); - res.setBlueF(a.blueF() * ka + b.blueF() * kb); - res.setAlphaF(o); - return res; -} - -float64 MediaView::overLevel(OverState control) { +float64 MediaView::overLevel(OverState control) const { ShowingOpacities::const_iterator i = _animOpacities.constFind(control); return (i == _animOpacities.cend()) ? (_over == control ? 1 : 0) : i->current(); } diff --git a/Telegram/SourceFiles/mediaview.h b/Telegram/SourceFiles/mediaview.h index 49941fe27..ee996a866 100644 --- a/Telegram/SourceFiles/mediaview.h +++ b/Telegram/SourceFiles/mediaview.h @@ -169,6 +169,8 @@ private: void step_state(uint64 ms, bool timer); void step_radial(uint64 ms, bool timer); + void paintDocRadialLoading(Painter &p, bool radial, float64 radialOpacity); + QBrush _transparentBrush; PhotoData *_photo = nullptr; @@ -315,7 +317,6 @@ private: void updateOverRect(OverState state); bool updateOverState(OverState newState); - float64 overLevel(OverState control); - QColor overColor(const QColor &a, float64 ca, const QColor &b, float64 cb); + float64 overLevel(OverState control) const; }; diff --git a/Telegram/SourceFiles/ui/images.h b/Telegram/SourceFiles/ui/images.h index 8596dbfc4..2a2ca3b2d 100644 --- a/Telegram/SourceFiles/ui/images.h +++ b/Telegram/SourceFiles/ui/images.h @@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mtproto/file_download.h" enum class ImageRoundRadius { + None, Large, Small, };