diff --git a/Telegram/SourceFiles/art/iconbig128.png b/Telegram/SourceFiles/art/iconbig128.png
new file mode 100644
index 0000000000..32b44a5eae
Binary files /dev/null and b/Telegram/SourceFiles/art/iconbig128.png differ
diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp
index d89bd59ead..bcb433e63b 100644
--- a/Telegram/SourceFiles/history.cpp
+++ b/Telegram/SourceFiles/history.cpp
@@ -1755,7 +1755,7 @@ void History::clear(bool leaveItems) {
 		_overview[i].clear();
 		_overviewIds[i].clear();
 	}
-	if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer);
+	if (App::wnd() && !App::quiting()) App::wnd()->mediaOverviewUpdated(peer);
 	for (Parent::const_iterator i = cbegin(), e = cend(); i != e; ++i) {
 		if (leaveItems) {
 			(*i)->clear(true);
diff --git a/Telegram/SourceFiles/mtproto/mtp.h b/Telegram/SourceFiles/mtproto/mtp.h
index 4093798631..0ac3edef95 100644
--- a/Telegram/SourceFiles/mtproto/mtp.h
+++ b/Telegram/SourceFiles/mtproto/mtp.h
@@ -95,7 +95,10 @@ namespace MTP {
 	void initdc(int32 dc);
 	template <typename TRequest>
 	inline mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), int32 dc = 0, uint64 msCanWait = 0, mtpRequestId after = 0) {
-		return _mtp_internal::getSession(dc)->send(request, callbacks, msCanWait, _mtp_internal::getLayer(), !dc, after);
+		MTProtoSessionPtr session = _mtp_internal::getSession(dc);
+		if (!session) return 0;
+		
+		return session->send(request, callbacks, msCanWait, _mtp_internal::getLayer(), !dc, after);
 	}
 	template <typename TRequest>
 	inline mtpRequestId send(const TRequest &request, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail = RPCFailHandlerPtr(), int32 dc = 0, uint64 msCanWait = 0, mtpRequestId after = 0) {
diff --git a/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp b/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp
index 28bd479f62..75dca6ed94 100644
--- a/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp
+++ b/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp
@@ -46,7 +46,7 @@ namespace {
 mtpFileLoader::mtpFileLoader(int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size) : prev(0), next(0),
 priority(0), inQueue(false), complete(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
 dc(dc), locationType(0), volume(volume), local(local), secret(secret),
-id(0), access(0), size(size), type(MTP_storage_fileUnknown()) {
+id(0), access(0), fileIsOpen(false), size(size), type(MTP_storage_fileUnknown()) {
 	LoaderQueues::iterator i = queues.find(dc);
 	if (i == queues.cend()) {
 		i = queues.insert(dc, mtpFileLoaderQueue());
@@ -57,7 +57,7 @@ id(0), access(0), size(size), type(MTP_storage_fileUnknown()) {
 mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size) : prev(0), next(0),
 priority(0), inQueue(false), complete(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
 dc(dc), locationType(locType),
-id(id), access(access), file(to), duplicateInData(false), size(size), type(MTP_storage_fileUnknown()) {
+id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(false), size(size), type(MTP_storage_fileUnknown()) {
 	LoaderQueues::iterator i = queues.find(MTP::dld[0] + dc);
 	if (i == queues.cend()) {
 		i = queues.insert(MTP::dld[0] + dc, mtpFileLoaderQueue());
@@ -68,7 +68,7 @@ id(id), access(access), file(to), duplicateInData(false), size(size), type(MTP_s
 mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size, bool todata) : prev(0), next(0),
 priority(0), inQueue(false), complete(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
 dc(dc), locationType(locType),
-id(id), access(access), file(to), duplicateInData(todata), size(size), type(MTP_storage_fileUnknown()) {
+id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(todata), size(size), type(MTP_storage_fileUnknown()) {
 	LoaderQueues::iterator i = queues.find(MTP::dld[0] + dc);
 	if (i == queues.cend()) {
 		i = queues.insert(MTP::dld[0] + dc, mtpFileLoaderQueue());
@@ -77,7 +77,7 @@ id(id), access(access), file(to), duplicateInData(todata), size(size), type(MTP_
 }
 
 QString mtpFileLoader::fileName() const {
-	return file.fileName();
+	return fname;
 }
 
 bool mtpFileLoader::done() const {
@@ -99,16 +99,16 @@ float64 mtpFileLoader::currentProgress() const {
 }
 
 int32 mtpFileLoader::currentOffset(bool includeSkipped) const {
-	return (file.isOpen() ? file.size() : data.size()) - (includeSkipped ? 0 : skippedBytes);
+	return (fileIsOpen ? file.size() : data.size()) - (includeSkipped ? 0 : skippedBytes);
 }
 
 int32 mtpFileLoader::fullSize() const {
 	return size;
 }
 
-void mtpFileLoader::setFileName(const QString &fname) {
-	if (duplicateInData && file.fileName().isEmpty()) {
-		file.setFileName(fname);
+void mtpFileLoader::setFileName(const QString &fileName) {
+	if (duplicateInData && fname.isEmpty()) {
+		file.setFileName(fname = fileName);
 	}
 }
 
@@ -132,13 +132,14 @@ void mtpFileLoader::finishFail() {
 	cancelRequests();
 	type = MTP_storage_fileUnknown();
 	complete = true;
-	if (file.isOpen()) {
+	if (fileIsOpen) {
 		file.close();
+		fileIsOpen = false;
 		file.remove();
 	}
 	data = QByteArray();
 	emit failed(this, started);
-	file.setFileName(QString());
+	file.setFileName(fname = QString());
 	loadNext();
 }
 
@@ -198,7 +199,7 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
 	const MTPDupload_file &d(result.c_upload_file());
 	const string &bytes(d.vbytes.c_string().v);
 	if (bytes.size()) {
-		if (file.isOpen()) {
+		if (fileIsOpen) {
 			int64 fsize = file.size();
 			if (offset < fsize) {
 				skippedBytes -= bytes.size();
@@ -230,8 +231,9 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
 		lastComplete = true;
 	}
 	if (requests.isEmpty() && (lastComplete || (size && nextRequestOffset >= size))) {
-		if (duplicateInData && !file.fileName().isEmpty()) {
-			if (!file.open(QIODevice::WriteOnly)) {
+		if (!fname.isEmpty() && duplicateInData) {
+			if (!fileIsOpen) fileIsOpen = file.open(QIODevice::WriteOnly);
+			if (!fileIsOpen) {
 				return finishFail();
 			}
 			if (file.write(data) != qint64(data.size())) {
@@ -240,8 +242,9 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
 		}
 		type = d.vtype;
 		complete = true;
-		if (file.isOpen()) {
+		if (fileIsOpen) {
 			file.close();
+			fileIsOpen = false;
 			psPostprocessFile(QFileInfo(file).absoluteFilePath());
 		}
 		removeFromQueue();
@@ -286,8 +289,9 @@ void mtpFileLoader::pause() {
 void mtpFileLoader::start(bool loadFirst, bool prior) {
 	if (complete) return;
 
-	if (!file.fileName().isEmpty() && !duplicateInData) {
-		if (!file.open(QIODevice::WriteOnly)) {
+	if (!fname.isEmpty() && !duplicateInData && !fileIsOpen) {
+		fileIsOpen = file.open(QIODevice::WriteOnly);
+		if (!fileIsOpen) {
 			finishFail();
 			return;
 		}
@@ -385,8 +389,9 @@ void mtpFileLoader::cancel() {
 	cancelRequests();
 	type = MTP_storage_fileUnknown();
 	complete = true;
-	if (file.isOpen()) {
+	if (fileIsOpen) {
 		file.close();
+		fileIsOpen = false;
 		file.remove();
 	}
 	data = QByteArray();
diff --git a/Telegram/SourceFiles/mtproto/mtpFileLoader.h b/Telegram/SourceFiles/mtproto/mtpFileLoader.h
index 287fd67f99..99781f6946 100644
--- a/Telegram/SourceFiles/mtproto/mtpFileLoader.h
+++ b/Telegram/SourceFiles/mtproto/mtpFileLoader.h
@@ -89,6 +89,8 @@ private:
 	uint64 id; // for other locations
 	uint64 access;
 	QFile file;
+	QString fname;
+	bool fileIsOpen;
 	bool duplicateInData;
 
 	QByteArray data;
diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp
index 4deb12b3b4..76d1ab4703 100644
--- a/Telegram/SourceFiles/overviewwidget.cpp
+++ b/Telegram/SourceFiles/overviewwidget.cpp
@@ -553,10 +553,14 @@ QPixmap OverviewInner::genPix(PhotoData *photo, int32 size) {
 	if (!photo->full->loaded() && !photo->medium->loaded()) {
 		img = imageBlur(img);
 	}
-	if (img.width() > img.height()) {
-        img = img.scaled(img.width() * size / img.height(), size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
+	if (img.width() == img.height()) {
+		if (img.width() != size) {
+			img = img.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
+		}
+	} else if (img.width() > img.height()) {
+        img = img.copy((img.width() - img.height()) / 2, 0, img.height(), img.height()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
 	} else {
-        img = img.scaled(size, img.height() * size / img.width(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
+        img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
 	}
 	img.setDevicePixelRatio(cRetinaFactor());
 	photo->forget();
@@ -625,26 +629,13 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
 						it->vsize = _vsize;
 						it->pix = genPix(photo, _vsize);
 					}
-					QPixmap &pix(it->pix);
 					QPoint pos(int32(i * w + st::overviewPhotoSkip), _addToY + row * (_vsize + st::overviewPhotoSkip) + st::overviewPhotoSkip);
-					int32 w = pix.width(), h = pix.height(), size;
-					if (w == h) {
-						p.drawPixmap(pos, pix);
-						size = w;
-					} else if (w > h) {
-						p.drawPixmap(pos, pix, QRect((w - h) / 2, 0, h, h));
-						size = h;
-					} else {
-						p.drawPixmap(pos, pix, QRect(0, (h - w) / 2, w, w));
-						size = w;
-					}
-					size /= cIntRetinaFactor();
-
+					p.drawPixmap(pos, it->pix);
 					if (!quality) {
 						uint64 dt = itemAnimations().animate(item, getms());
 						int32 cnt = int32(st::photoLoaderCnt), period = int32(st::photoLoaderPeriod), t = dt % period, delta = int32(st::photoLoaderDelta);
 
-						int32 x = pos.x() + (size - st::overviewLoader.width()) / 2, y = pos.y() + (size - st::overviewLoader.height()) / 2;
+						int32 x = pos.x() + (_vsize - st::overviewLoader.width()) / 2, y = pos.y() + (_vsize - st::overviewLoader.height()) / 2;
 						p.fillRect(x, y, st::overviewLoader.width(), st::overviewLoader.height(), st::photoLoaderBg->b);
 						x += (st::overviewLoader.width() - cnt * st::overviewLoaderPoint.width() - (cnt - 1) * st::overviewLoaderSkip) / 2;
 						y += (st::overviewLoader.height() - st::overviewLoaderPoint.height()) / 2;
@@ -671,7 +662,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
 						}
 					}
 					if (sel == FullItemSel) {
-						p.fillRect(QRect(pos.x(), pos.y(), size, size), st::msgInSelectOverlay->b);
+						p.fillRect(QRect(pos.x(), pos.y(), _vsize, _vsize), st::msgInSelectOverlay->b);
 					}
 				} break;
 				}
diff --git a/Telegram/SourceFiles/pspecific_linux.cpp b/Telegram/SourceFiles/pspecific_linux.cpp
index 09d14813e1..3da05918ca 100644
--- a/Telegram/SourceFiles/pspecific_linux.cpp
+++ b/Telegram/SourceFiles/pspecific_linux.cpp
@@ -50,7 +50,7 @@ namespace {
 };
 
 PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent),
-posInited(false), trayIcon(0), trayIconMenu(0), icon256(qsl(":/gui/art/iconround256.png")) {
+posInited(false), trayIcon(0), trayIconMenu(0), icon256(qsl(":/gui/art/iconround256.png")), wndIcon(QPixmap::fromImage(icon256)) {
     connect(&psIdleTimer, SIGNAL(timeout()), this, SLOT(psIdleTimeout()));
     psIdleTimer.setSingleShot(false);
 }
@@ -115,6 +115,8 @@ void PsMainWindow::psUpdateWorkmode() {
 }
 
 void PsMainWindow::psUpdateCounter() {
+	setWindowIcon(myIcon);
+
 	int32 counter = App::histories().unreadFull;
 
     setWindowTitle((counter > 0) ? qsl("Telegram (%1)").arg(counter) : qsl("Telegram"));
diff --git a/Telegram/SourceFiles/pspecific_linux.h b/Telegram/SourceFiles/pspecific_linux.h
index 7fba2bb320..7dcd62e2e1 100644
--- a/Telegram/SourceFiles/pspecific_linux.h
+++ b/Telegram/SourceFiles/pspecific_linux.h
@@ -88,6 +88,7 @@ protected:
     QSystemTrayIcon *trayIcon;
     QMenu *trayIconMenu;
     QImage icon256;
+	QIcon wndIcon;
 
 	virtual void setupTrayIcon() = 0;
 	virtual QImage iconWithCounter(int size, int count, style::color bg, bool smallIcon) = 0;
diff --git a/Telegram/SourceFiles/pspecific_mac.cpp b/Telegram/SourceFiles/pspecific_mac.cpp
index b76e618c4d..f9565882cd 100644
--- a/Telegram/SourceFiles/pspecific_mac.cpp
+++ b/Telegram/SourceFiles/pspecific_mac.cpp
@@ -64,7 +64,7 @@ void MacPrivate::notifyReplied(unsigned long long peer, const char *str) {
 }
 
 PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent),
-posInited(false), trayIcon(0), trayIconMenu(0), icon256(qsl(":/gui/art/iconround256.png")) {
+posInited(false), trayIcon(0), trayIconMenu(0), icon256(qsl(":/gui/art/iconround256.png")), wndIcon(QPixmap(qsl(":/gui/art/iconbig128.png"))) {
 	QImage tray(qsl(":/gui/art/osxtray.png"));
 	trayImg = tray.copy(0, cRetina() ? 0 : tray.width() / 2, tray.width() / (cRetina() ? 2 : 4), tray.width() / (cRetina() ? 2 : 4));
 	trayImgSel = tray.copy(tray.width() / (cRetina() ? 2 : 4), cRetina() ? 0 : tray.width() / 2, tray.width() / (cRetina() ? 2 : 4), tray.width() / (cRetina() ? 2 : 4));
@@ -141,6 +141,7 @@ void PsMainWindow::psUpdateWorkmode() {
 		}
 		trayIcon = 0;
 	}
+	setWindowIcon(wndIcon);
 }
 
 void _placeCounter(QImage &img, int size, int count, style::color bg, style::color color) {
@@ -182,6 +183,7 @@ void PsMainWindow::psUpdateCounter() {
 	int32 counter = App::histories().unreadFull;
 
     setWindowTitle((counter > 0) ? qsl("Telegram (%1)").arg(counter) : qsl("Telegram"));
+	setWindowIcon(wndIcon);
 
     QString cnt = (counter < 1000) ? QString("%1").arg(counter) : QString("..%1").arg(counter % 100, 2, 10, QChar('0'));
     _private.setWindowBadge(counter ? cnt : QString());
diff --git a/Telegram/SourceFiles/pspecific_mac.h b/Telegram/SourceFiles/pspecific_mac.h
index f057159841..cb8e971a01 100644
--- a/Telegram/SourceFiles/pspecific_mac.h
+++ b/Telegram/SourceFiles/pspecific_mac.h
@@ -99,6 +99,7 @@ protected:
     QSystemTrayIcon *trayIcon;
     QMenu *trayIconMenu;
     QImage icon256;
+	QIcon wndIcon;
 
 	QImage trayImg, trayImgSel;
 
diff --git a/Telegram/SourceFiles/pspecific_wnd.cpp b/Telegram/SourceFiles/pspecific_wnd.cpp
index 57e6458e8c..0f8fa9ecaf 100644
--- a/Telegram/SourceFiles/pspecific_wnd.cpp
+++ b/Telegram/SourceFiles/pspecific_wnd.cpp
@@ -860,7 +860,7 @@ namespace {
 
 };
 
-PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent), ps_hWnd(0), ps_menu(0), icon256(qsl(":/gui/art/iconround256.png")),
+PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent), ps_hWnd(0), ps_menu(0), icon256(qsl(":/gui/art/iconround256.png")), wndIcon(QPixmap::fromImage(icon256)),
 	ps_iconBig(0), ps_iconSmall(0), ps_iconOverlay(0), trayIcon(0), trayIconMenu(0), posInited(false), ps_tbHider_hWnd(createTaskbarHider()), psIdle(false) {
 	tbCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated");
 	connect(&psIdleTimer, SIGNAL(timeout()), this, SLOT(psIdleTimeout()));
diff --git a/Telegram/SourceFiles/pspecific_wnd.h b/Telegram/SourceFiles/pspecific_wnd.h
index ecfcaf50b6..94b4f4f155 100644
--- a/Telegram/SourceFiles/pspecific_wnd.h
+++ b/Telegram/SourceFiles/pspecific_wnd.h
@@ -87,6 +87,7 @@ protected:
 	QSystemTrayIcon *trayIcon;
 	ContextMenu *trayIconMenu;
 	QImage icon256;
+	QIcon wndIcon;
 
 	virtual void setupTrayIcon() = 0;
 	virtual QImage iconWithCounter(int size, int count, style::color bg, bool smallIcon) = 0;
diff --git a/Telegram/SourceFiles/telegram.qrc b/Telegram/SourceFiles/telegram.qrc
index 93525b0449..8bc2e1f1b2 100644
--- a/Telegram/SourceFiles/telegram.qrc
+++ b/Telegram/SourceFiles/telegram.qrc
@@ -18,6 +18,7 @@
         <file>art/emoji_200x.png</file>
         <file>art/blank.gif</file>
         <file>art/iconround256.png</file>
+		<file>art/iconbig128.png</file>
         <file>art/fonts/DejaVuSans.ttf</file>
 		<file>art/osxtray.png</file>
     </qresource>
diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp
index 9fd6013358..fb78629c08 100644
--- a/Telegram/SourceFiles/window.cpp
+++ b/Telegram/SourceFiles/window.cpp
@@ -337,7 +337,7 @@ NotifyWindow::~NotifyWindow() {
 
 Window::Window(QWidget *parent) : PsMainWindow(parent),
 intro(0), main(0), settings(0), layerBG(0), _topWidget(0),
-_connecting(0), _tempDeleter(0), _tempDeleterThread(0), myIcon(QPixmap::fromImage(icon256)), dragging(false), _inactivePress(false), _mediaView(0) {
+_connecting(0), _tempDeleter(0), _tempDeleterThread(0), dragging(false), _inactivePress(false), _mediaView(0) {
 
 	icon16 = icon256.scaledToWidth(16, Qt::SmoothTransformation);
 	icon32 = icon256.scaledToWidth(32, Qt::SmoothTransformation);
@@ -380,7 +380,7 @@ void Window::onInactiveTimer() {
 
 void Window::init() {
 	psInitFrameless();
-	setWindowIcon(myIcon);
+	setWindowIcon(wndIcon);
 
 	App::app()->installEventFilter(this);
     connect(windowHandle(), SIGNAL(activeChanged()), this, SLOT(checkHistoryActivation()));
@@ -875,7 +875,6 @@ void Window::noTopWidget(QWidget *w) {
 void Window::showFromTray(QSystemTrayIcon::ActivationReason reason) {
 	if (reason != QSystemTrayIcon::Context) {
         activate();
-		setWindowIcon(myIcon);
 		psUpdateCounter();
 		if (App::main()) App::main()->setOnline(windowState());
 		QTimer::singleShot(1, this, SLOT(updateTrayMenu()));
diff --git a/Telegram/SourceFiles/window.h b/Telegram/SourceFiles/window.h
index 18bcb44a62..15b2ea0b56 100644
--- a/Telegram/SourceFiles/window.h
+++ b/Telegram/SourceFiles/window.h
@@ -281,8 +281,6 @@ private:
 
 	void clearWidgets();
 
-	QIcon myIcon;
-
 	bool dragging;
 	QPoint dragStart;
 
diff --git a/Telegram/_qt_5_3_1_patch/qtbase/src/plugins/platforms/cocoa/qcocoawindow.mm b/Telegram/_qt_5_3_1_patch/qtbase/src/plugins/platforms/cocoa/qcocoawindow.mm
index f3033316f3..159395aa2a 100644
--- a/Telegram/_qt_5_3_1_patch/qtbase/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/Telegram/_qt_5_3_1_patch/qtbase/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -167,7 +167,7 @@ static bool isMouseEvent(NSEvent *ev)
     if (!self.window.delegate)
         return; // Already detached, pending NSAppKitDefined event
 
-    if (pw && pw->frameStrutEventsEnabled() && pw->m_synchedWindowState != Qt::WindowMinimized && isMouseEvent(theEvent)) {
+    if (pw && pw->frameStrutEventsEnabled() && pw->m_synchedWindowState != Qt::WindowMinimized && pw->m_isExposed && isMouseEvent(theEvent)) {
         NSPoint loc = [theEvent locationInWindow];
         NSRect windowFrame = [self.window legacyConvertRectFromScreen:[self.window frame]];
         NSRect contentFrame = [[self.window contentView] frame];
@@ -903,6 +903,14 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath)
     [m_nsWindow setRepresentedFilename: fi.exists() ? QCFString::toNSString(filePath) : @""];
 }
 
+qreal _win_devicePixelRatio() {
+	qreal result = 1.0;
+	foreach (QScreen *screen, QGuiApplication::screens()) {
+		result = qMax(result, screen->devicePixelRatio());
+	}
+	return result;
+}
+
 void QCocoaWindow::setWindowIcon(const QIcon &icon)
 {
     QCocoaAutoReleasePool pool;
@@ -918,7 +926,8 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon)
     if (icon.isNull()) {
         [iconButton setImage:nil];
     } else {
-        QPixmap pixmap = icon.pixmap(QSize(22, 22));
+		CGFloat hgt = 16. * _win_devicePixelRatio();
+        QPixmap pixmap = icon.pixmap(QSize(hgt, hgt));
         NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(pixmap));
         [iconButton setImage:image];
         [image release];
diff --git a/Telegram/_qt_5_3_1_patch/qtmultimedia/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm b/Telegram/_qt_5_3_1_patch/qtmultimedia/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm
new file mode 100644
index 0000000000..1b7b863f99
--- /dev/null
+++ b/Telegram/_qt_5_3_1_patch/qtmultimedia/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm
@@ -0,0 +1,851 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "avfmediaplayersession.h"
+#include "avfmediaplayerservice.h"
+#include "avfvideooutput.h"
+
+#import <AVFoundation/AVFoundation.h>
+
+QT_USE_NAMESPACE
+
+//AVAsset Keys
+static NSString* const AVF_TRACKS_KEY       = @"tracks";
+static NSString* const AVF_PLAYABLE_KEY     = @"playable";
+
+//AVPlayerItem keys
+static NSString* const AVF_STATUS_KEY       = @"status";
+
+//AVPlayer keys
+static NSString* const AVF_RATE_KEY         = @"rate";
+static NSString* const AVF_CURRENT_ITEM_KEY = @"currentItem";
+
+static void *AVFMediaPlayerSessionObserverRateObservationContext = &AVFMediaPlayerSessionObserverRateObservationContext;
+static void *AVFMediaPlayerSessionObserverStatusObservationContext = &AVFMediaPlayerSessionObserverStatusObservationContext;
+static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMediaPlayerSessionObserverCurrentItemObservationContext;
+
+@interface AVFMediaPlayerSessionObserver : NSObject
+{
+@private
+    AVFMediaPlayerSession *m_session;
+    AVPlayer *m_player;
+    AVPlayerItem *m_playerItem;
+    AVPlayerLayer *m_playerLayer;
+    NSURL *m_URL;
+    bool m_audioAvailable;
+    bool m_videoAvailable;
+}
+
+@property (readonly, getter=player) AVPlayer* m_player;
+@property (readonly, getter=playerItem) AVPlayerItem* m_playerItem;
+@property (readonly, getter=playerLayer) AVPlayerLayer* m_playerLayer;
+@property (readonly, getter=audioAvailable) bool m_audioAvailable;
+@property (readonly, getter=videoAvailable) bool m_videoAvailable;
+@property (readonly, getter=session) AVFMediaPlayerSession* m_session;
+
+- (AVFMediaPlayerSessionObserver *) initWithMediaPlayerSession:(AVFMediaPlayerSession *)session;
+- (void) setURL:(NSURL *)url;
+- (void) unloadMedia;
+- (void) prepareToPlayAsset:(AVURLAsset *)asset withKeys:(NSArray *)requestedKeys;
+- (void) assetFailedToPrepareForPlayback:(NSError *)error;
+- (void) playerItemDidReachEnd:(NSNotification *)notification;
+- (void) playerItemTimeJumped:(NSNotification *)notification;
+- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
+                         change:(NSDictionary *)change context:(void *)context;
+- (void) detatchSession;
+- (void) dealloc;
+@end
+
+@implementation AVFMediaPlayerSessionObserver
+
+@synthesize m_player, m_playerItem, m_playerLayer, m_audioAvailable, m_videoAvailable, m_session;
+
+- (AVFMediaPlayerSessionObserver *) initWithMediaPlayerSession:(AVFMediaPlayerSession *)session
+{
+    if (!(self = [super init]))
+        return nil;
+
+    self->m_session = session;
+    return self;
+}
+
+- (void) setURL:(NSURL *)url
+{
+    if (m_URL != url)
+    {
+        [m_URL release];
+        m_URL = [url copy];
+
+        //Create an asset for inspection of a resource referenced by a given URL.
+        //Load the values for the asset keys "tracks", "playable".
+
+        AVURLAsset *asset = [AVURLAsset URLAssetWithURL:m_URL options:nil];
+        NSArray *requestedKeys = [NSArray arrayWithObjects:AVF_TRACKS_KEY, AVF_PLAYABLE_KEY, nil];
+
+        // Tells the asset to load the values of any of the specified keys that are not already loaded.
+        [asset loadValuesAsynchronouslyForKeys:requestedKeys completionHandler:
+         ^{
+             dispatch_async( dispatch_get_main_queue(),
+                           ^{
+                                [self prepareToPlayAsset:asset withKeys:requestedKeys];
+                            });
+         }];
+    }
+}
+
+- (void) unloadMedia
+{
+    if (m_player)
+        [m_player setRate:0.0];
+    if (m_playerItem) {
+        [m_playerItem removeObserver:self forKeyPath:AVF_STATUS_KEY];
+
+        [[NSNotificationCenter defaultCenter] removeObserver:self
+                                                    name:AVPlayerItemDidPlayToEndTimeNotification
+                                                  object:m_playerItem];
+        [[NSNotificationCenter defaultCenter] removeObserver:self
+                                                    name:AVPlayerItemTimeJumpedNotification
+                                                    object:m_playerItem];
+        m_playerItem = 0;
+    }
+}
+
+- (void) prepareToPlayAsset:(AVURLAsset *)asset
+                   withKeys:(NSArray *)requestedKeys
+{
+    //Make sure that the value of each key has loaded successfully.
+    for (NSString *thisKey in requestedKeys)
+    {
+        NSError *error = nil;
+        AVKeyValueStatus keyStatus = [asset statusOfValueForKey:thisKey error:&error];
+#ifdef QT_DEBUG_AVF
+        qDebug() << Q_FUNC_INFO << [thisKey UTF8String] << " status: " << keyStatus;
+#endif
+        if (keyStatus == AVKeyValueStatusFailed)
+        {
+            [self assetFailedToPrepareForPlayback:error];
+            return;
+        }
+    }
+
+    //Use the AVAsset playable property to detect whether the asset can be played.
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO << "isPlayable: " << [asset isPlayable];
+#endif
+    if (!asset.playable)
+    {
+        //Generate an error describing the failure.
+        NSString *localizedDescription = NSLocalizedString(@"Item cannot be played", @"Item cannot be played description");
+        NSString *localizedFailureReason = NSLocalizedString(@"The assets tracks were loaded, but could not be made playable.", @"Item cannot be played failure reason");
+        NSDictionary *errorDict = [NSDictionary dictionaryWithObjectsAndKeys:
+                localizedDescription, NSLocalizedDescriptionKey,
+                localizedFailureReason, NSLocalizedFailureReasonErrorKey,
+                nil];
+        NSError *assetCannotBePlayedError = [NSError errorWithDomain:@"StitchedStreamPlayer" code:0 userInfo:errorDict];
+
+        [self assetFailedToPrepareForPlayback:assetCannotBePlayedError];
+
+        return;
+    }
+
+    m_audioAvailable = false;
+    m_videoAvailable = false;
+
+    //Check each track of asset for audio and video content
+    NSArray *tracks = [asset tracks];
+    for (AVAssetTrack *track in tracks) {
+        if ([track hasMediaCharacteristic:AVMediaCharacteristicAudible])
+            m_audioAvailable = true;
+        if ([track hasMediaCharacteristic:AVMediaCharacteristicVisual])
+            m_videoAvailable = true;
+    }
+
+    //At this point we're ready to set up for playback of the asset.
+    //Stop observing our prior AVPlayerItem, if we have one.
+    if (m_playerItem)
+    {
+        //Remove existing player item key value observers and notifications.
+        [self unloadMedia];
+    }
+
+    //Create a new instance of AVPlayerItem from the now successfully loaded AVAsset.
+    m_playerItem = [AVPlayerItem playerItemWithAsset:asset];
+
+    //Observe the player item "status" key to determine when it is ready to play.
+    [m_playerItem addObserver:self
+                   forKeyPath:AVF_STATUS_KEY
+                      options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
+                      context:AVFMediaPlayerSessionObserverStatusObservationContext];
+
+    //When the player item has played to its end time we'll toggle
+    //the movie controller Pause button to be the Play button
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(playerItemDidReachEnd:)
+                                                 name:AVPlayerItemDidPlayToEndTimeNotification
+                                               object:m_playerItem];
+
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(playerItemTimeJumped:)
+                                                 name:AVPlayerItemTimeJumpedNotification
+                                               object:m_playerItem];
+
+
+    //Clean up old player if we have one
+    if (m_player) {
+        [m_player setRate:0.0];
+        [m_player removeObserver:self forKeyPath:AVF_CURRENT_ITEM_KEY];
+        [m_player removeObserver:self forKeyPath:AVF_RATE_KEY];
+        [m_player release];
+        m_player = 0;
+
+        if (m_playerLayer) {
+            [m_playerLayer release];
+            m_playerLayer = 0; //Will have been released
+        }
+    }
+
+    //Get a new AVPlayer initialized to play the specified player item.
+    m_player = [AVPlayer playerWithPlayerItem:m_playerItem];
+    [m_player retain];
+
+#if defined(Q_OS_OSX)
+    //Set the initial volume on new player object
+    if (self.session)
+        m_player.volume = m_session->volume() / 100.0f;
+#endif
+
+    //Create a new player layer if we don't have one already
+    if (!m_playerLayer)
+    {
+        m_playerLayer = [AVPlayerLayer playerLayerWithPlayer:m_player];
+        [m_playerLayer retain];
+        m_playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
+
+        //Get the native size of the new item, and reset the bounds of the player layer
+        AVAsset *asset = m_playerItem.asset;
+        if (asset) {
+            NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
+            if ([tracks count]) {
+                AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
+                m_playerLayer.anchorPoint = CGPointMake(0.0f, 0.0f);
+                m_playerLayer.bounds = CGRectMake(0.0f, 0.0f, videoTrack.naturalSize.width, videoTrack.naturalSize.height);
+            }
+        }
+
+    }
+
+    //Observe the AVPlayer "currentItem" property to find out when any
+    //AVPlayer replaceCurrentItemWithPlayerItem: replacement will/did
+    //occur.
+    [m_player addObserver:self
+                          forKeyPath:AVF_CURRENT_ITEM_KEY
+                          options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
+                          context:AVFMediaPlayerSessionObserverCurrentItemObservationContext];
+
+    //Observe the AVPlayer "rate" property to update the scrubber control.
+    [m_player addObserver:self
+                          forKeyPath:AVF_RATE_KEY
+                          options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
+                          context:AVFMediaPlayerSessionObserverRateObservationContext];
+
+}
+
+-(void) assetFailedToPrepareForPlayback:(NSError *)error
+{
+    Q_UNUSED(error)
+    QMetaObject::invokeMethod(m_session, "processMediaLoadError", Qt::AutoConnection);
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO;
+    qDebug() << [[error localizedDescription] UTF8String];
+    qDebug() << [[error localizedFailureReason] UTF8String];
+    qDebug() << [[error localizedRecoverySuggestion] UTF8String];
+#endif
+}
+
+- (void) playerItemDidReachEnd:(NSNotification *)notification
+{
+    Q_UNUSED(notification)
+    if (self.session)
+        QMetaObject::invokeMethod(m_session, "processEOS", Qt::AutoConnection);
+}
+
+- (void) playerItemTimeJumped:(NSNotification *)notification
+{
+    Q_UNUSED(notification)
+    if (self.session)
+        QMetaObject::invokeMethod(m_session, "processPositionChange", Qt::AutoConnection);
+}
+
+- (void) observeValueForKeyPath:(NSString*) path
+                       ofObject:(id)object
+                         change:(NSDictionary*)change
+                        context:(void*)context
+{
+    //AVPlayerItem "status" property value observer.
+    if (context == AVFMediaPlayerSessionObserverStatusObservationContext)
+    {
+		AVPlayerStatus status = (AVPlayerStatus)[[change objectForKey:NSKeyValueChangeNewKey] integerValue];
+        switch (status)
+        {
+            //Indicates that the status of the player is not yet known because
+            //it has not tried to load new media resources for playback
+            case AVPlayerStatusUnknown:
+            {
+                //QMetaObject::invokeMethod(m_session, "processLoadStateChange", Qt::AutoConnection);
+            }
+            break;
+
+            case AVPlayerStatusReadyToPlay:
+            {
+                //Once the AVPlayerItem becomes ready to play, i.e.
+                //[playerItem status] == AVPlayerItemStatusReadyToPlay,
+                //its duration can be fetched from the item.
+                if (self.session)
+                    QMetaObject::invokeMethod(m_session, "processLoadStateChange", Qt::AutoConnection);
+            }
+            break;
+
+            case AVPlayerStatusFailed:
+            {
+                AVPlayerItem *playerItem = (AVPlayerItem *)object;
+                [self assetFailedToPrepareForPlayback:playerItem.error];
+
+                if (self.session)
+                    QMetaObject::invokeMethod(m_session, "processLoadStateChange", Qt::AutoConnection);
+            }
+            break;
+        }
+    }
+    //AVPlayer "rate" property value observer.
+    else if (context == AVFMediaPlayerSessionObserverRateObservationContext)
+    {
+        //QMetaObject::invokeMethod(m_session, "setPlaybackRate",  Qt::AutoConnection, Q_ARG(qreal, [m_player rate]));
+    }
+    //AVPlayer "currentItem" property observer.
+    //Called when the AVPlayer replaceCurrentItemWithPlayerItem:
+    //replacement will/did occur.
+    else if (context == AVFMediaPlayerSessionObserverCurrentItemObservationContext)
+    {
+        AVPlayerItem *newPlayerItem = [change objectForKey:NSKeyValueChangeNewKey];
+        if (m_playerItem != newPlayerItem)
+        {
+            m_playerItem = newPlayerItem;
+
+            //Get the native size of the new item, and reset the bounds of the player layer
+            //AVAsset *asset = m_playerItem.asset;
+            AVAsset *asset = [m_playerItem asset];
+            if (asset) {
+                NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
+                if ([tracks count]) {
+                    AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
+                    m_playerLayer.anchorPoint = CGPointMake(0.0f, 0.0f);
+                    m_playerLayer.bounds = CGRectMake(0.0f, 0.0f, videoTrack.naturalSize.width, videoTrack.naturalSize.height);
+                }
+            }
+
+        }
+        if (self.session)
+            QMetaObject::invokeMethod(m_session, "processCurrentItemChanged", Qt::AutoConnection);
+    }
+    else
+    {
+        [super observeValueForKeyPath:path ofObject:object change:change context:context];
+    }
+}
+
+- (void) detatchSession
+{
+#ifdef QT_DEBUG_AVF
+        qDebug() << Q_FUNC_INFO;
+#endif
+        m_session = 0;
+}
+
+- (void) dealloc
+{
+#ifdef QT_DEBUG_AVF
+        qDebug() << Q_FUNC_INFO;
+#endif
+    [self unloadMedia];
+
+    if (m_player) {
+        [m_player removeObserver:self forKeyPath:AVF_CURRENT_ITEM_KEY];
+        [m_player removeObserver:self forKeyPath:AVF_RATE_KEY];
+        [m_player release];
+        m_player = 0;
+    }
+
+    if (m_playerLayer) {
+        [m_playerLayer release];
+        m_playerLayer = 0;
+    }
+
+    if (m_URL) {
+        [m_URL release];
+    }
+
+    [super dealloc];
+}
+
+@end
+
+AVFMediaPlayerSession::AVFMediaPlayerSession(AVFMediaPlayerService *service, QObject *parent)
+    : QObject(parent)
+    , m_service(service)
+    , m_videoOutput(0)
+    , m_state(QMediaPlayer::StoppedState)
+    , m_mediaStatus(QMediaPlayer::NoMedia)
+    , m_mediaStream(0)
+    , m_muted(false)
+    , m_tryingAsync(false)
+    , m_volume(100)
+    , m_rate(1.0)
+    , m_duration(0)
+    , m_videoAvailable(false)
+    , m_audioAvailable(false)
+{
+    m_observer = [[AVFMediaPlayerSessionObserver alloc] initWithMediaPlayerSession:this];
+}
+
+AVFMediaPlayerSession::~AVFMediaPlayerSession()
+{
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO;
+#endif
+    //Detatch the session from the sessionObserver (which could still be alive trying to communicate with this session).
+    [(AVFMediaPlayerSessionObserver*)m_observer detatchSession];
+    [(AVFMediaPlayerSessionObserver*)m_observer release];
+}
+
+void AVFMediaPlayerSession::setVideoOutput(AVFVideoOutput *output)
+{
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO << output;
+#endif
+
+    if (m_videoOutput == output)
+        return;
+
+    //Set the current output layer to null to stop rendering
+    if (m_videoOutput) {
+        m_videoOutput->setLayer(0);
+    }
+
+    m_videoOutput = output;
+
+    if (m_videoOutput && m_state != QMediaPlayer::StoppedState)
+        m_videoOutput->setLayer([(AVFMediaPlayerSessionObserver*)m_observer playerLayer]);
+}
+
+void *AVFMediaPlayerSession::currentAssetHandle()
+{
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO;
+#endif
+    AVAsset *currentAsset = [[(AVFMediaPlayerSessionObserver*)m_observer playerItem] asset];
+    return currentAsset;
+}
+
+QMediaPlayer::State AVFMediaPlayerSession::state() const
+{
+    return m_state;
+}
+
+QMediaPlayer::MediaStatus AVFMediaPlayerSession::mediaStatus() const
+{
+    return m_mediaStatus;
+}
+
+QMediaContent AVFMediaPlayerSession::media() const
+{
+    return m_resources;
+}
+
+const QIODevice *AVFMediaPlayerSession::mediaStream() const
+{
+    return m_mediaStream;
+}
+
+void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *stream)
+{
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO << content.canonicalUrl();
+#endif
+
+    m_resources = content;
+    m_mediaStream = stream;
+
+    QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus;
+
+    if (content.isNull() || content.canonicalUrl().isEmpty()) {
+        [(AVFMediaPlayerSessionObserver*)m_observer unloadMedia];
+        m_mediaStatus = QMediaPlayer::NoMedia;
+        if (m_state != QMediaPlayer::StoppedState)
+            Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState);
+
+        if (m_mediaStatus != oldMediaStatus)
+            Q_EMIT mediaStatusChanged(m_mediaStatus);
+        Q_EMIT positionChanged(position());
+        return;
+    } else {
+
+        m_mediaStatus = QMediaPlayer::LoadingMedia;
+        if (m_mediaStatus != oldMediaStatus)
+            Q_EMIT mediaStatusChanged(m_mediaStatus);
+    }
+    //Load AVURLAsset
+    //initialize asset using content's URL
+    NSString *urlString = [NSString stringWithUTF8String:content.canonicalUrl().toEncoded().constData()];
+    NSURL *url = [NSURL URLWithString:urlString];
+    [(AVFMediaPlayerSessionObserver*)m_observer setURL:url];
+}
+
+qint64 AVFMediaPlayerSession::position() const
+{
+    AVPlayerItem *playerItem = [(AVFMediaPlayerSessionObserver*)m_observer playerItem];
+
+    if (!playerItem)
+        return 0;
+
+    CMTime time = [playerItem currentTime];
+    return static_cast<quint64>(float(time.value) / float(time.timescale) * 1000.0f);
+}
+
+qint64 AVFMediaPlayerSession::duration() const
+{
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO;
+#endif
+    AVPlayerItem *playerItem = [(AVFMediaPlayerSessionObserver*)m_observer playerItem];
+
+    if (!playerItem)
+        return 0;
+
+    CMTime time = [playerItem duration];
+    return static_cast<quint64>(float(time.value) / float(time.timescale) * 1000.0f);
+}
+
+int AVFMediaPlayerSession::bufferStatus() const
+{
+    //BUG: bufferStatus may be relevant?
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO;
+#endif
+    return 100;
+}
+
+int AVFMediaPlayerSession::volume() const
+{
+    return m_volume;
+}
+
+bool AVFMediaPlayerSession::isMuted() const
+{
+    return m_muted;
+}
+
+bool AVFMediaPlayerSession::isAudioAvailable() const
+{
+    return [(AVFMediaPlayerSessionObserver*)m_observer audioAvailable];
+}
+
+bool AVFMediaPlayerSession::isVideoAvailable() const
+{
+    return [(AVFMediaPlayerSessionObserver*)m_observer videoAvailable];
+}
+
+bool AVFMediaPlayerSession::isSeekable() const
+{
+    return true;
+}
+
+QMediaTimeRange AVFMediaPlayerSession::availablePlaybackRanges() const
+{
+    AVPlayerItem *playerItem = [(AVFMediaPlayerSessionObserver*)m_observer playerItem];
+
+    if (playerItem) {
+        QMediaTimeRange timeRanges;
+
+        NSArray *ranges = [playerItem loadedTimeRanges];
+        for (NSValue *timeRange in ranges) {
+            CMTimeRange currentTimeRange = [timeRange CMTimeRangeValue];
+            qint64 startTime = qint64(float(currentTimeRange.start.value) / currentTimeRange.start.timescale * 1000.0);
+            timeRanges.addInterval(startTime, startTime + qint64(float(currentTimeRange.duration.value) / currentTimeRange.duration.timescale * 1000.0));
+        }
+        if (!timeRanges.isEmpty())
+            return timeRanges;
+    }
+    return QMediaTimeRange(0, duration());
+}
+
+qreal AVFMediaPlayerSession::playbackRate() const
+{
+    return m_rate;
+}
+
+void AVFMediaPlayerSession::setPlaybackRate(qreal rate)
+{
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO << rate;
+#endif
+
+    if (qFuzzyCompare(m_rate, rate))
+        return;
+
+    m_rate = rate;
+
+    AVPlayer *player = [(AVFMediaPlayerSessionObserver*)m_observer player];
+
+    if (player != 0 && m_state == QMediaPlayer::PlayingState) {
+        [player setRate:m_rate];
+    }
+}
+
+void AVFMediaPlayerSession::setPosition(qint64 pos)
+{
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO << pos;
+#endif
+
+    if ( !isSeekable() || pos == position())
+        return;
+
+    AVPlayerItem *playerItem = [(AVFMediaPlayerSessionObserver*)m_observer playerItem];
+
+    if (!playerItem)
+        return;
+
+    if (duration() > 0)
+        pos = qMin(pos, duration());
+
+    CMTime newTime = [playerItem currentTime];
+    newTime.value = (pos / 1000.0f) * newTime.timescale;
+    [playerItem seekToTime:newTime];
+
+    //reset the EndOfMedia status position is changed after playback is finished
+    if (m_mediaStatus == QMediaPlayer::EndOfMedia)
+        processLoadStateChange();
+}
+
+void AVFMediaPlayerSession::play()
+{
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO << "currently: " << m_state;
+#endif
+
+    if (m_state == QMediaPlayer::PlayingState)
+        return;
+
+    m_state = QMediaPlayer::PlayingState;
+
+    if (m_videoOutput) {
+        m_videoOutput->setLayer([(AVFMediaPlayerSessionObserver*)m_observer playerLayer]);
+    }
+
+    //reset the EndOfMedia status if the same file is played again
+    if (m_mediaStatus == QMediaPlayer::EndOfMedia) {
+        setPosition(0);
+        processLoadStateChange();
+    }
+
+    if (m_mediaStatus == QMediaPlayer::LoadedMedia || m_mediaStatus == QMediaPlayer::BufferedMedia)
+        [[(AVFMediaPlayerSessionObserver*)m_observer player] play];
+
+    //processLoadStateChange();
+    Q_EMIT stateChanged(m_state);
+}
+
+void AVFMediaPlayerSession::pause()
+{
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO << "currently: " << m_state;
+#endif
+
+    if (m_state == QMediaPlayer::PausedState)
+        return;
+
+    m_state = QMediaPlayer::PausedState;
+
+    if (m_videoOutput) {
+        m_videoOutput->setLayer([(AVFMediaPlayerSessionObserver*)m_observer playerLayer]);
+    }
+
+    //reset the EndOfMedia status if the same file is played again
+    if (m_mediaStatus == QMediaPlayer::EndOfMedia)
+        processLoadStateChange();
+
+    [[(AVFMediaPlayerSessionObserver*)m_observer player] pause];
+
+    //processLoadStateChange();
+    Q_EMIT stateChanged(m_state);
+}
+
+void AVFMediaPlayerSession::stop()
+{
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO << "currently: " << m_state;
+#endif
+
+    if (m_state == QMediaPlayer::StoppedState)
+        return;
+
+    m_state = QMediaPlayer::StoppedState;
+    m_rate = 0.0f;
+    [[(AVFMediaPlayerSessionObserver*)m_observer player] setRate:m_rate];
+    setPosition(0);
+
+    if (m_videoOutput) {
+        m_videoOutput->setLayer(0);
+    }
+
+    processLoadStateChange();
+    Q_EMIT stateChanged(m_state);
+    Q_EMIT positionChanged(position());
+}
+
+void AVFMediaPlayerSession::setVolume(int volume)
+{
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO << volume;
+#endif
+
+    if (m_volume == volume)
+        return;
+
+    m_volume = volume;
+
+#if defined(Q_OS_OSX)
+    AVPlayer *player = [(AVFMediaPlayerSessionObserver*)m_observer player];
+    if (player) {
+        [[(AVFMediaPlayerSessionObserver*)m_observer player] setVolume:m_volume / 100.0f];
+    }
+#endif
+
+    Q_EMIT volumeChanged(m_volume);
+}
+
+void AVFMediaPlayerSession::setMuted(bool muted)
+{
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO << muted;
+#endif
+    if (m_muted == muted)
+        return;
+
+    m_muted = muted;
+#if defined(Q_OS_OSX)
+    [[(AVFMediaPlayerSessionObserver*)m_observer player] setMuted:m_muted];
+#endif
+    Q_EMIT mutedChanged(muted);
+}
+
+void AVFMediaPlayerSession::processEOS()
+{
+    //AVPlayerItem has reached end of track/stream
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO;
+#endif
+    Q_EMIT positionChanged(position());
+    m_mediaStatus = QMediaPlayer::EndOfMedia;
+
+    Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState);
+    Q_EMIT mediaStatusChanged(m_mediaStatus);
+}
+
+void AVFMediaPlayerSession::processLoadStateChange()
+{
+    AVPlayerStatus currentStatus = [[(AVFMediaPlayerSessionObserver*)m_observer player] status];
+
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO << currentStatus;
+#endif
+
+    QMediaPlayer::MediaStatus newStatus = QMediaPlayer::NoMedia;
+    bool isPlaying = (m_state != QMediaPlayer::StoppedState);
+
+    if (currentStatus == AVPlayerStatusReadyToPlay) {
+        qint64 currentDuration = duration();
+        if (m_duration != currentDuration)
+            Q_EMIT durationChanged(m_duration = currentDuration);
+
+        if (m_audioAvailable != isAudioAvailable())
+            Q_EMIT audioAvailableChanged(m_audioAvailable = !m_audioAvailable);
+
+        if (m_videoAvailable != isVideoAvailable())
+            Q_EMIT videoAvailableChanged(m_videoAvailable = !m_videoAvailable);
+
+        newStatus = isPlaying ? QMediaPlayer::BufferedMedia : QMediaPlayer::LoadedMedia;
+
+        if (m_state == QMediaPlayer::PlayingState && [(AVFMediaPlayerSessionObserver*)m_observer player]) {
+            [[(AVFMediaPlayerSessionObserver*)m_observer player] setRate:m_rate];
+            [[(AVFMediaPlayerSessionObserver*)m_observer player] play];
+        }
+    }
+
+    if (newStatus != m_mediaStatus)
+        Q_EMIT mediaStatusChanged(m_mediaStatus = newStatus);
+}
+
+void AVFMediaPlayerSession::processPositionChange()
+{
+    Q_EMIT positionChanged(position());
+}
+
+void AVFMediaPlayerSession::processMediaLoadError()
+{
+    Q_EMIT error(QMediaPlayer::FormatError, tr("Failed to load media"));
+    Q_EMIT mediaStatusChanged(m_mediaStatus = QMediaPlayer::InvalidMedia);
+    Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState);
+}
+
+void AVFMediaPlayerSession::processCurrentItemChanged()
+{
+#ifdef QT_DEBUG_AVF
+    qDebug() << Q_FUNC_INFO;
+#endif
+
+    AVPlayerLayer *playerLayer = [(AVFMediaPlayerSessionObserver*)m_observer playerLayer];
+
+    if (m_videoOutput && m_state != QMediaPlayer::StoppedState) {
+        m_videoOutput->setLayer(playerLayer);
+    }
+
+}