pausing gifs that are not currently displayed

This commit is contained in:
John Preston 2015-12-16 17:39:26 +03:00
parent 322eef660e
commit fdb93f700d
4 changed files with 75 additions and 18 deletions

View File

@ -2441,7 +2441,7 @@ namespace App {
} }
void stopGifItems() { void stopGifItems() {
while (!::gifItems.isEmpty()) { if (!::gifItems.isEmpty()) {
if (HistoryItem *playing = ::gifItems.begin().value()) { if (HistoryItem *playing = ::gifItems.begin().value()) {
if (playing->getMedia() && playing->getMedia()->type() == MediaTypeGif) { if (playing->getMedia() && playing->getMedia()->type() == MediaTypeGif) {
static_cast<HistoryGif*>(playing->getMedia())->stop(playing); static_cast<HistoryGif*>(playing->getMedia())->stop(playing);

View File

@ -83,8 +83,9 @@ enum {
LocalEncryptKeySize = 256, // 2048 bit LocalEncryptKeySize = 256, // 2048 bit
AnimationTimerDelta = 7, AnimationTimerDelta = 7,
ClipThreadsCount = 8, ClipThreadsCount = 4,
AverageGifSize = 320 * 240, AverageGifSize = 320 * 240,
WaitBeforeGifPause = 200, // wait 200ms for gif draw before pausing it
SaveRecentEmojisTimeout = 3000, // 3 secs SaveRecentEmojisTimeout = 3000, // 3 secs
SaveWindowPositionTimeout = 1000, // 1 sec SaveWindowPositionTimeout = 1000, // 1 sec

View File

@ -330,6 +330,8 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data) : _
, _width(0) , _width(0)
, _height(0) , _height(0)
, _currentDisplayed(1) , _currentDisplayed(1)
, _paused(0)
, _lastDisplayMs(getms())
, _private(0) { , _private(0) {
if (_clipThreads.size() < ClipThreadsCount) { if (_clipThreads.size() < ClipThreadsCount) {
_threadIndex = _clipThreads.size(); _threadIndex = _clipThreads.size();
@ -365,8 +367,15 @@ void ClipReader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, b
} }
QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh, uint64 ms) { QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh, uint64 ms) {
_currentDisplayed.storeRelease(1); _lastDisplayMs.set(ms);
_lastDisplayMs = ms; _currentDisplayed.set(true);
if (_paused.get()) {
_paused.set(false);
if (_clipManagers.size() <= _threadIndex) error();
if (_state != ClipError) {
_clipManagers.at(_threadIndex)->update(this);
}
}
int32 factor(cIntRetinaFactor()); int32 factor(cIntRetinaFactor());
QPixmap result(_current); QPixmap result(_current);
@ -441,8 +450,10 @@ public:
, _accessed(false) , _accessed(false)
, _buffer(_data.isEmpty() ? 0 : &_data) , _buffer(_data.isEmpty() ? 0 : &_data)
, _reader(0) , _reader(0)
, _previousMs(0)
, _currentMs(0) , _currentMs(0)
, _nextUpdateMs(0) { , _nextUpdateMs(0)
, _paused(false) {
if (_data.isEmpty() && !_location->accessEnable()) { if (_data.isEmpty() && !_location->accessEnable()) {
error(); error();
@ -476,6 +487,7 @@ public:
if (_current.isNull()) { // first frame read, but not yet prepared if (_current.isNull()) { // first frame read, but not yet prepared
_currentOriginal.setDevicePixelRatio(_request.factor); _currentOriginal.setDevicePixelRatio(_request.factor);
_previousMs = _currentMs;
_currentMs = ms; _currentMs = ms;
_current = _prepareFrame(_request, _currentOriginal, _currentCache, true); _current = _prepareFrame(_request, _currentOriginal, _currentCache, true);
@ -483,7 +495,7 @@ public:
return error(); return error();
} }
return ClipProcessStarted; return ClipProcessStarted;
} else if (ms >= _nextUpdateMs) { } else if (!_paused && ms >= _nextUpdateMs) {
swapBuffers(); swapBuffers();
return ClipProcessRedraw; return ClipProcessRedraw;
} }
@ -508,6 +520,7 @@ public:
} }
void swapBuffers(uint64 ms = 0) { void swapBuffers(uint64 ms = 0) {
_previousMs = _currentMs;
_currentMs = qMax(ms, _nextUpdateMs); _currentMs = qMax(ms, _nextUpdateMs);
qSwap(_currentOriginal, _nextOriginal); qSwap(_currentOriginal, _nextOriginal);
qSwap(_current, _next); qSwap(_current, _next);
@ -628,13 +641,15 @@ private:
QImage _currentOriginal, _nextOriginal, _currentCache, _nextCache; QImage _currentOriginal, _nextOriginal, _currentCache, _nextCache;
int32 _framesLeft; int32 _framesLeft;
uint64 _currentMs, _nextUpdateMs; uint64 _previousMs, _currentMs, _nextUpdateMs;
bool _paused;
friend class ClipReadManager; friend class ClipReadManager;
}; };
ClipReadManager::ClipReadManager(QThread *thread) : _processingInThread(0) { ClipReadManager::ClipReadManager(QThread *thread) : _processingInThread(0), _needReProcess(false) {
moveToThread(thread); moveToThread(thread);
connect(thread, SIGNAL(started()), this, SLOT(process())); connect(thread, SIGNAL(started()), this, SLOT(process()));
connect(this, SIGNAL(processDelayed()), this, SLOT(process()), Qt::QueuedConnection); connect(this, SIGNAL(processDelayed()), this, SLOT(process()), Qt::QueuedConnection);
@ -669,7 +684,7 @@ void ClipReadManager::stop(ClipReader *reader) {
emit processDelayed(); emit processDelayed();
} }
bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result) { bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) {
QMutexLocker lock(&_readerPointersMutex); QMutexLocker lock(&_readerPointersMutex);
ReaderPointers::iterator it = _readerPointers.find(reader->_interface); ReaderPointers::iterator it = _readerPointers.find(reader->_interface);
if (result == ClipProcessError) { if (result == ClipProcessError) {
@ -686,10 +701,20 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
if (result == ClipProcessStarted) { if (result == ClipProcessStarted) {
_loadLevel.fetchAndAddRelease(reader->_currentOriginal.width() * reader->_currentOriginal.height() - AverageGifSize); _loadLevel.fetchAndAddRelease(reader->_currentOriginal.width() * reader->_currentOriginal.height() - AverageGifSize);
} }
if (!reader->_paused && (result == ClipProcessRedraw || result == ClipProcessWait)) {
if (it.key()->_lastDisplayMs.get() + WaitBeforeGifPause < qMax(reader->_previousMs, ms)) {
reader->_paused = true;
it.key()->_paused.set(true);
if (it.key()->_lastDisplayMs.get() + WaitBeforeGifPause >= qMax(reader->_previousMs, ms)) {
it.key()->_paused.set(false);
reader->_paused = false;
}
}
}
if (result == ClipProcessReinit || result == ClipProcessRedraw || result == ClipProcessStarted) { if (result == ClipProcessReinit || result == ClipProcessRedraw || result == ClipProcessStarted) {
it.key()->_current = reader->_current; it.key()->_current = reader->_current;
it.key()->_currentOriginal = reader->_currentOriginal; it.key()->_currentOriginal = reader->_currentOriginal;
it.key()->_currentDisplayed.storeRelease(0); it.key()->_currentDisplayed.set(false);
if (result == ClipProcessReinit) { if (result == ClipProcessReinit) {
emit reinit(it.key()); emit reinit(it.key());
} else if (result == ClipProcessRedraw) { } else if (result == ClipProcessRedraw) {
@ -700,7 +725,7 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
} }
ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) { ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) {
if (!handleProcessResult(reader, result)) { if (!handleProcessResult(reader, result, ms)) {
_loadLevel.fetchAndAddRelease(-1 * (reader->_currentOriginal.isNull() ? AverageGifSize : reader->_currentOriginal.width() * reader->_currentOriginal.height())); _loadLevel.fetchAndAddRelease(-1 * (reader->_currentOriginal.isNull() ? AverageGifSize : reader->_currentOriginal.width() * reader->_currentOriginal.height()));
delete reader; delete reader;
return ResultHandleRemove; return ResultHandleRemove;
@ -719,7 +744,10 @@ ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPriva
} }
void ClipReadManager::process() { void ClipReadManager::process() {
if (_processingInThread) return; if (_processingInThread) {
_needReProcess = true;
return;
}
_timer.stop(); _timer.stop();
_processingInThread = thread(); _processingInThread = thread();
@ -734,6 +762,9 @@ void ClipReadManager::process() {
_readers.insert(i.value(), 0); _readers.insert(i.value(), 0);
} else { } else {
it.value() = ms; it.value() = ms;
if (it.key()->_paused && !i.key()->_paused.get()) {
it.key()->_paused = false;
}
} }
i.value()->_request = i.key()->_request; i.value()->_request = i.key()->_request;
i.value() = 0; i.value() = 0;
@ -754,15 +785,17 @@ void ClipReadManager::process() {
return; return;
} }
i.value() = i.key()->_nextUpdateMs; i.value() = i.key()->_nextUpdateMs;
ms = getms();
} }
if (i.value() < minms) { if (!i.key()->_paused && i.value() < minms) {
minms = i.value(); minms = i.value();
} }
++i; ++i;
} }
ms = getms(); ms = getms();
if (minms <= ms) { if (_needReProcess || minms <= ms) {
_needReProcess = false;
_timer.start(1); _timer.start(1);
} else { } else {
_timer.start(minms - ms); _timer.start(minms - ms);

View File

@ -493,6 +493,28 @@ struct ClipFrameRequest {
bool rounded; bool rounded;
}; };
template <typename Type>
class Atomic {
public:
Atomic(const Type &value = Type()) : _v(1, value) {
}
Type get() const {
QVector<Type> v(_v);
return v.at(0);
}
void set(const Type &value) {
QVector<Type> v(1, value);
_v = v;
}
private:
QVector<Type> _v;
};
class ClipReaderPrivate; class ClipReaderPrivate;
class ClipReader { class ClipReader {
public: public:
@ -502,7 +524,7 @@ public:
void start(int32 framew, int32 frameh, int32 outerw, int32 outerh, bool rounded); void start(int32 framew, int32 frameh, int32 outerw, int32 outerh, bool rounded);
QPixmap current(int32 framew, int32 frameh, int32 outerw, int32 outerh, uint64 ms); QPixmap current(int32 framew, int32 frameh, int32 outerw, int32 outerh, uint64 ms);
bool currentDisplayed() const { bool currentDisplayed() const {
return _currentDisplayed.loadAcquire() > 0; return _currentDisplayed.get();
} }
int32 width() const; int32 width() const;
@ -529,8 +551,8 @@ private:
QPixmap _current; QPixmap _current;
QImage _currentOriginal, _cacheForResize; QImage _currentOriginal, _cacheForResize;
QAtomicInt _currentDisplayed; Atomic<bool> _currentDisplayed, _paused;
uint64 _lastDisplayMs; Atomic<uint64> _lastDisplayMs;
int32 _threadIndex; int32 _threadIndex;
friend class ClipReadManager; friend class ClipReadManager;
@ -580,7 +602,7 @@ private:
ReaderPointers _readerPointers; ReaderPointers _readerPointers;
QMutex _readerPointersMutex; QMutex _readerPointersMutex;
bool handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result); bool handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms);
enum ResultHandleState { enum ResultHandleState {
ResultHandleRemove, ResultHandleRemove,
@ -594,5 +616,6 @@ private:
QTimer _timer; QTimer _timer;
QThread *_processingInThread; QThread *_processingInThread;
bool _needReProcess;
}; };