2014-05-30 12:53:19 +04:00
/*
This file is part of Telegram Desktop ,
2014-12-01 13:47:38 +03:00
the official desktop version of Telegram messaging app , see https : //telegram.org
2014-05-30 12:53:19 +04:00
Telegram Desktop is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
It is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2015-10-03 16:16:42 +03:00
In addition , as a special exception , the copyright holders give permission
to link the code of portions of this program with the OpenSSL library .
2014-05-30 12:53:19 +04:00
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2015-10-03 16:16:42 +03:00
Copyright ( c ) 2014 - 2015 John Preston , https : //desktop.telegram.org
2014-05-30 12:53:19 +04:00
*/
# include "stdafx.h"
# include "localimageloader.h"
2014-08-11 13:03:45 +04:00
# include "gui/filedialog.h"
2015-07-01 00:07:05 +03:00
# include "audio.h"
2014-05-30 12:53:19 +04:00
# include <libexif/exif-data.h>
2015-09-29 21:44:31 +03:00
LocalImageLoaderPrivate : : LocalImageLoaderPrivate ( LocalImageLoader * loader , QThread * thread ) : QObject ( 0 )
2014-06-16 13:31:10 +04:00
, loader ( loader )
{
2014-05-30 12:53:19 +04:00
moveToThread ( thread ) ;
connect ( loader , SIGNAL ( needToPrepare ( ) ) , this , SLOT ( prepareImages ( ) ) ) ;
connect ( this , SIGNAL ( imageReady ( ) ) , loader , SLOT ( onImageReady ( ) ) ) ;
connect ( this , SIGNAL ( imageFailed ( quint64 ) ) , loader , SLOT ( onImageFailed ( quint64 ) ) ) ;
} ;
void LocalImageLoaderPrivate : : prepareImages ( ) {
2015-01-05 23:17:33 +03:00
QString file , filename , mime , stickerMime = qsl ( " image/webp " ) ;
2014-07-14 09:16:21 +04:00
int32 filesize = 0 ;
2014-05-30 12:53:19 +04:00
QImage img ;
QByteArray data ;
PeerId peer ;
2015-01-05 23:17:33 +03:00
uint64 id , thumbId = 0 ;
2015-05-29 21:52:43 +03:00
int32 duration = 0 ;
2015-01-05 23:17:33 +03:00
QString thumbExt = " jpg " ;
2014-05-30 12:53:19 +04:00
ToPrepareMediaType type ;
2014-12-23 02:11:37 +03:00
bool animated = false ;
2015-09-21 23:57:42 +03:00
bool broadcast = false ;
2014-10-17 23:14:42 +04:00
bool ctrlShiftEnter = false ;
2015-09-03 13:48:40 +03:00
MsgId replyTo ;
2014-05-30 12:53:19 +04:00
{
QMutexLocker lock ( loader - > toPrepareMutex ( ) ) ;
ToPrepareMedias & list ( loader - > toPrepareMedias ( ) ) ;
if ( list . isEmpty ( ) ) return ;
file = list . front ( ) . file ;
img = list . front ( ) . img ;
data = list . front ( ) . data ;
peer = list . front ( ) . peer ;
id = list . front ( ) . id ;
type = list . front ( ) . type ;
2015-05-29 21:52:43 +03:00
duration = list . front ( ) . duration ;
2015-09-21 23:57:42 +03:00
broadcast = list . front ( ) . broadcast ;
2014-10-17 23:14:42 +04:00
ctrlShiftEnter = list . front ( ) . ctrlShiftEnter ;
2015-03-19 12:18:19 +03:00
replyTo = list . front ( ) . replyTo ;
2014-05-30 12:53:19 +04:00
}
if ( img . isNull ( ) ) {
if ( ! file . isEmpty ( ) ) {
QFileInfo info ( file ) ;
if ( type = = ToPrepareAuto ) {
QString lower ( file . toLower ( ) ) ;
const QStringList & photoExtensions ( cPhotoExtensions ( ) ) ;
for ( QStringList : : const_iterator i = photoExtensions . cbegin ( ) , e = photoExtensions . cend ( ) ; i ! = e ; + + i ) {
if ( lower . lastIndexOf ( * i ) = = lower . size ( ) - i - > size ( ) ) {
if ( info . size ( ) < MaxUploadPhotoSize ) {
type = ToPreparePhoto ;
break ;
}
}
}
if ( type = = ToPrepareAuto & & info . size ( ) < MaxUploadDocumentSize ) {
type = ToPrepareDocument ;
}
}
2015-01-05 23:17:33 +03:00
if ( type ! = ToPrepareAuto & & info . size ( ) < MaxUploadPhotoSize ) {
bool opaque = ( mime ! = stickerMime ) ;
img = App : : readImage ( file , 0 , opaque , & animated ) ;
2015-08-14 18:47:56 +03:00
if ( animated ) {
type = ToPrepareDocument ;
}
}
if ( type = = ToPrepareDocument ) {
mime = mimeTypeForFile ( info ) . name ( ) ;
2015-01-05 23:17:33 +03:00
}
2014-05-30 12:53:19 +04:00
filename = info . fileName ( ) ;
filesize = info . size ( ) ;
} else if ( ! data . isEmpty ( ) ) {
2015-05-29 21:52:43 +03:00
if ( type ! = ToPrepareAudio ) {
img = App : : readImage ( data , 0 , true , & animated ) ;
if ( type = = ToPrepareAuto ) {
if ( ! img . isNull ( ) & & data . size ( ) < MaxUploadPhotoSize ) {
type = ToPreparePhoto ;
} else if ( data . size ( ) < MaxUploadDocumentSize ) {
type = ToPrepareDocument ;
} else {
img = QImage ( ) ;
}
2014-05-30 12:53:19 +04:00
}
}
2015-01-03 02:44:34 +03:00
MimeType mimeType = mimeTypeForData ( data ) ;
2015-05-29 21:52:43 +03:00
if ( type = = ToPrepareDocument | | type = = ToPrepareAudio ) {
2014-05-30 12:53:19 +04:00
mime = mimeType . name ( ) ;
}
2015-01-05 23:17:33 +03:00
if ( mime = = " image/jpeg " ) {
filename = filedialogDefaultName ( qsl ( " image " ) , qsl ( " .jpg " ) , QString ( ) , true ) ;
2015-06-01 12:42:56 +03:00
} else if ( type = = ToPrepareAudio ) {
2015-05-29 21:52:43 +03:00
filename = filedialogDefaultName ( qsl ( " audio " ) , qsl ( " .ogg " ) , QString ( ) , true ) ;
mime = " audio/ogg " ;
2015-01-05 23:17:33 +03:00
} else {
QString ext ;
QStringList patterns = mimeType . globPatterns ( ) ;
if ( ! patterns . isEmpty ( ) ) {
ext = patterns . front ( ) . replace ( ' * ' , QString ( ) ) ;
}
2015-05-29 21:52:43 +03:00
filename = filedialogDefaultName ( ( type = = ToPrepareAudio ) ? qsl ( " audio " ) : qsl ( " doc " ) , ext , QString ( ) , true ) ;
2014-05-30 12:53:19 +04:00
}
filesize = data . size ( ) ;
}
} else {
2014-08-11 13:03:45 +04:00
if ( type = = ToPrepareDocument ) {
filename = filedialogDefaultName ( qsl ( " image " ) , qsl ( " .png " ) , QString ( ) , true ) ;
2015-01-03 02:44:34 +03:00
mime = mimeTypeForName ( " image/png " ) . name ( ) ;
2014-08-11 13:03:45 +04:00
data = QByteArray ( ) ;
{
QBuffer b ( & data ) ;
img . save ( & b , " PNG " ) ;
}
filesize = data . size ( ) ;
} else {
2015-01-05 23:17:33 +03:00
if ( img . hasAlphaChannel ( ) ) {
QImage solid ( img . width ( ) , img . height ( ) , QImage : : Format_ARGB32_Premultiplied ) ;
solid . fill ( st : : white - > c ) ;
{
QPainter ( & solid ) . drawImage ( 0 , 0 , img ) ;
}
img = solid ;
}
type = ToPreparePhoto ;
2014-08-11 13:03:45 +04:00
filename = qsl ( " Untitled.jpg " ) ;
filesize = 0 ;
}
2014-05-30 12:53:19 +04:00
}
2015-05-29 21:52:43 +03:00
if ( ( img . isNull ( ) & & ( ( type ! = ToPrepareDocument & & type ! = ToPrepareAudio ) | | ! filesize ) ) | | type = = ToPrepareAuto | | ( img . isNull ( ) & & file . isEmpty ( ) & & data . isEmpty ( ) ) ) { // if could not decide what type
2014-05-30 12:53:19 +04:00
{
QMutexLocker lock ( loader - > toPrepareMutex ( ) ) ;
ToPrepareMedias & list ( loader - > toPrepareMedias ( ) ) ;
list . pop_front ( ) ;
}
QTimer : : singleShot ( 1 , this , SLOT ( prepareImages ( ) ) ) ;
emit imageFailed ( id ) ;
} else {
PreparedPhotoThumbs photoThumbs ;
QVector < MTPPhotoSize > photoSizes ;
2014-12-23 02:11:37 +03:00
QVector < MTPDocumentAttribute > attributes ( 1 , MTP_documentAttributeFilename ( MTP_string ( filename ) ) ) ;
2014-05-30 12:53:19 +04:00
MTPPhotoSize thumb ( MTP_photoSizeEmpty ( MTP_string ( " " ) ) ) ;
MTPPhoto photo ( MTP_photoEmpty ( MTP_long ( 0 ) ) ) ;
MTPDocument document ( MTP_documentEmpty ( MTP_long ( 0 ) ) ) ;
2015-05-29 21:52:43 +03:00
MTPAudio audio ( MTP_audioEmpty ( MTP_long ( 0 ) ) ) ;
2014-05-30 12:53:19 +04:00
2015-07-01 00:07:05 +03:00
bool isSong = false ;
2014-05-30 12:53:19 +04:00
QByteArray jpeg ;
2015-07-01 00:07:05 +03:00
if ( type = = ToPrepareDocument ) {
2015-07-17 22:30:24 +03:00
if ( mime = = qstr ( " audio/mp3 " ) | | mime = = qstr ( " audio/m4a " ) | | mime = = qstr ( " audio/aac " ) | | mime = = qstr ( " audio/ogg " ) | | mime = = qstr ( " audio/flac " ) | |
2015-07-01 00:07:05 +03:00
filename . endsWith ( qstr ( " .mp3 " ) , Qt : : CaseInsensitive ) | | filename . endsWith ( qstr ( " .m4a " ) , Qt : : CaseInsensitive ) | |
2015-07-17 22:30:24 +03:00
filename . endsWith ( qstr ( " .aac " ) , Qt : : CaseInsensitive ) | | filename . endsWith ( qstr ( " .ogg " ) , Qt : : CaseInsensitive ) | |
filename . endsWith ( qstr ( " .flac " ) , Qt : : CaseInsensitive ) ) {
2015-07-01 00:07:05 +03:00
QImage cover ;
QByteArray coverBytes , coverFormat ;
MTPDocumentAttribute audioAttribute = audioReadSongAttributes ( file , data , cover , coverBytes , coverFormat ) ;
if ( audioAttribute . type ( ) = = mtpc_documentAttributeAudio ) {
attributes . push_back ( audioAttribute ) ;
isSong = true ;
if ( ! cover . isNull ( ) ) { // cover to thumb
int32 cw = cover . width ( ) , ch = cover . height ( ) ;
if ( cw < 20 * ch & & ch < 20 * cw ) {
QPixmap full = ( cw > 90 | | ch > 90 ) ? QPixmap : : fromImage ( cover . scaled ( 90 , 90 , Qt : : KeepAspectRatio , Qt : : SmoothTransformation ) , Qt : : ColorOnly ) : QPixmap : : fromImage ( cover , Qt : : ColorOnly ) ;
{
QByteArray thumbFormat = " JPG " ;
int32 thumbQuality = 87 ;
QBuffer jpegBuffer ( & jpeg ) ;
full . save ( & jpegBuffer , thumbFormat , thumbQuality ) ;
}
photoThumbs . insert ( ' 0 ' , full ) ;
thumb = MTP_photoSize ( MTP_string ( " " ) , MTP_fileLocationUnavailable ( MTP_long ( 0 ) , MTP_int ( 0 ) , MTP_long ( 0 ) ) , MTP_int ( full . width ( ) ) , MTP_int ( full . height ( ) ) , MTP_int ( 0 ) ) ;
thumbId = MTP : : nonce < uint64 > ( ) ;
}
}
}
}
}
2014-05-30 12:53:19 +04:00
if ( type = = ToPreparePhoto ) {
int32 w = img . width ( ) , h = img . height ( ) ;
2014-12-23 02:11:37 +03:00
QPixmap thumb = ( w > 100 | | h > 100 ) ? QPixmap : : fromImage ( img . scaled ( 100 , 100 , Qt : : KeepAspectRatio , Qt : : SmoothTransformation ) , Qt : : ColorOnly ) : QPixmap : : fromImage ( img ) ;
2014-05-30 12:53:19 +04:00
photoThumbs . insert ( ' s ' , thumb ) ;
photoSizes . push_back ( MTP_photoSize ( MTP_string ( " s " ) , MTP_fileLocationUnavailable ( MTP_long ( 0 ) , MTP_int ( 0 ) , MTP_long ( 0 ) ) , MTP_int ( thumb . width ( ) ) , MTP_int ( thumb . height ( ) ) , MTP_int ( 0 ) ) ) ;
2014-12-23 02:11:37 +03:00
QPixmap medium = ( w > 320 | | h > 320 ) ? QPixmap : : fromImage ( img . scaled ( 320 , 320 , Qt : : KeepAspectRatio , Qt : : SmoothTransformation ) , Qt : : ColorOnly ) : QPixmap : : fromImage ( img ) ;
2014-08-15 15:19:32 +04:00
photoThumbs . insert ( ' m ' , medium ) ;
photoSizes . push_back ( MTP_photoSize ( MTP_string ( " m " ) , MTP_fileLocationUnavailable ( MTP_long ( 0 ) , MTP_int ( 0 ) , MTP_long ( 0 ) ) , MTP_int ( medium . width ( ) ) , MTP_int ( medium . height ( ) ) , MTP_int ( 0 ) ) ) ;
2014-12-23 02:11:37 +03:00
QPixmap full = ( w > 1280 | | h > 1280 ) ? QPixmap : : fromImage ( img . scaled ( 1280 , 1280 , Qt : : KeepAspectRatio , Qt : : SmoothTransformation ) , Qt : : ColorOnly ) : QPixmap : : fromImage ( img ) ;
2014-12-12 19:27:03 +03:00
photoThumbs . insert ( ' y ' , full ) ;
photoSizes . push_back ( MTP_photoSize ( MTP_string ( " y " ) , MTP_fileLocationUnavailable ( MTP_long ( 0 ) , MTP_int ( 0 ) , MTP_long ( 0 ) ) , MTP_int ( full . width ( ) ) , MTP_int ( full . height ( ) ) , MTP_int ( 0 ) ) ) ;
2014-05-30 12:53:19 +04:00
{
QBuffer jpegBuffer ( & jpeg ) ;
2014-12-12 19:27:03 +03:00
full . save ( & jpegBuffer , " JPG " , 77 ) ;
2014-05-30 12:53:19 +04:00
}
if ( ! filesize ) filesize = jpeg . size ( ) ;
2015-08-12 21:01:32 +03:00
photo = MTP_photo ( MTP_long ( id ) , MTP_long ( 0 ) , MTP_int ( unixtime ( ) ) , MTP_vector < MTPPhotoSize > ( photoSizes ) ) ;
2014-05-30 12:53:19 +04:00
2015-01-05 23:17:33 +03:00
thumbId = id ;
2015-07-01 00:07:05 +03:00
} else if ( ( type = = ToPrepareVideo | | type = = ToPrepareDocument ) & & ! img . isNull ( ) & & ! isSong ) {
2014-05-30 12:53:19 +04:00
int32 w = img . width ( ) , h = img . height ( ) ;
2015-01-02 17:55:24 +03:00
QByteArray thumbFormat = " JPG " ;
2015-01-05 23:17:33 +03:00
int32 thumbQuality = 87 ;
2015-01-02 17:55:24 +03:00
if ( animated ) {
attributes . push_back ( MTP_documentAttributeAnimated ( ) ) ;
2015-01-05 23:17:33 +03:00
} else if ( mime = = stickerMime & & w > 0 & & h > 0 & & w < = StickerMaxSize & & h < = StickerMaxSize & & filesize < StickerInMemory ) {
2015-05-11 15:44:27 +03:00
attributes . push_back ( MTP_documentAttributeSticker ( MTP_string ( " " ) , MTP_inputStickerSetEmpty ( ) ) ) ;
2015-01-02 17:55:24 +03:00
thumbFormat = " webp " ;
2015-01-05 23:17:33 +03:00
thumbExt = qsl ( " webp " ) ;
2015-01-02 17:55:24 +03:00
}
2014-12-23 02:11:37 +03:00
attributes . push_back ( MTP_documentAttributeImageSize ( MTP_int ( w ) , MTP_int ( h ) ) ) ;
2015-01-05 23:17:33 +03:00
if ( w < 20 * h & & h < 20 * w ) {
QPixmap full = ( w > 90 | | h > 90 ) ? QPixmap : : fromImage ( img . scaled ( 90 , 90 , Qt : : KeepAspectRatio , Qt : : SmoothTransformation ) , Qt : : ColorOnly ) : QPixmap : : fromImage ( img , Qt : : ColorOnly ) ;
2014-05-30 12:53:19 +04:00
2015-01-05 23:17:33 +03:00
{
QBuffer jpegBuffer ( & jpeg ) ;
full . save ( & jpegBuffer , thumbFormat , thumbQuality ) ;
}
2014-05-30 12:53:19 +04:00
2015-01-05 23:17:33 +03:00
photoThumbs . insert ( ' 0 ' , full ) ;
thumb = MTP_photoSize ( MTP_string ( " " ) , MTP_fileLocationUnavailable ( MTP_long ( 0 ) , MTP_int ( 0 ) , MTP_long ( 0 ) ) , MTP_int ( full . width ( ) ) , MTP_int ( full . height ( ) ) , MTP_int ( 0 ) ) ;
2014-05-30 12:53:19 +04:00
2015-01-05 23:17:33 +03:00
thumbId = MTP : : nonce < uint64 > ( ) ;
}
2014-05-30 12:53:19 +04:00
}
if ( type = = ToPrepareDocument ) {
2014-12-23 02:11:37 +03:00
document = MTP_document ( MTP_long ( id ) , MTP_long ( 0 ) , MTP_int ( unixtime ( ) ) , MTP_string ( mime ) , MTP_int ( filesize ) , thumb , MTP_int ( MTP : : maindc ( ) ) , MTP_vector < MTPDocumentAttribute > ( attributes ) ) ;
2015-05-29 21:52:43 +03:00
} else if ( type = = ToPrepareAudio ) {
2015-08-12 21:01:32 +03:00
audio = MTP_audio ( MTP_long ( id ) , MTP_long ( 0 ) , MTP_int ( unixtime ( ) ) , MTP_int ( duration ) , MTP_string ( mime ) , MTP_int ( filesize ) , MTP_int ( MTP : : maindc ( ) ) ) ;
2014-05-30 12:53:19 +04:00
}
{
QMutexLocker lock ( loader - > readyMutex ( ) ) ;
2015-09-21 23:57:42 +03:00
loader - > readyList ( ) . push_back ( ReadyLocalMedia ( type , file , filename , filesize , data , id , thumbId , thumbExt , peer , photo , audio , photoThumbs , document , jpeg , broadcast , ctrlShiftEnter , replyTo ) ) ;
2014-05-30 12:53:19 +04:00
}
{
QMutexLocker lock ( loader - > toPrepareMutex ( ) ) ;
ToPrepareMedias & list ( loader - > toPrepareMedias ( ) ) ;
list . pop_front ( ) ;
}
QTimer : : singleShot ( 1 , this , SLOT ( prepareImages ( ) ) ) ;
emit imageReady ( ) ;
}
}
LocalImageLoaderPrivate : : ~ LocalImageLoaderPrivate ( ) {
loader = 0 ;
}
LocalImageLoader : : LocalImageLoader ( QObject * parent ) : QObject ( parent ) , thread ( 0 ) , priv ( 0 ) {
}
2015-09-21 23:57:42 +03:00
void LocalImageLoader : : append ( const QStringList & files , const PeerId & peer , bool broadcast , MsgId replyTo , ToPrepareMediaType t ) {
2014-05-30 12:53:19 +04:00
{
QMutexLocker lock ( toPrepareMutex ( ) ) ;
for ( QStringList : : const_iterator i = files . cbegin ( ) , e = files . cend ( ) ; i ! = e ; + + i ) {
2015-09-21 23:57:42 +03:00
toPrepare . push_back ( ToPrepareMedia ( * i , peer , t , broadcast , false , replyTo ) ) ;
2014-05-30 12:53:19 +04:00
}
}
if ( ! thread ) {
thread = new QThread ( ) ;
2015-09-29 21:44:31 +03:00
priv = new LocalImageLoaderPrivate ( this , thread ) ;
2014-05-30 12:53:19 +04:00
thread - > start ( ) ;
}
emit needToPrepare ( ) ;
}
2015-09-21 23:57:42 +03:00
PhotoId LocalImageLoader : : append ( const QByteArray & img , const PeerId & peer , bool broadcast , MsgId replyTo , ToPrepareMediaType t ) {
2014-05-30 12:53:19 +04:00
PhotoId result = 0 ;
{
QMutexLocker lock ( toPrepareMutex ( ) ) ;
2015-09-21 23:57:42 +03:00
toPrepare . push_back ( ToPrepareMedia ( img , peer , t , broadcast , false , replyTo ) ) ;
2014-05-30 12:53:19 +04:00
result = toPrepare . back ( ) . id ;
}
if ( ! thread ) {
thread = new QThread ( ) ;
2015-09-29 21:44:31 +03:00
priv = new LocalImageLoaderPrivate ( this , thread ) ;
2014-05-30 12:53:19 +04:00
thread - > start ( ) ;
}
emit needToPrepare ( ) ;
return result ;
}
2015-09-21 23:57:42 +03:00
AudioId LocalImageLoader : : append ( const QByteArray & audio , int32 duration , const PeerId & peer , bool broadcast , MsgId replyTo , ToPrepareMediaType t ) {
2015-05-29 21:52:43 +03:00
AudioId result = 0 ;
{
QMutexLocker lock ( toPrepareMutex ( ) ) ;
2015-09-21 23:57:42 +03:00
toPrepare . push_back ( ToPrepareMedia ( audio , duration , peer , t , broadcast , false , replyTo ) ) ;
2015-05-29 21:52:43 +03:00
result = toPrepare . back ( ) . id ;
}
if ( ! thread ) {
thread = new QThread ( ) ;
2015-09-29 21:44:31 +03:00
priv = new LocalImageLoaderPrivate ( this , thread ) ;
2015-05-29 21:52:43 +03:00
thread - > start ( ) ;
}
emit needToPrepare ( ) ;
return result ;
}
2015-09-21 23:57:42 +03:00
PhotoId LocalImageLoader : : append ( const QImage & img , const PeerId & peer , bool broadcast , MsgId replyTo , ToPrepareMediaType t , bool ctrlShiftEnter ) {
2014-05-30 12:53:19 +04:00
PhotoId result = 0 ;
{
QMutexLocker lock ( toPrepareMutex ( ) ) ;
2015-09-21 23:57:42 +03:00
toPrepare . push_back ( ToPrepareMedia ( img , peer , t , broadcast , ctrlShiftEnter , replyTo ) ) ;
2014-05-30 12:53:19 +04:00
result = toPrepare . back ( ) . id ;
}
if ( ! thread ) {
thread = new QThread ( ) ;
2015-09-29 21:44:31 +03:00
priv = new LocalImageLoaderPrivate ( this , thread ) ;
2014-05-30 12:53:19 +04:00
thread - > start ( ) ;
}
emit needToPrepare ( ) ;
return result ;
}
2015-09-21 23:57:42 +03:00
PhotoId LocalImageLoader : : append ( const QString & file , const PeerId & peer , bool broadcast , MsgId replyTo , ToPrepareMediaType t ) {
2014-05-30 12:53:19 +04:00
PhotoId result = 0 ;
{
QMutexLocker lock ( toPrepareMutex ( ) ) ;
2015-09-21 23:57:42 +03:00
toPrepare . push_back ( ToPrepareMedia ( file , peer , t , broadcast , false , replyTo ) ) ;
2014-05-30 12:53:19 +04:00
result = toPrepare . back ( ) . id ;
}
if ( ! thread ) {
thread = new QThread ( ) ;
2015-09-29 21:44:31 +03:00
priv = new LocalImageLoaderPrivate ( this , thread ) ;
2014-05-30 12:53:19 +04:00
thread - > start ( ) ;
}
emit needToPrepare ( ) ;
return result ;
}
void LocalImageLoader : : onImageReady ( ) {
{
QMutexLocker lock ( toPrepareMutex ( ) ) ;
if ( toPrepare . isEmpty ( ) ) {
if ( priv ) priv - > deleteLater ( ) ;
priv = 0 ;
if ( thread ) thread - > deleteLater ( ) ;
thread = 0 ;
}
}
emit imageReady ( ) ;
}
void LocalImageLoader : : onImageFailed ( quint64 id ) {
{
QMutexLocker lock ( toPrepareMutex ( ) ) ;
if ( toPrepare . isEmpty ( ) ) {
if ( priv ) priv - > deleteLater ( ) ;
priv = 0 ;
if ( thread ) thread - > deleteLater ( ) ;
thread = 0 ;
}
}
emit imageFailed ( id ) ;
}
QMutex * LocalImageLoader : : readyMutex ( ) {
return & readyLock ;
}
ReadyLocalMedias & LocalImageLoader : : readyList ( ) {
return ready ;
}
QMutex * LocalImageLoader : : toPrepareMutex ( ) {
return & toPrepareLock ;
}
ToPrepareMedias & LocalImageLoader : : toPrepareMedias ( ) {
return toPrepare ;
}
LocalImageLoader : : ~ LocalImageLoader ( ) {
delete priv ;
delete thread ;
}
2015-09-29 21:44:31 +03:00
2015-09-29 21:59:26 +03:00
TaskQueue : : TaskQueue ( QObject * parent , int32 stopTimeoutMs ) : QObject ( parent ) , _thread ( 0 ) , _worker ( 0 ) , _stopTimer ( 0 ) {
2015-09-29 21:44:31 +03:00
if ( stopTimeoutMs > 0 ) {
_stopTimer = new QTimer ( this ) ;
connect ( _stopTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( stop ( ) ) ) ;
_stopTimer - > setSingleShot ( true ) ;
_stopTimer - > setInterval ( stopTimeoutMs ) ;
}
}
TaskId TaskQueue : : addTask ( TaskPtr task ) {
{
QMutexLocker lock ( & _tasksToProcessMutex ) ;
_tasksToProcess . push_back ( task ) ;
}
if ( ! _thread ) {
_thread = new QThread ( ) ;
_worker = new TaskQueueWorker ( this ) ;
_worker - > moveToThread ( _thread ) ;
connect ( this , SIGNAL ( taskAdded ( ) ) , _worker , SLOT ( onTaskAdded ( ) ) ) ;
connect ( _worker , SIGNAL ( taskProcessed ( ) ) , this , SLOT ( onTaskProcessed ( ) ) ) ;
_thread - > start ( ) ;
}
if ( _stopTimer ) _stopTimer - > stop ( ) ;
emit taskAdded ( ) ;
return task - > id ( ) ;
}
void TaskQueue : : cancelTask ( TaskId id ) {
QMutexLocker lock ( & _tasksToProcessMutex ) ;
for ( int32 i = 0 , l = _tasksToProcess . size ( ) ; i < l ; + + i ) {
if ( _tasksToProcess . at ( i ) - > id ( ) = = id ) {
_tasksToProcess . removeAt ( i ) ;
break ;
}
}
}
void TaskQueue : : onTaskProcessed ( ) {
do {
TaskPtr task ;
{
QMutexLocker lock ( & _tasksToFinishMutex ) ;
if ( _tasksToFinish . isEmpty ( ) ) break ;
task = _tasksToFinish . front ( ) ;
_tasksToFinish . pop_front ( ) ;
}
task - > finish ( ) ;
} while ( true ) ;
if ( _stopTimer ) {
QMutexLocker lock ( & _tasksToProcessMutex ) ;
if ( _tasksToProcess . isEmpty ( ) ) {
_stopTimer - > start ( ) ;
}
}
}
void TaskQueue : : stop ( ) {
if ( _thread ) {
_thread - > requestInterruption ( ) ;
_thread - > quit ( ) ;
_thread - > wait ( ) ;
delete _worker ;
delete _thread ;
_worker = 0 ;
_thread = 0 ;
}
_tasksToProcess . clear ( ) ;
_tasksToFinish . clear ( ) ;
}
TaskQueue : : ~ TaskQueue ( ) {
stop ( ) ;
delete _stopTimer ;
}
void TaskQueueWorker : : onTaskAdded ( ) {
if ( _inTaskAdded ) return ;
_inTaskAdded = true ;
bool someTasksLeft = false ;
do {
TaskPtr task ;
{
QMutexLocker lock ( & _queue - > _tasksToProcessMutex ) ;
if ( ! _queue - > _tasksToProcess . isEmpty ( ) ) {
task = _queue - > _tasksToProcess . front ( ) ;
}
}
if ( task ) {
task - > process ( ) ;
bool emitTaskProcessed = false ;
{
QMutexLocker lockToProcess ( & _queue - > _tasksToProcessMutex ) ;
if ( ! _queue - > _tasksToProcess . isEmpty ( ) & & _queue - > _tasksToProcess . front ( ) = = task ) {
_queue - > _tasksToProcess . pop_front ( ) ;
someTasksLeft = ! _queue - > _tasksToProcess . isEmpty ( ) ;
QMutexLocker lockToFinish ( & _queue - > _tasksToFinishMutex ) ;
emitTaskProcessed = _queue - > _tasksToFinish . isEmpty ( ) ;
_queue - > _tasksToFinish . push_back ( task ) ;
}
}
if ( emitTaskProcessed ) {
emit taskProcessed ( ) ;
}
}
QCoreApplication : : processEvents ( ) ;
} while ( someTasksLeft & & ! thread ( ) - > isInterruptionRequested ( ) ) ;
_inTaskAdded = false ;
}