Merge pull request #2531 from Montellese/settings_cleanup_4
[vuplus_xbmc] / xbmc / cores / omxplayer / OMXPlayerVideo.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #if (defined HAVE_CONFIG_H) && (!defined WIN32)
22   #include "config.h"
23 #elif defined(_WIN32)
24 #include "system.h"
25 #endif
26
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <sys/time.h>
30 #include <iomanip>
31 #include <iostream>
32 #include <sstream>
33
34 #include "OMXPlayerVideo.h"
35
36 #include "linux/XMemUtils.h"
37 #include "utils/BitstreamStats.h"
38
39 #include "DVDDemuxers/DVDDemuxUtils.h"
40 #include "DVDCodecs/DVDCodecUtils.h"
41 #include "windowing/WindowingFactory.h"
42 #include "DVDOverlayRenderer.h"
43 #include "settings/GUISettings.h"
44 #include "settings/Settings.h"
45 #include "settings/MediaSettings.h"
46 #include "cores/VideoRenderers/RenderFormats.h"
47 #include "cores/VideoRenderers/RenderFlags.h"
48
49 #include "OMXPlayer.h"
50
51 class COMXMsgVideoCodecChange : public CDVDMsg
52 {
53 public:
54   COMXMsgVideoCodecChange(const CDVDStreamInfo &hints, COMXVideo *codec)
55     : CDVDMsg(GENERAL_STREAMCHANGE)
56     , m_codec(codec)
57     , m_hints(hints)
58   {}
59  ~COMXMsgVideoCodecChange()
60   {
61     delete m_codec;
62   }
63   COMXVideo       *m_codec;
64   CDVDStreamInfo  m_hints;
65 };
66
67 OMXPlayerVideo::OMXPlayerVideo(OMXClock *av_clock,
68                                CDVDOverlayContainer* pOverlayContainer,
69                                CDVDMessageQueue& parent)
70 : CThread("COMXPlayerVideo")
71 , m_messageQueue("video")
72 , m_messageParent(parent)
73 {
74   m_av_clock              = av_clock;
75   m_pOverlayContainer     = pOverlayContainer;
76   m_pTempOverlayPicture   = NULL;
77   m_open                  = false;
78   m_stream_id             = -1;
79   m_fFrameRate            = 25.0f;
80   m_hdmi_clock_sync       = false;
81   m_speed                 = DVD_PLAYSPEED_NORMAL;
82   m_stalled               = false;
83   m_codecname             = "";
84   m_iSubtitleDelay        = 0;
85   m_FlipTimeStamp         = 0.0;
86   m_bRenderSubs           = false;
87   m_flags                 = 0;
88   m_bAllowFullscreen      = false;
89   m_iCurrentPts           = DVD_NOPTS_VALUE;
90   m_iVideoDelay           = 0;
91   m_droptime              = 0.0;
92   m_dropbase              = 0.0;
93   m_autosync              = 1;
94   m_fForcedAspectRatio    = 0.0f;
95   m_send_eos              = false;
96   m_messageQueue.SetMaxDataSize(10 * 1024 * 1024);
97   m_messageQueue.SetMaxTimeSize(8.0);
98
99   m_dst_rect.SetRect(0, 0, 0, 0);
100 }
101
102 OMXPlayerVideo::~OMXPlayerVideo()
103 {
104   CloseStream(false);
105 }
106
107 bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints)
108 {
109   /*
110   if(IsRunning())
111     CloseStream(false);
112   */
113
114   m_hints       = hints;
115   m_Deinterlace = ( CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode == VS_DEINTERLACEMODE_OFF ) ? false : true;
116   m_hdmi_clock_sync = (g_guiSettings.GetInt("videoplayer.adjustrefreshrate") != ADJUST_REFRESHRATE_OFF);
117   m_started     = false;
118   m_flush       = false;
119   m_stalled     = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0;
120   m_autosync    = 1;
121   m_iSleepEndTime = DVD_NOPTS_VALUE;
122   // force SetVideoRect to be called initially
123   m_dst_rect.SetRect(0, 0, 0, 0);
124
125   m_audio_count = m_av_clock->HasAudio();
126
127   if (!m_DllBcmHost.Load())
128     return false;
129
130   if(!OpenDecoder())
131   {
132     return false;
133   }
134
135   if(m_messageQueue.IsInited())
136     m_messageQueue.Put(new COMXMsgVideoCodecChange(hints, NULL), 0);
137   else
138   {
139     if(!OpenStream(hints, NULL))
140       return false;
141     CLog::Log(LOGNOTICE, "Creating video thread");
142     m_messageQueue.Init();
143     Create();
144   }
145
146   /*
147   if(!OpenStream(hints, NULL))
148     return false;
149
150   CLog::Log(LOGNOTICE, "Creating video thread");
151   m_messageQueue.Init();
152   Create();
153   */
154
155   m_open        = true;
156   m_send_eos    = false;
157
158   return true;
159 }
160
161 bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints, COMXVideo *codec)
162 {
163   return true;
164 }
165
166 bool OMXPlayerVideo::CloseStream(bool bWaitForBuffers)
167 {
168   // wait until buffers are empty
169   if (bWaitForBuffers && m_speed > 0) m_messageQueue.WaitUntilEmpty();
170
171   m_messageQueue.Abort();
172
173   if(IsRunning())
174     StopThread();
175
176   m_messageQueue.End();
177
178   m_open          = false;
179   m_stream_id     = -1;
180   m_speed         = DVD_PLAYSPEED_NORMAL;
181   m_started       = false;
182
183   if (m_pTempOverlayPicture)
184   {
185     CDVDCodecUtils::FreePicture(m_pTempOverlayPicture);
186     m_pTempOverlayPicture = NULL;
187   }
188
189   m_av_clock->Lock();
190   m_av_clock->OMXStop(false);
191   m_omxVideo.Close();
192   m_av_clock->HasVideo(false);
193   m_av_clock->OMXReset(false);
194   m_av_clock->UnLock();
195
196   if(m_DllBcmHost.IsLoaded())
197     m_DllBcmHost.Unload();
198
199   return true;
200 }
201
202 void OMXPlayerVideo::OnStartup()
203 {
204   m_iCurrentPts = DVD_NOPTS_VALUE;
205   m_FlipTimeStamp = m_av_clock->GetAbsoluteClock();
206 }
207
208 void OMXPlayerVideo::OnExit()
209 {
210   CLog::Log(LOGNOTICE, "thread end: video_thread");
211 }
212
213 void OMXPlayerVideo::ProcessOverlays(int iGroupId, double pts)
214 {
215   // remove any overlays that are out of time
216   if (m_started)
217     m_pOverlayContainer->CleanUp(pts - m_iSubtitleDelay);
218
219   VecOverlays overlays;
220
221   CSingleLock lock(*m_pOverlayContainer);
222
223   VecOverlays* pVecOverlays = m_pOverlayContainer->GetOverlays();
224   VecOverlaysIter it = pVecOverlays->begin();
225
226   //Check all overlays and render those that should be rendered, based on time and forced
227   //Both forced and subs should check timeing, pts == 0 in the stillframe case
228   while (it != pVecOverlays->end())
229   {
230     CDVDOverlay* pOverlay = *it++;
231     if(!pOverlay->bForced && !m_bRenderSubs)
232       continue;
233
234     if(pOverlay->iGroupId != iGroupId)
235       continue;
236
237     double pts2 = pOverlay->bForced ? pts : pts - m_iSubtitleDelay;
238
239     if((pOverlay->iPTSStartTime <= pts2 && (pOverlay->iPTSStopTime > pts2 || pOverlay->iPTSStopTime == 0LL)) || pts == 0)
240     {
241       if(pOverlay->IsOverlayType(DVDOVERLAY_TYPE_GROUP))
242         overlays.insert(overlays.end(), static_cast<CDVDOverlayGroup*>(pOverlay)->m_overlays.begin()
243                                       , static_cast<CDVDOverlayGroup*>(pOverlay)->m_overlays.end());
244       else
245         overlays.push_back(pOverlay);
246     }
247   }
248
249   for(it = overlays.begin(); it != overlays.end(); ++it)
250   {
251     double pts2 = (*it)->bForced ? pts : pts - m_iSubtitleDelay;
252     g_renderManager.AddOverlay(*it, pts2);
253   }
254 }
255
256 void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket)
257 {
258   if (!g_renderManager.IsStarted()) {
259     CLog::Log(LOGERROR, "%s - renderer not started", __FUNCTION__);
260     return;
261   }
262
263   // calculate the time we need to delay this picture before displaying
264   double iSleepTime, iClockSleep, iFrameSleep, iPlayingClock, iCurrentClock, iFrameDuration;
265
266   iPlayingClock = m_av_clock->GetClock(iCurrentClock, false); // snapshot current clock
267   iClockSleep = pts - iPlayingClock; //sleep calculated by pts to clock comparison
268   iFrameSleep = m_FlipTimeStamp - iCurrentClock; // sleep calculated by duration of frame
269   iFrameDuration = (double)DVD_TIME_BASE / m_fFrameRate; //pPacket->duration;
270
271   // correct sleep times based on speed
272   if(m_speed)
273   {
274     iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed;
275     iFrameSleep = iFrameSleep * DVD_PLAYSPEED_NORMAL / abs(m_speed);
276     iFrameDuration = iFrameDuration * DVD_PLAYSPEED_NORMAL / abs(m_speed);
277   }
278   else
279   {
280     iClockSleep = 0;
281     iFrameSleep = 0;
282   }
283
284   // dropping to a very low framerate is not correct (it should not happen at all)
285   iClockSleep = min(iClockSleep, DVD_MSEC_TO_TIME(500));
286   iFrameSleep = min(iFrameSleep, DVD_MSEC_TO_TIME(500));
287
288   if( m_stalled )
289     iSleepTime = iFrameSleep;
290   else
291     iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync;
292
293   // present the current pts of this frame to user, and include the actual
294   // presentation delay, to allow him to adjust for it
295   if( m_stalled )
296     m_iCurrentPts = DVD_NOPTS_VALUE;
297   else
298     m_iCurrentPts = pts - max(0.0, iSleepTime);
299
300   // timestamp when we think next picture should be displayed based on current duration
301   m_FlipTimeStamp  = iCurrentClock;
302   m_FlipTimeStamp += max(0.0, iSleepTime);
303   m_FlipTimeStamp += iFrameDuration;
304
305   if( m_speed < 0 )
306   {
307     if( iClockSleep < -DVD_MSEC_TO_TIME(200))
308       return;
309   }
310
311   if(bDropPacket)
312     return;
313
314 #if 0
315   if( m_speed != DVD_PLAYSPEED_NORMAL)
316   {
317     // calculate frame dropping pattern to render at this speed
318     // we do that by deciding if this or next frame is closest
319     // to the flip timestamp
320     double current   = fabs(m_dropbase -  m_droptime);
321     double next      = fabs(m_dropbase - (m_droptime + iFrameDuration));
322     double frametime = (double)DVD_TIME_BASE / m_fFrameRate;
323
324     m_droptime += iFrameDuration;
325 #ifndef PROFILE
326     if( next < current /*&& !(pPicture->iFlags & DVP_FLAG_NOSKIP) */)
327       return /*result | EOS_DROPPED*/;
328 #endif
329
330     while(!m_bStop && m_dropbase < m_droptime)             m_dropbase += frametime;
331     while(!m_bStop && m_dropbase - frametime > m_droptime) m_dropbase -= frametime;
332   }
333   else
334   {
335     m_droptime = 0.0f;
336     m_dropbase = 0.0f;
337   }
338 #else
339   m_droptime = 0.0f;
340   m_dropbase = 0.0f;
341 #endif
342
343   // DVDPlayer sleeps until m_iSleepEndTime here before calling FlipPage.
344   // Video playback in asynchronous in OMXPlayer, so we don't want to do that here, as it prevents the video fifo from being kept full.
345   // So, we keep track of when FlipPage would have been called on DVDPlayer and return early if it is not time.
346   // m_iSleepEndTime == DVD_NOPTS_VALUE means we are not waiting to call FlipPage, otherwise it is the time we want to call FlipPage
347   if (m_iSleepEndTime == DVD_NOPTS_VALUE) {
348     m_iSleepEndTime = iCurrentClock + iSleepTime;
349   }
350
351   if (!CThread::m_bStop && m_av_clock->GetAbsoluteClock(false) < m_iSleepEndTime + DVD_MSEC_TO_TIME(500))
352     return;
353
354   double pts_media = m_av_clock->OMXMediaTime(false, false);
355   ProcessOverlays(iGroupId, pts_media);
356
357   g_renderManager.FlipPage(CThread::m_bStop, m_iSleepEndTime / DVD_TIME_BASE, -1, FS_NONE);
358
359   m_iSleepEndTime = DVD_NOPTS_VALUE;
360
361   //m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime));
362 }
363
364 void OMXPlayerVideo::Process()
365 {
366   double pts = 0;
367   double frametime = (double)DVD_TIME_BASE / m_fFrameRate;
368   bool bRequestDrop = false;
369
370   m_videoStats.Start();
371
372   while(!m_bStop)
373   {
374     CDVDMsg* pMsg;
375     int iQueueTimeOut = (int)(m_stalled ? frametime / 4 : frametime * 10) / 1000;
376     int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0;
377     MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, iQueueTimeOut, iPriority);
378
379     if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT)
380     {
381       CLog::Log(LOGERROR, "Got MSGQ_ABORT or MSGO_IS_ERROR return true");
382       break;
383     }
384     else if (ret == MSGQ_TIMEOUT)
385     {
386       // if we only wanted priority messages, this isn't a stall
387       if( iPriority )
388         continue;
389
390       //Okey, start rendering at stream fps now instead, we are likely in a stillframe
391       if( !m_stalled )
392       {
393         if(m_started)
394           CLog::Log(LOGINFO, "COMXPlayerVideo - Stillframe detected, switching to forced %f fps", m_fFrameRate);
395         m_stalled = true;
396         pts += frametime*4;
397       }
398
399       pts += frametime;
400
401       continue;
402     }
403
404     if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE))
405     {
406       if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait(100, SYNCSOURCE_VIDEO))
407       {
408         CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_SYNCHRONIZE");
409
410       }
411       else
412         m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */
413
414       pMsg->Release();
415
416       continue;
417     }
418     else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC))
419     {
420       CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg;
421
422       if(pMsgGeneralResync->m_timestamp != DVD_NOPTS_VALUE)
423         pts = pMsgGeneralResync->m_timestamp;
424
425       double delay = m_FlipTimeStamp - m_av_clock->GetAbsoluteClock();
426       if( delay > frametime ) delay = frametime;
427       else if( delay < 0 )    delay = 0;
428
429       if(pMsgGeneralResync->m_clock)
430       {
431         CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f, 1)", pts);
432         m_av_clock->Discontinuity(pts - delay);
433         //m_av_clock->OMXUpdateClock(pts - delay);
434       }
435       else
436         CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f, 0)", pts);
437
438       pMsgGeneralResync->Release();
439       continue;
440     }
441     else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY))
442     {
443       if (m_speed != DVD_PLAYSPEED_PAUSE)
444       {
445         double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value;
446
447         CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_DELAY(%f)", timeout);
448
449         timeout *= (double)DVD_PLAYSPEED_NORMAL / abs(m_speed);
450         timeout += m_av_clock->GetAbsoluteClock();
451
452         while(!m_bStop && m_av_clock->GetAbsoluteClock() < timeout)
453           Sleep(1);
454       }
455     }
456     else if (pMsg->IsType(CDVDMsg::VIDEO_SET_ASPECT))
457     {
458       CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::VIDEO_SET_ASPECT");
459       m_fForcedAspectRatio = *((CDVDMsgDouble*)pMsg);
460     }
461     else if (pMsg->IsType(CDVDMsg::GENERAL_RESET))
462     {
463       CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESET");
464       m_av_clock->Lock();
465       m_av_clock->OMXStop(false);
466       m_omxVideo.Reset();
467       m_av_clock->OMXReset(false);
468       m_av_clock->UnLock();
469       m_started = false;
470       m_iSleepEndTime = DVD_NOPTS_VALUE;
471     }
472     else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (COMXPlayerVideo::Flush())
473     {
474       CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_FLUSH");
475       m_stalled = true;
476       m_started = false;
477       m_iSleepEndTime = DVD_NOPTS_VALUE;
478       m_av_clock->Lock();
479       m_av_clock->OMXStop(false);
480       m_omxVideo.Reset();
481       m_av_clock->OMXReset(false);
482       m_av_clock->UnLock();
483       m_flush = false;
484     }
485     else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED))
486     {
487       m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value;
488     }
489     else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED))
490     {
491       if(m_started)
492         m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO));
493     }
494     else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME))
495     {
496       COMXPlayer::SPlayerState& state = ((CDVDMsgType<COMXPlayer::SPlayerState>*)pMsg)->m_value;
497
498       if(state.time_src == COMXPlayer::ETIMESOURCE_CLOCK)
499         state.time      = DVD_TIME_TO_MSEC(m_av_clock->OMXMediaTime(true, true));
500         //state.time      = DVD_TIME_TO_MSEC(m_av_clock->GetClock(state.timestamp) + state.time_offset);
501       else
502         state.timestamp = m_av_clock->GetAbsoluteClock();
503       state.player    = DVDPLAYER_VIDEO;
504       m_messageParent.Put(pMsg->Acquire());
505     }
506     else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE))
507     {
508       COMXMsgVideoCodecChange* msg(static_cast<COMXMsgVideoCodecChange*>(pMsg));
509       OpenStream(msg->m_hints, msg->m_codec);
510       msg->m_codec = NULL;
511     }
512     else if (pMsg->IsType(CDVDMsg::GENERAL_EOF) && !m_audio_count)
513     {
514       CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_EOF");
515       WaitCompletion();
516     }
517     else if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
518     {
519       DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket();
520       bool bPacketDrop     = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop();
521
522       if (m_messageQueue.GetDataSize() == 0
523       ||  m_speed < 0)
524       {
525         bRequestDrop = false;
526       }
527
528       // if player want's us to drop this packet, do so nomatter what
529       if(bPacketDrop)
530         bRequestDrop = true;
531
532       m_omxVideo.SetDropState(bRequestDrop);
533
534       while (!m_bStop)
535       {
536         // discard if flushing as clocks may be stopped and we'll never submit it
537         if (m_flush)
538            break;
539
540         if((int)m_omxVideo.GetFreeSpace() < pPacket->iSize)
541         {
542           Sleep(10);
543           continue;
544         }
545   
546         if (m_stalled)
547         {
548           CLog::Log(LOGINFO, "COMXPlayerVideo - Stillframe left, switching to normal playback");
549           m_stalled = false;
550         }
551
552         double output_pts = 0;
553         // validate picture timing,
554         // if both dts/pts invalid, use pts calulated from picture.iDuration
555         // if pts invalid use dts, else use picture.pts as passed
556         if (pPacket->dts == DVD_NOPTS_VALUE && pPacket->pts == DVD_NOPTS_VALUE)
557           output_pts = pts;
558         else if (pPacket->pts == DVD_NOPTS_VALUE)
559           output_pts = pts;
560         else
561           output_pts = pPacket->pts;
562
563         if(pPacket->pts != DVD_NOPTS_VALUE)
564           pPacket->pts += m_iVideoDelay;
565
566         if(pPacket->dts != DVD_NOPTS_VALUE)
567           pPacket->dts += m_iVideoDelay;
568
569         if(pPacket->duration == 0)
570           pPacket->duration = frametime;
571
572         if(output_pts != DVD_NOPTS_VALUE)
573           pts = output_pts;
574
575         m_omxVideo.Decode(pPacket->pData, pPacket->iSize, pPacket->dts, pPacket->pts);
576
577         Output(pPacket->iGroupId, output_pts, bRequestDrop);
578
579         if(m_started == false)
580         {
581           m_codecname = m_omxVideo.GetDecoderName();
582           m_started = true;
583           m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO));
584         }
585
586         // guess next frame pts. iDuration is always valid
587         if (m_speed != 0)
588           pts += pPacket->duration * m_speed / abs(m_speed);
589
590         break;
591       }
592
593       bRequestDrop = false;
594
595       m_videoStats.AddSampleBytes(pPacket->iSize);
596     }
597     pMsg->Release();
598
599   }
600 }
601
602 void OMXPlayerVideo::Flush()
603 {
604   m_flush = true;
605   m_messageQueue.Flush();
606   m_messageQueue.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH), 1);
607 }
608
609 bool OMXPlayerVideo::OpenDecoder()
610 {
611   if(!m_av_clock)
612     return false;
613
614   if (m_hints.fpsrate && m_hints.fpsscale)
615     m_fFrameRate = DVD_TIME_BASE / OMXClock::NormalizeFrameduration((double)DVD_TIME_BASE * m_hints.fpsscale / m_hints.fpsrate);
616   else
617     m_fFrameRate = 25;
618
619   if( m_fFrameRate > 100 || m_fFrameRate < 5 )
620   {
621     CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder : Invalid framerate %d, using forced 25fps and just trust timestamps\n", (int)m_fFrameRate);
622     m_fFrameRate = 25;
623   }
624   // use aspect in stream always
625   m_fForcedAspectRatio = m_hints.aspect;
626
627
628   m_av_clock->Lock();
629   m_av_clock->OMXStop(false);
630
631   bool bVideoDecoderOpen = m_omxVideo.Open(m_hints, m_av_clock, m_Deinterlace, m_hdmi_clock_sync);
632   m_omxVideo.RegisterResolutionUpdateCallBack((void *)this, ResolutionUpdateCallBack);
633
634   if(!bVideoDecoderOpen)
635   {
636     CLog::Log(LOGERROR, "OMXPlayerVideo : Error open video output");
637     m_omxVideo.Close();
638   }
639   else
640   {
641     CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder : Video codec %s width %d height %d profile %d fps %f\n",
642         m_omxVideo.GetDecoderName().c_str() , m_hints.width, m_hints.height, m_hints.profile, m_fFrameRate);
643
644     m_codecname = m_omxVideo.GetDecoderName();
645
646     // if we are closer to ntsc version of framerate, let gpu know
647     int   iFrameRate  = (int)(m_fFrameRate + 0.5f);
648     bool  bNtscFreq  = fabs(m_fFrameRate * 1001.0f / 1000.0f - iFrameRate) < fabs(m_fFrameRate - iFrameRate);
649     char  response[80], command[80];
650     sprintf(command, "hdmi_ntsc_freqs %d", bNtscFreq);
651     CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder fps: %f %s\n", m_fFrameRate, command);
652     m_DllBcmHost.vc_gencmd(response, sizeof response, command);
653
654     if(m_av_clock)
655       m_av_clock->SetRefreshRate(m_fFrameRate);
656   }
657
658   m_av_clock->OMXStateExecute(false);
659   m_av_clock->HasVideo(bVideoDecoderOpen);
660   m_av_clock->OMXReset(false);
661   m_av_clock->UnLock();
662
663   return bVideoDecoderOpen;
664 }
665
666 int  OMXPlayerVideo::GetDecoderBufferSize()
667 {
668   return m_omxVideo.GetInputBufferSize();
669 }
670
671 int  OMXPlayerVideo::GetDecoderFreeSpace()
672 {
673   return m_omxVideo.GetFreeSpace();
674 }
675
676 void OMXPlayerVideo::WaitCompletion()
677 {
678   if(!m_send_eos)
679     m_omxVideo.WaitCompletion();
680   m_send_eos = true;
681 }
682
683 void OMXPlayerVideo::SetSpeed(int speed)
684 {
685   if(m_messageQueue.IsInited())
686     m_messageQueue.Put( new CDVDMsgInt(CDVDMsg::PLAYER_SETSPEED, speed), 1 );
687   else
688     m_speed = speed;
689 }
690
691 std::string OMXPlayerVideo::GetPlayerInfo()
692 {
693   std::ostringstream s;
694   s << "fr:"     << fixed << setprecision(3) << m_fFrameRate;
695   s << ", vq:"   << setw(2) << min(99,GetLevel()) << "%";
696   s << ", dc:"   << m_codecname;
697   s << ", Mb/s:" << fixed << setprecision(2) << (double)GetVideoBitrate() / (1024.0*1024.0);
698
699   return s.str();
700 }
701
702 int OMXPlayerVideo::GetVideoBitrate()
703 {
704   return (int)m_videoStats.GetBitrate();
705 }
706
707 double OMXPlayerVideo::GetOutputDelay()
708 {
709   double time = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET);
710   if( m_fFrameRate )
711     time = (time * DVD_TIME_BASE) / m_fFrameRate;
712   else
713     time = 0.0;
714
715   if( m_speed != 0 )
716     time = time * DVD_PLAYSPEED_NORMAL / abs(m_speed);
717
718   return time;
719 }
720
721 int OMXPlayerVideo::GetFreeSpace()
722 {
723   return m_omxVideo.GetFreeSpace();
724 }
725
726 void OMXPlayerVideo::SetVideoRect(const CRect &SrcRect, const CRect &DestRect)
727 {
728   // check if destination rect or video view mode has changed
729   if ((m_dst_rect != DestRect) || (m_view_mode != CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode))
730   {
731     m_dst_rect  = DestRect;
732     m_view_mode = CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode;
733   }
734   else
735   {
736     return;
737   }
738
739   // might need to scale up m_dst_rect to display size as video decodes
740   // to separate video plane that is at display size.
741   CRect gui, display, dst_rect;
742   RESOLUTION res = g_graphicsContext.GetVideoResolution();
743   gui.SetRect(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iWidth, CDisplaySettings::Get().GetResolutionInfo(res).iHeight);
744   display.SetRect(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth, CDisplaySettings::Get().GetResolutionInfo(res).iScreenHeight);
745   
746   dst_rect = m_dst_rect;
747   if (gui != display)
748   {
749     float xscale = display.Width()  / gui.Width();
750     float yscale = display.Height() / gui.Height();
751     // video is displayed in absolute coordinates (bypassing half width or height GUI mode)
752     if (m_flags & CONF_FLAGS_FORMAT_SBS) xscale *= 2.0f;
753     if (m_flags & CONF_FLAGS_FORMAT_TB)  yscale *= 2.0f;
754     dst_rect.x1 *= xscale;
755     dst_rect.x2 *= xscale;
756     dst_rect.y1 *= yscale;
757     dst_rect.y2 *= yscale;
758   }
759   m_omxVideo.SetVideoRect(SrcRect, dst_rect);
760 }
761
762 void OMXPlayerVideo::RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, const CRect &DestRect)
763 {
764   OMXPlayerVideo *player = (OMXPlayerVideo*)ctx;
765   player->SetVideoRect(SrcRect, DestRect);
766 }
767
768 void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height)
769 {
770   RESOLUTION res  = g_graphicsContext.GetVideoResolution();
771   uint32_t video_width   = CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth;
772   uint32_t video_height  = CDisplaySettings::Get().GetResolutionInfo(res).iScreenHeight;
773
774   unsigned flags = 0;
775   ERenderFormat format = RENDER_FMT_BYPASS;
776
777   if(m_bAllowFullscreen)
778   {
779     flags |= CONF_FLAGS_FULLSCREEN;
780     m_bAllowFullscreen = false; // only allow on first configure
781   }
782
783   if(m_flags & CONF_FLAGS_FORMAT_SBS)
784   {
785     if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DSBS))
786     {
787       CLog::Log(LOGNOTICE, "3DSBS movie found");
788       flags |= CONF_FLAGS_FORMAT_SBS;
789     }
790   }
791   else if(m_flags & CONF_FLAGS_FORMAT_TB)
792   {
793     if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DTB))
794     {
795       CLog::Log(LOGNOTICE, "3DTB movie found");
796       flags |= CONF_FLAGS_FORMAT_TB;
797     }
798   }
799
800   unsigned int iDisplayWidth  = width;
801   unsigned int iDisplayHeight = height;
802
803   /* use forced aspect if any */
804   if( m_fForcedAspectRatio != 0.0f )
805     iDisplayWidth = (int) (iDisplayHeight * m_fForcedAspectRatio);
806
807   CLog::Log(LOGDEBUG,"%s - change configuration. video:%dx%d. framerate: %4.2f. %dx%d format: BYPASS",
808       __FUNCTION__, video_width, video_height, m_fFrameRate, iDisplayWidth, iDisplayHeight);
809
810   if(!g_renderManager.Configure(width, height,
811         iDisplayWidth, iDisplayHeight, m_fFrameRate, flags, format, 0,
812         m_hints.orientation))
813   {
814     CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__);
815     return;
816   }
817
818   g_renderManager.RegisterRenderUpdateCallBack((const void*)this, RenderUpdateCallBack);
819 }
820
821 void OMXPlayerVideo::ResolutionUpdateCallBack(void *ctx, uint32_t width, uint32_t height)
822 {
823   OMXPlayerVideo *player = static_cast<OMXPlayerVideo*>(ctx);
824   player->ResolutionUpdateCallBack(width, height);
825 }
826