/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 518 lines · 340 code · 123 blank · 55 comment · 39 complexity · bd097c4b368e3c5be718b8b1a469e295 MD5 · raw file

  1. /* This file is part of the KDE project.
  2. Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
  3. This library is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation, either version 2.1 or 3 of the License.
  6. This library is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU Lesser General Public License for more details.
  10. You should have received a copy of the GNU Lesser General Public License
  11. along with this library. If not, see <http://www.gnu.org/licenses/>.
  12. */
  13. #include <QDir>
  14. #include <QUrl>
  15. #include <QTimer>
  16. #include <QWidget>
  17. #include <coemain.h> // for CCoeEnv
  18. #include "abstractvideoplayer.h"
  19. #include "utils.h"
  20. #ifndef QT_NO_DEBUG
  21. #include "objectdump.h"
  22. #endif
  23. QT_BEGIN_NAMESPACE
  24. using namespace Phonon;
  25. using namespace Phonon::MMF;
  26. /*! \class MMF::AbstractVideoPlayer
  27. \internal
  28. */
  29. //-----------------------------------------------------------------------------
  30. // Constructor / destructor
  31. //-----------------------------------------------------------------------------
  32. MMF::AbstractVideoPlayer::AbstractVideoPlayer(MediaObject *parent, const AbstractPlayer *player)
  33. : AbstractMediaPlayer(parent, player)
  34. , m_wsSession(CCoeEnv::Static()->WsSession())
  35. , m_screenDevice(*CCoeEnv::Static()->ScreenDevice())
  36. , m_window(0)
  37. , m_scaleWidth(1.0)
  38. , m_scaleHeight(1.0)
  39. , m_totalTime(0)
  40. {
  41. }
  42. void MMF::AbstractVideoPlayer::construct()
  43. {
  44. TRACE_CONTEXT(AbstractVideoPlayer::AbstractVideoPlayer, EVideoApi);
  45. TRACE_ENTRY_0();
  46. if (m_videoOutput) {
  47. initVideoOutput();
  48. m_window = m_videoOutput->videoWindow();
  49. }
  50. createPlayer();
  51. m_player->RegisterForVideoLoadingNotification(*this);
  52. TRACE_EXIT_0();
  53. }
  54. MMF::AbstractVideoPlayer::~AbstractVideoPlayer()
  55. {
  56. TRACE_CONTEXT(AbstractVideoPlayer::~AbstractVideoPlayer, EVideoApi);
  57. TRACE_ENTRY_0();
  58. // QObject destructor removes all signal-slot connections involving this
  59. // object, so we do not need to disconnect from m_videoOutput here.
  60. TRACE_EXIT_0();
  61. }
  62. CVideoPlayerUtility* MMF::AbstractVideoPlayer::nativePlayer() const
  63. {
  64. return m_player.data();
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Public API
  68. //-----------------------------------------------------------------------------
  69. void MMF::AbstractVideoPlayer::doPlay()
  70. {
  71. TRACE_CONTEXT(AbstractVideoPlayer::doPlay, EVideoApi);
  72. handlePendingParametersChanged();
  73. m_player->Play();
  74. }
  75. void MMF::AbstractVideoPlayer::doPause()
  76. {
  77. TRACE_CONTEXT(AbstractVideoPlayer::doPause, EVideoApi);
  78. TRAPD(err, m_player->PauseL());
  79. if (KErrNone != err && state() != ErrorState) {
  80. TRACE("PauseL error %d", err);
  81. setError(tr("Pause failed"), err);
  82. }
  83. }
  84. void MMF::AbstractVideoPlayer::doStop()
  85. {
  86. m_player->Stop();
  87. }
  88. void MMF::AbstractVideoPlayer::doSeek(qint64 ms)
  89. {
  90. TRACE_CONTEXT(AbstractVideoPlayer::doSeek, EVideoApi);
  91. TRAPD(err, m_player->SetPositionL(TTimeIntervalMicroSeconds(ms * 1000)));
  92. if (KErrNone != err)
  93. setError(tr("Seek failed"), err);
  94. }
  95. int MMF::AbstractVideoPlayer::setDeviceVolume(int mmfVolume)
  96. {
  97. TRAPD(err, m_player->SetVolumeL(mmfVolume));
  98. return err;
  99. }
  100. int MMF::AbstractVideoPlayer::openFile(const QString &fileName)
  101. {
  102. const QHBufC nativeFileName(QDir::toNativeSeparators(fileName));
  103. TRAPD(err, m_player->OpenFileL(*nativeFileName));
  104. return err;
  105. }
  106. int MMF::AbstractVideoPlayer::openFile(RFile &file)
  107. {
  108. TRAPD(err, m_player->OpenFileL(file));
  109. return err;
  110. }
  111. int MMF::AbstractVideoPlayer::openUrl(const QString &url, int iap)
  112. {
  113. TRAPD(err, m_player->OpenUrlL(qt_QString2TPtrC(url), iap));
  114. return err;
  115. }
  116. int MMF::AbstractVideoPlayer::openDescriptor(const TDesC8 &des)
  117. {
  118. TRAPD(err, m_player->OpenDesL(des));
  119. return err;
  120. }
  121. int MMF::AbstractVideoPlayer::bufferStatus() const
  122. {
  123. int result = 0;
  124. TRAP_IGNORE(m_player->GetVideoLoadingProgressL(result));
  125. return result;
  126. }
  127. void MMF::AbstractVideoPlayer::doClose()
  128. {
  129. m_player->Close();
  130. }
  131. bool MMF::AbstractVideoPlayer::hasVideo() const
  132. {
  133. return true;
  134. }
  135. qint64 MMF::AbstractVideoPlayer::getCurrentTime() const
  136. {
  137. TRACE_CONTEXT(AbstractVideoPlayer::getCurrentTime, EVideoApi);
  138. TTimeIntervalMicroSeconds us;
  139. TRAPD(err, us = m_player->PositionL())
  140. qint64 result = 0;
  141. if (KErrNone == err) {
  142. result = toMilliSeconds(us);
  143. } else {
  144. TRACE("PositionL error %d", err);
  145. // If we don't cast away constness here, we simply have to ignore
  146. // the error.
  147. const_cast<AbstractVideoPlayer*>(this)->setError(tr("Getting position failed"), err);
  148. }
  149. return result;
  150. }
  151. qint64 MMF::AbstractVideoPlayer::totalTime() const
  152. {
  153. return m_totalTime;
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Public slots
  157. //-----------------------------------------------------------------------------
  158. void MMF::AbstractVideoPlayer::videoWindowChanged()
  159. {
  160. TRACE_CONTEXT(AbstractVideoPlayer::videoWindowChanged, EVideoInternal);
  161. TRACE_ENTRY("state %d", state());
  162. m_window = m_videoOutput ? m_videoOutput->videoWindow() : 0;
  163. if (m_videoOutput)
  164. m_videoOutput->dump();
  165. handleVideoWindowChanged();
  166. TRACE_EXIT_0();
  167. }
  168. void MMF::AbstractVideoPlayer::aspectRatioChanged()
  169. {
  170. TRACE_CONTEXT(AbstractVideoPlayer::aspectRatioChanged, EVideoInternal);
  171. TRACE_ENTRY("state %d aspectRatio %d", state());
  172. if (m_videoOutput)
  173. updateScaleFactors(m_videoOutput->videoWindowSize());
  174. TRACE_EXIT_0();
  175. }
  176. void MMF::AbstractVideoPlayer::scaleModeChanged()
  177. {
  178. TRACE_CONTEXT(AbstractVideoPlayer::scaleModeChanged, EVideoInternal);
  179. TRACE_ENTRY("state %d", state());
  180. if (m_videoOutput)
  181. updateScaleFactors(m_videoOutput->videoWindowSize());
  182. TRACE_EXIT_0();
  183. }
  184. //-----------------------------------------------------------------------------
  185. // MVideoPlayerUtilityObserver callbacks
  186. //-----------------------------------------------------------------------------
  187. void MMF::AbstractVideoPlayer::MvpuoOpenComplete(TInt aError)
  188. {
  189. TRACE_CONTEXT(AbstractVideoPlayer::MvpuoOpenComplete, EVideoApi);
  190. TRACE_ENTRY("state %d error %d", state(), aError);
  191. __ASSERT_ALWAYS(LoadingState == state() ||
  192. progressiveDownloadStalled() && BufferingState == state(),
  193. Utils::panic(InvalidStatePanic));
  194. if (KErrNone == aError)
  195. m_player->Prepare();
  196. else
  197. setError(tr("Opening clip failed"), aError);
  198. TRACE_EXIT_0();
  199. }
  200. void MMF::AbstractVideoPlayer::MvpuoPrepareComplete(TInt aError)
  201. {
  202. TRACE_CONTEXT(AbstractVideoPlayer::MvpuoPrepareComplete, EVideoApi);
  203. TRACE_ENTRY("state %d error %d", state(), aError);
  204. __ASSERT_ALWAYS(LoadingState == state() ||
  205. progressiveDownloadStalled() && BufferingState == state(),
  206. Utils::panic(InvalidStatePanic));
  207. TRAPD(err, getVideoClipParametersL(aError));
  208. if (KErrNone == err) {
  209. if (m_videoOutput)
  210. m_videoOutput->dump();
  211. maxVolumeChanged(m_player->MaxVolume());
  212. if (m_videoOutput)
  213. m_videoOutput->setVideoSize(m_videoFrameSize);
  214. prepareCompleted();
  215. handlePendingParametersChanged();
  216. emit totalTimeChanged(totalTime());
  217. }
  218. loadingComplete(aError);
  219. TRACE_EXIT_0();
  220. }
  221. void MMF::AbstractVideoPlayer::getVideoClipParametersL(TInt aError)
  222. {
  223. User::LeaveIfError(aError);
  224. // Get frame size
  225. TSize size;
  226. m_player->VideoFrameSizeL(size);
  227. m_videoFrameSize = QSize(size.iWidth, size.iHeight);
  228. // Get duration
  229. m_totalTime = toMilliSeconds(m_player->DurationL());
  230. }
  231. void MMF::AbstractVideoPlayer::MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError)
  232. {
  233. TRACE_CONTEXT(AbstractVideoPlayer::MvpuoFrameReady, EVideoApi);
  234. TRACE_ENTRY("state %d error %d", state(), aError);
  235. Q_UNUSED(aFrame);
  236. Q_UNUSED(aError); // suppress warnings in release builds
  237. TRACE_EXIT_0();
  238. }
  239. void MMF::AbstractVideoPlayer::MvpuoPlayComplete(TInt aError)
  240. {
  241. TRACE_CONTEXT(AbstractVideoPlayer::MvpuoPlayComplete, EVideoApi)
  242. TRACE_ENTRY("state %d error %d", state(), aError);
  243. // Call base class function which handles end of playback for both
  244. // audio and video clips.
  245. playbackComplete(aError);
  246. TRACE_EXIT_0();
  247. }
  248. void MMF::AbstractVideoPlayer::MvpuoEvent(const TMMFEvent &aEvent)
  249. {
  250. TRACE_CONTEXT(AbstractVideoPlayer::MvpuoEvent, EVideoApi);
  251. TRACE_ENTRY("state %d", state());
  252. Q_UNUSED(aEvent);
  253. TRACE_EXIT_0();
  254. }
  255. //-----------------------------------------------------------------------------
  256. // MVideoLoadingObserver callbacks
  257. //-----------------------------------------------------------------------------
  258. void MMF::AbstractVideoPlayer::MvloLoadingStarted()
  259. {
  260. bufferingStarted();
  261. }
  262. void MMF::AbstractVideoPlayer::MvloLoadingComplete()
  263. {
  264. bufferingComplete();
  265. }
  266. //-----------------------------------------------------------------------------
  267. // Video window updates
  268. //-----------------------------------------------------------------------------
  269. void MMF::AbstractVideoPlayer::videoOutputChanged()
  270. {
  271. TRACE_CONTEXT(AbstractVideoPlayer::videoOutputChanged, EVideoInternal);
  272. TRACE_ENTRY_0();
  273. if (m_videoOutput)
  274. initVideoOutput();
  275. videoWindowChanged();
  276. TRACE_EXIT_0();
  277. }
  278. void MMF::AbstractVideoPlayer::initVideoOutput()
  279. {
  280. Q_ASSERT(m_videoOutput);
  281. bool connected = connect(
  282. m_videoOutput, SIGNAL(videoWindowChanged()),
  283. this, SLOT(videoWindowChanged())
  284. );
  285. Q_ASSERT(connected);
  286. connected = connect(
  287. m_videoOutput, SIGNAL(aspectRatioChanged()),
  288. this, SLOT(aspectRatioChanged())
  289. );
  290. Q_ASSERT(connected);
  291. connected = connect(
  292. m_videoOutput, SIGNAL(scaleModeChanged()),
  293. this, SLOT(scaleModeChanged())
  294. );
  295. Q_ASSERT(connected);
  296. // Suppress warnings in release builds
  297. Q_UNUSED(connected);
  298. m_videoOutput->setVideoSize(m_videoFrameSize);
  299. }
  300. // Helper function for aspect ratio / scale mode handling
  301. QSize scaleToAspect(const QSize &srcRect, int aspectWidth, int aspectHeight)
  302. {
  303. const qreal aspectRatio = qreal(aspectWidth) / aspectHeight;
  304. int width = srcRect.width();
  305. int height = srcRect.width() / aspectRatio;
  306. if (height > srcRect.height()){
  307. height = srcRect.height();
  308. width = srcRect.height() * aspectRatio;
  309. }
  310. return QSize(width, height);
  311. }
  312. void MMF::AbstractVideoPlayer::updateScaleFactors(const QSize &windowSize, bool apply)
  313. {
  314. Q_ASSERT(m_videoOutput);
  315. if (m_videoFrameSize.isValid()) {
  316. QRect videoRect;
  317. // Calculate size of smallest rect which contains video frame size
  318. // and conforms to aspect ratio
  319. switch (m_videoOutput->aspectRatio()) {
  320. case Phonon::VideoWidget::AspectRatioAuto:
  321. videoRect.setSize(m_videoFrameSize);
  322. break;
  323. case Phonon::VideoWidget::AspectRatioWidget:
  324. videoRect.setSize(windowSize);
  325. break;
  326. case Phonon::VideoWidget::AspectRatio4_3:
  327. videoRect.setSize(scaleToAspect(m_videoFrameSize, 4, 3));
  328. break;
  329. case Phonon::VideoWidget::AspectRatio16_9:
  330. videoRect.setSize(scaleToAspect(m_videoFrameSize, 16, 9));
  331. break;
  332. }
  333. // Scale to fill the window width
  334. const int windowWidth = windowSize.width();
  335. const int windowHeight = windowSize.height();
  336. const qreal windowScaleFactor = qreal(windowWidth) / videoRect.width();
  337. int videoWidth = windowWidth;
  338. int videoHeight = videoRect.height() * windowScaleFactor;
  339. const qreal windowToVideoHeightRatio = qreal(windowHeight) / videoHeight;
  340. switch (m_videoOutput->scaleMode()) {
  341. case Phonon::VideoWidget::ScaleAndCrop:
  342. if (videoHeight < windowHeight) {
  343. videoWidth *= windowToVideoHeightRatio;
  344. videoHeight = windowHeight;
  345. }
  346. break;
  347. case Phonon::VideoWidget::FitInView:
  348. default:
  349. if (videoHeight > windowHeight) {
  350. videoWidth *= windowToVideoHeightRatio;
  351. videoHeight = windowHeight;
  352. }
  353. break;
  354. }
  355. // Calculate scale factors
  356. m_scaleWidth = 100.0f * videoWidth / m_videoFrameSize.width();
  357. m_scaleHeight = 100.0f * videoHeight / m_videoFrameSize.height();
  358. if (apply)
  359. parametersChanged(ScaleFactors);
  360. }
  361. }
  362. void MMF::AbstractVideoPlayer::parametersChanged(VideoParameters parameters)
  363. {
  364. if (state() == LoadingState || progressiveDownloadStalled() && BufferingState == state())
  365. m_pendingChanges |= parameters;
  366. else
  367. handleParametersChanged(parameters);
  368. }
  369. void MMF::AbstractVideoPlayer::handlePendingParametersChanged()
  370. {
  371. if (m_pendingChanges)
  372. handleParametersChanged(m_pendingChanges);
  373. m_pendingChanges = 0;
  374. }
  375. //-----------------------------------------------------------------------------
  376. // Metadata
  377. //-----------------------------------------------------------------------------
  378. int MMF::AbstractVideoPlayer::numberOfMetaDataEntries() const
  379. {
  380. int numberOfEntries = 0;
  381. TRAP_IGNORE(numberOfEntries = m_player->NumberOfMetaDataEntriesL());
  382. return numberOfEntries;
  383. }
  384. QPair<QString, QString> MMF::AbstractVideoPlayer::metaDataEntry(int index) const
  385. {
  386. CMMFMetaDataEntry *entry = 0;
  387. QT_TRAP_THROWING(entry = m_player->MetaDataEntryL(index));
  388. return QPair<QString, QString>(qt_TDesC2QString(entry->Name()), qt_TDesC2QString(entry->Value()));
  389. }
  390. QT_END_NAMESPACE