[release] version bump to 13.0 beta1
[vuplus_xbmc] / xbmc / cores / omxplayer / OMXPlayerVideo.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://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 TARGET_WINDOWS)
22   #include "config.h"
23 #elif defined(TARGET_WINDOWS)
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/DisplaySettings.h"
44 #include "settings/Settings.h"
45 #include "settings/MediaSettings.h"
46 #include "cores/VideoRenderers/RenderFormats.h"
47 #include "cores/VideoRenderers/RenderFlags.h"
48 #include "guilib/GraphicContext.h"
49
50 #include "OMXPlayer.h"
51 #include "linux/RBP.h"
52
53 using namespace RenderManager;
54
55 class COMXMsgVideoCodecChange : public CDVDMsg
56 {
57 public:
58   COMXMsgVideoCodecChange(const CDVDStreamInfo &hints, COMXVideo *codec)
59     : CDVDMsg(GENERAL_STREAMCHANGE)
60     , m_codec(codec)
61     , m_hints(hints)
62   {}
63  ~COMXMsgVideoCodecChange()
64   {
65     delete m_codec;
66   }
67   COMXVideo       *m_codec;
68   CDVDStreamInfo  m_hints;
69 };
70
71 OMXPlayerVideo::OMXPlayerVideo(OMXClock *av_clock,
72                                CDVDOverlayContainer* pOverlayContainer,
73                                CDVDMessageQueue& parent)
74 : CThread("OMXPlayerVideo")
75 , m_messageQueue("video")
76 , m_codecname("")
77 , m_messageParent(parent)
78 {
79   m_av_clock              = av_clock;
80   m_pOverlayContainer     = pOverlayContainer;
81   m_open                  = false;
82   m_stream_id             = -1;
83   m_fFrameRate            = 25.0f;
84   m_hdmi_clock_sync       = false;
85   m_speed                 = DVD_PLAYSPEED_NORMAL;
86   m_stalled               = false;
87   m_iSubtitleDelay        = 0;
88   m_bRenderSubs           = false;
89   m_flags                 = 0;
90   m_bAllowFullscreen      = false;
91   m_iCurrentPts           = DVD_NOPTS_VALUE;
92   m_iVideoDelay           = 0;
93   m_fForcedAspectRatio    = 0.0f;
94   bool small_mem = g_RBP.GetArmMem() < 256;
95   m_messageQueue.SetMaxDataSize((small_mem ? 10:40) * 1024 * 1024);
96   m_messageQueue.SetMaxTimeSize(8.0);
97
98   m_dst_rect.SetRect(0, 0, 0, 0);
99   m_started = false;
100   m_iCurrentPts = DVD_NOPTS_VALUE;
101   m_nextOverlay = DVD_NOPTS_VALUE;
102   m_flush = false;
103   m_view_mode = 0;
104   m_history_valid_pts = 0;
105 }
106
107 OMXPlayerVideo::~OMXPlayerVideo()
108 {
109   CloseStream(false);
110 }
111
112 bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints)
113 {
114   m_hints       = hints;
115   m_hdmi_clock_sync = (CSettings::Get().GetInt("videoplayer.adjustrefreshrate") != ADJUST_REFRESHRATE_OFF);
116   m_started     = false;
117   m_flush       = false;
118   m_stalled     = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0;
119   m_nextOverlay = DVD_NOPTS_VALUE;
120   // force SetVideoRect to be called initially
121   m_dst_rect.SetRect(0, 0, 0, 0);
122
123   if (!m_DllBcmHost.Load())
124     return false;
125
126   if(!OpenDecoder())
127   {
128     return false;
129   }
130
131   if(m_messageQueue.IsInited())
132     m_messageQueue.Put(new COMXMsgVideoCodecChange(hints, NULL), 0);
133   else
134   {
135     if(!OpenStream(hints, NULL))
136       return false;
137     CLog::Log(LOGNOTICE, "Creating video thread");
138     m_messageQueue.Init();
139     Create();
140   }
141
142   m_open        = true;
143   m_iCurrentPts = DVD_NOPTS_VALUE;
144   m_nextOverlay = DVD_NOPTS_VALUE;
145
146   return true;
147 }
148
149 bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints, COMXVideo *codec)
150 {
151   return true;
152 }
153
154 bool OMXPlayerVideo::CloseStream(bool bWaitForBuffers)
155 {
156   // wait until buffers are empty
157   if (bWaitForBuffers && m_speed > 0) m_messageQueue.WaitUntilEmpty();
158
159   m_messageQueue.Abort();
160
161   if(IsRunning())
162     StopThread();
163
164   m_messageQueue.End();
165
166   m_open          = false;
167   m_stream_id     = -1;
168   m_speed         = DVD_PLAYSPEED_NORMAL;
169   m_started       = false;
170
171   m_omxVideo.Close();
172
173   if(m_DllBcmHost.IsLoaded())
174     m_DllBcmHost.Unload();
175
176   return true;
177 }
178
179 void OMXPlayerVideo::OnStartup()
180 {
181 }
182
183 void OMXPlayerVideo::OnExit()
184 {
185   CLog::Log(LOGNOTICE, "thread end: video_thread");
186 }
187
188 double OMXPlayerVideo::NextOverlay(double pts)
189 {
190   double delta_start, delta_stop, min_delta = DVD_NOPTS_VALUE;
191
192   CSingleLock lock(*m_pOverlayContainer);
193   VecOverlays* pVecOverlays = m_pOverlayContainer->GetOverlays();
194   VecOverlaysIter it = pVecOverlays->begin();
195
196   //Find the minimum time before a subtitle is added or removed
197   while (it != pVecOverlays->end())
198   {
199     CDVDOverlay* pOverlay = *it++;
200     if(!pOverlay->bForced && !m_bRenderSubs)
201       continue;
202
203     double pts2 = pOverlay->bForced ? pts : pts - m_iSubtitleDelay;
204
205     delta_start = pOverlay->iPTSStartTime - pts2;
206     delta_stop = pOverlay->iPTSStopTime - pts2;
207
208     // when currently on screen, we periodically update to allow (limited rate) ASS animation
209     if (delta_start <= 0.0 && delta_stop > 0.0 && (min_delta == DVD_NOPTS_VALUE || DVD_MSEC_TO_TIME(100) < min_delta))
210       min_delta = DVD_MSEC_TO_TIME(100);
211
212     else if (delta_start > 0.0 && (min_delta == DVD_NOPTS_VALUE || delta_start < min_delta))
213       min_delta = delta_start;
214
215     else if (delta_stop > 0.0 && (min_delta == DVD_NOPTS_VALUE || delta_stop < min_delta))
216       min_delta = delta_stop;
217   }
218   return min_delta == DVD_NOPTS_VALUE ? pts+DVD_MSEC_TO_TIME(500) : pts+min_delta;
219 }
220
221
222 void OMXPlayerVideo::ProcessOverlays(double pts)
223 {
224   // remove any overlays that are out of time
225   if (m_started)
226     m_pOverlayContainer->CleanUp(pts - m_iSubtitleDelay);
227
228   VecOverlays overlays;
229
230   CSingleLock lock(*m_pOverlayContainer);
231
232   VecOverlays* pVecOverlays = m_pOverlayContainer->GetOverlays();
233   VecOverlaysIter it = pVecOverlays->begin();
234
235   //Check all overlays and render those that should be rendered, based on time and forced
236   //Both forced and subs should check timing
237   while (it != pVecOverlays->end())
238   {
239     CDVDOverlay* pOverlay = *it++;
240     if(!pOverlay->bForced && !m_bRenderSubs)
241       continue;
242
243     double pts2 = pOverlay->bForced ? pts : pts - m_iSubtitleDelay;
244
245     if((pOverlay->iPTSStartTime <= pts2 && (pOverlay->iPTSStopTime > pts2 || pOverlay->iPTSStopTime == 0LL)))
246     {
247       if(pOverlay->IsOverlayType(DVDOVERLAY_TYPE_GROUP))
248         overlays.insert(overlays.end(), static_cast<CDVDOverlayGroup*>(pOverlay)->m_overlays.begin()
249                                       , static_cast<CDVDOverlayGroup*>(pOverlay)->m_overlays.end());
250       else
251         overlays.push_back(pOverlay);
252     }
253   }
254
255   for(it = overlays.begin(); it != overlays.end(); ++it)
256   {
257     double pts2 = (*it)->bForced ? pts : pts - m_iSubtitleDelay;
258     g_renderManager.AddOverlay(*it, pts2);
259   }
260 }
261
262 std::string OMXPlayerVideo::GetStereoMode()
263 {
264   std::string  stereo_mode;
265
266   switch(CMediaSettings::Get().GetCurrentVideoSettings().m_StereoMode)
267   {
268     case RENDER_STEREO_MODE_SPLIT_VERTICAL:   stereo_mode = "left_right"; break;
269     case RENDER_STEREO_MODE_SPLIT_HORIZONTAL: stereo_mode = "top_bottom"; break;
270     default:                                  stereo_mode = m_hints.stereo_mode; break;
271   }
272
273   if(CMediaSettings::Get().GetCurrentVideoSettings().m_StereoInvert)
274     stereo_mode = GetStereoModeInvert(stereo_mode);
275   return stereo_mode;
276 }
277
278 void OMXPlayerVideo::Output(double pts, bool bDropPacket)
279 {
280   if (!g_renderManager.IsStarted()) {
281     CLog::Log(LOGINFO, "%s - renderer not started", __FUNCTION__);
282     return;
283   }
284
285   if (CThread::m_bStop)
286     return;
287
288   // we aim to submit subtitles 100ms early
289   const double preroll = DVD_MSEC_TO_TIME(100);
290   double media_pts = m_av_clock->OMXMediaTime();
291
292   if (m_nextOverlay != DVD_NOPTS_VALUE && media_pts + preroll <= m_nextOverlay)
293     return;
294
295   int buffer = g_renderManager.WaitForBuffer(CThread::m_bStop);
296   if (buffer < 0)
297     return;
298
299   double subtitle_pts = m_nextOverlay;
300   double time = subtitle_pts != DVD_NOPTS_VALUE ? subtitle_pts - media_pts : 0.0;
301
302   m_nextOverlay = NextOverlay(media_pts);
303
304   ProcessOverlays(media_pts);
305
306   time += m_av_clock->GetAbsoluteClock();
307   g_renderManager.FlipPage(CThread::m_bStop, time/DVD_TIME_BASE);
308 }
309
310 static unsigned count_bits(int32_t value)
311 {
312   unsigned bits = 0;
313   for(;value;++bits)
314     value &= value - 1;
315   return bits;
316 }
317
318 void OMXPlayerVideo::Process()
319 {
320   double frametime = (double)DVD_TIME_BASE / m_fFrameRate;
321   bool bRequestDrop = false;
322
323   m_videoStats.Start();
324
325   while(!m_bStop)
326   {
327     CDVDMsg* pMsg;
328     int iQueueTimeOut = (int)(m_stalled ? frametime / 4 : frametime * 10) / 1000;
329     int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0;
330     MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, iQueueTimeOut, iPriority);
331
332     if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT)
333     {
334       CLog::Log(LOGERROR, "OMXPlayerVideo: Got MSGQ_IS_ERROR(%d) Aborting", (int)ret);
335       break;
336     }
337     else if (ret == MSGQ_TIMEOUT)
338     {
339       continue;
340     }
341
342     if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE))
343     {
344       if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait(100, SYNCSOURCE_VIDEO))
345       {
346         CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_SYNCHRONIZE");
347
348       }
349       else
350         m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */
351
352       pMsg->Release();
353
354       continue;
355     }
356     else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC))
357     {
358       CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg;
359
360       double delay = 0;
361
362       if(pMsgGeneralResync->m_clock && pMsgGeneralResync->m_timestamp != DVD_NOPTS_VALUE)
363       {
364         CLog::Log(LOGDEBUG, "CDVDPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f, %f, 1)", m_iCurrentPts, pMsgGeneralResync->m_timestamp);
365         m_av_clock->Discontinuity(pMsgGeneralResync->m_timestamp - delay);
366       }
367       else
368         CLog::Log(LOGDEBUG, "CDVDPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f, 0)", m_iCurrentPts);
369
370       m_nextOverlay = DVD_NOPTS_VALUE;
371       m_iCurrentPts = DVD_NOPTS_VALUE;
372       pMsgGeneralResync->Release();
373       continue;
374     }
375     else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY))
376     {
377       double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value;
378       CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_DELAY(%f)", timeout);
379     }
380     else if (pMsg->IsType(CDVDMsg::VIDEO_SET_ASPECT))
381     {
382       m_fForcedAspectRatio = *((CDVDMsgDouble*)pMsg);
383       CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::VIDEO_SET_ASPECT %.2f", m_fForcedAspectRatio);
384     }
385     else if (pMsg->IsType(CDVDMsg::GENERAL_RESET))
386     {
387       CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESET");
388       m_omxVideo.Reset();
389       m_started = false;
390       m_nextOverlay = DVD_NOPTS_VALUE;
391       m_iCurrentPts = DVD_NOPTS_VALUE;
392     }
393     else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (COMXPlayerVideo::Flush())
394     {
395       CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_FLUSH");
396       m_stalled = true;
397       m_started = false;
398       m_nextOverlay = DVD_NOPTS_VALUE;
399       m_iCurrentPts = DVD_NOPTS_VALUE;
400       m_omxVideo.Reset();
401       m_flush = false;
402     }
403     else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED))
404     {
405       if (m_speed != static_cast<CDVDMsgInt*>(pMsg)->m_value)
406       {
407         m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value;
408         CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::PLAYER_SETSPEED %d", m_speed);
409       }
410     }
411     else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED))
412     {
413       CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::PLAYER_STARTED %d", m_started);
414       if(m_started)
415         m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO));
416     }
417     else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME))
418     {
419       COMXPlayer::SPlayerState& state = ((CDVDMsgType<COMXPlayer::SPlayerState>*)pMsg)->m_value;
420       double pts = m_iCurrentPts;
421       double stamp = m_av_clock->OMXMediaTime();
422
423       if(state.time_src == COMXPlayer::ETIMESOURCE_CLOCK)
424         state.time      = stamp == 0.0 ? state.time : DVD_TIME_TO_MSEC(stamp + state.time_offset);
425       else
426         state.time      = stamp == 0.0 || pts == DVD_NOPTS_VALUE ? state.time : state.time + DVD_TIME_TO_MSEC(stamp - pts);
427       state.timestamp = m_av_clock->GetAbsoluteClock();
428       state.player    = DVDPLAYER_VIDEO;
429       m_messageParent.Put(pMsg->Acquire());
430     }
431     else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE))
432     {
433       COMXMsgVideoCodecChange* msg(static_cast<COMXMsgVideoCodecChange*>(pMsg));
434       OpenStream(msg->m_hints, msg->m_codec);
435       msg->m_codec = NULL;
436     }
437     else if (pMsg->IsType(CDVDMsg::GENERAL_EOF))
438     {
439       CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_EOF");
440       SubmitEOS();
441     }
442     else if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
443     {
444       DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket();
445       bool bPacketDrop     = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop();
446
447       #ifdef _DEBUG
448       CLog::Log(LOGINFO, "Video: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d\n", pPacket->dts, pPacket->pts, 
449           (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, 0);
450       #endif
451       if (m_messageQueue.GetDataSize() == 0
452       ||  m_speed < 0)
453       {
454         bRequestDrop = false;
455       }
456
457       // if player want's us to drop this packet, do so nomatter what
458       if(bPacketDrop)
459         bRequestDrop = true;
460
461       m_omxVideo.SetDropState(bRequestDrop);
462
463       while (!m_bStop)
464       {
465         // discard if flushing as clocks may be stopped and we'll never submit it
466         if (m_flush)
467            break;
468
469         if((int)m_omxVideo.GetFreeSpace() < pPacket->iSize)
470         {
471           Sleep(10);
472           continue;
473         }
474   
475         if (m_stalled)
476         {
477           CLog::Log(LOGINFO, "COMXPlayerVideo - Stillframe left, switching to normal playback");
478           m_stalled = false;
479         }
480
481         // some packed bitstream AVI files set almost all pts values to DVD_NOPTS_VALUE, but have a scattering of real pts values.
482         // the valid pts values match the dts values.
483         // if a stream has had more than 4 valid pts values in the last 16, the use UNKNOWN, otherwise use dts
484         m_history_valid_pts = (m_history_valid_pts << 1) | (pPacket->pts != DVD_NOPTS_VALUE);
485         double pts = pPacket->pts;
486         if(pPacket->pts == DVD_NOPTS_VALUE && count_bits(m_history_valid_pts & 0xffff) < 4)
487           pts = pPacket->dts;
488
489         if (pts != DVD_NOPTS_VALUE)
490           pts += m_iVideoDelay;
491
492         m_omxVideo.Decode(pPacket->pData, pPacket->iSize, pts);
493         Output(pts, bRequestDrop);
494         if(pts != DVD_NOPTS_VALUE)
495           m_iCurrentPts = pts;
496
497         if(m_started == false)
498         {
499           m_codecname = m_omxVideo.GetDecoderName();
500           m_started = true;
501           m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO));
502         }
503
504         break;
505       }
506
507       bRequestDrop = false;
508
509       m_videoStats.AddSampleBytes(pPacket->iSize);
510     }
511     pMsg->Release();
512
513   }
514 }
515
516 void OMXPlayerVideo::Flush()
517 {
518   m_flush = true;
519   m_messageQueue.Flush();
520   m_messageQueue.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH), 1);
521 }
522
523 bool OMXPlayerVideo::OpenDecoder()
524 {
525   if(!m_av_clock)
526     return false;
527
528   if (m_hints.fpsrate && m_hints.fpsscale)
529     m_fFrameRate = DVD_TIME_BASE / OMXClock::NormalizeFrameduration((double)DVD_TIME_BASE * m_hints.fpsscale / m_hints.fpsrate);
530   else
531     m_fFrameRate = 25;
532
533   if( m_fFrameRate > 100 || m_fFrameRate < 5 )
534   {
535     CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder : Invalid framerate %d, using forced 25fps and just trust timestamps\n", (int)m_fFrameRate);
536     m_fFrameRate = 25;
537   }
538   // use aspect in stream if available
539   if (m_hints.forced_aspect)
540     m_fForcedAspectRatio = m_hints.aspect;
541   else
542     m_fForcedAspectRatio = 0.0;
543
544   bool bVideoDecoderOpen = m_omxVideo.Open(m_hints, m_av_clock, CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode, m_hdmi_clock_sync);
545   m_omxVideo.RegisterResolutionUpdateCallBack((void *)this, ResolutionUpdateCallBack);
546
547   if(!bVideoDecoderOpen)
548   {
549     CLog::Log(LOGERROR, "OMXPlayerVideo : Error open video output");
550     m_omxVideo.Close();
551   }
552   else
553   {
554     CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder : Video codec %s width %d height %d profile %d fps %f\n",
555         m_omxVideo.GetDecoderName().c_str() , m_hints.width, m_hints.height, m_hints.profile, m_fFrameRate);
556
557     m_codecname = m_omxVideo.GetDecoderName();
558
559     // if we are closer to ntsc version of framerate, let gpu know
560     int   iFrameRate  = (int)(m_fFrameRate + 0.5f);
561     bool  bNtscFreq  = fabs(m_fFrameRate * 1001.0f / 1000.0f - iFrameRate) < fabs(m_fFrameRate - iFrameRate);
562     char  response[80], command[80];
563     sprintf(command, "hdmi_ntsc_freqs %d", bNtscFreq);
564     CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder fps: %f %s\n", m_fFrameRate, command);
565     m_DllBcmHost.vc_gencmd(response, sizeof response, command);
566
567     m_av_clock->SetRefreshRate(m_fFrameRate);
568   }
569
570   // start from assuming all recent frames had valid pts
571   m_history_valid_pts = ~0;
572
573   return bVideoDecoderOpen;
574 }
575
576 int  OMXPlayerVideo::GetDecoderBufferSize()
577 {
578   return m_omxVideo.GetInputBufferSize();
579 }
580
581 int  OMXPlayerVideo::GetDecoderFreeSpace()
582 {
583   return m_omxVideo.GetFreeSpace();
584 }
585
586 void OMXPlayerVideo::SubmitEOS()
587 {
588   m_omxVideo.SubmitEOS();
589 }
590
591 bool OMXPlayerVideo::SubmittedEOS()
592 {
593   return m_omxVideo.SubmittedEOS();
594 }
595
596 bool OMXPlayerVideo::IsEOS()
597 {
598   return m_omxVideo.IsEOS();
599 }
600
601 void OMXPlayerVideo::SetSpeed(int speed)
602 {
603   if(m_messageQueue.IsInited())
604     m_messageQueue.Put( new CDVDMsgInt(CDVDMsg::PLAYER_SETSPEED, speed), 1 );
605   else
606     m_speed = speed;
607 }
608
609 std::string OMXPlayerVideo::GetPlayerInfo()
610 {
611   std::ostringstream s;
612   s << "fr:"     << fixed << setprecision(3) << m_fFrameRate;
613   s << ", vq:"   << setw(2) << min(99,GetLevel()) << "%";
614   s << ", dc:"   << m_codecname;
615   s << ", Mb/s:" << fixed << setprecision(2) << (double)GetVideoBitrate() / (1024.0*1024.0);
616
617   return s.str();
618 }
619
620 int OMXPlayerVideo::GetVideoBitrate()
621 {
622   return (int)m_videoStats.GetBitrate();
623 }
624
625 double OMXPlayerVideo::GetOutputDelay()
626 {
627   double time = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET);
628   if( m_fFrameRate )
629     time = (time * DVD_TIME_BASE) / m_fFrameRate;
630   else
631     time = 0.0;
632
633   if( m_speed != 0 )
634     time = time * DVD_PLAYSPEED_NORMAL / abs(m_speed);
635
636   return time;
637 }
638
639 int OMXPlayerVideo::GetFreeSpace()
640 {
641   return m_omxVideo.GetFreeSpace();
642 }
643
644 void OMXPlayerVideo::SetVideoRect(const CRect &SrcRect, const CRect &DestRect)
645 {
646   // in 3d modes skip this - we get called as the gui switches from left eye to right eye
647   unsigned flags = GetStereoModeFlags(m_hints.stereo_mode);
648   if (CONF_FLAGS_STEREO_MODE_MASK(flags))
649     return;
650
651   // check if destination rect or video view mode has changed
652   if ((m_dst_rect != DestRect) || (m_view_mode != CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode))
653   {
654     m_dst_rect  = DestRect;
655     m_view_mode = CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode;
656   }
657   else
658   {
659     return;
660   }
661
662   // might need to scale up m_dst_rect to display size as video decodes
663   // to separate video plane that is at display size.
664   CRect gui, display, dst_rect;
665   RESOLUTION res = g_graphicsContext.GetVideoResolution();
666   gui.SetRect(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iWidth, CDisplaySettings::Get().GetResolutionInfo(res).iHeight);
667   display.SetRect(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth, CDisplaySettings::Get().GetResolutionInfo(res).iScreenHeight);
668   
669   dst_rect = m_dst_rect;
670   if (gui != display)
671   {
672     float xscale = display.Width()  / gui.Width();
673     float yscale = display.Height() / gui.Height();
674     dst_rect.x1 *= xscale;
675     dst_rect.x2 *= xscale;
676     dst_rect.y1 *= yscale;
677     dst_rect.y2 *= yscale;
678   }
679   m_omxVideo.SetVideoRect(SrcRect, dst_rect);
680 }
681
682 void OMXPlayerVideo::RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, const CRect &DestRect)
683 {
684   OMXPlayerVideo *player = (OMXPlayerVideo*)ctx;
685   player->SetVideoRect(SrcRect, DestRect);
686 }
687
688 void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, float display_aspect)
689 {
690   RESOLUTION res  = g_graphicsContext.GetVideoResolution();
691   uint32_t video_width   = CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth;
692   uint32_t video_height  = CDisplaySettings::Get().GetResolutionInfo(res).iScreenHeight;
693
694   unsigned flags = 0;
695   ERenderFormat format = RENDER_FMT_BYPASS;
696
697   if(m_bAllowFullscreen)
698   {
699     flags |= CONF_FLAGS_FULLSCREEN;
700     m_bAllowFullscreen = false; // only allow on first configure
701   }
702
703   flags |= GetStereoModeFlags(m_hints.stereo_mode);
704
705   if(flags & CONF_FLAGS_STEREO_MODE_SBS)
706   {
707     if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DSBS))
708       CLog::Log(LOGNOTICE, "3DSBS movie found");
709     else
710     {
711       flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0);
712       CLog::Log(LOGNOTICE, "3DSBS movie found but not supported");
713     }
714   }
715   else if(flags & CONF_FLAGS_STEREO_MODE_TAB)
716   {
717     if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DTB))
718       CLog::Log(LOGNOTICE, "3DTB movie found");
719     else
720     {
721       flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0);
722       CLog::Log(LOGNOTICE, "3DTB movie found but not supported");
723     }
724   }
725   else
726     CLog::Log(LOGNOTICE, "not a 3D movie");
727
728   unsigned int iDisplayWidth  = width;
729   unsigned int iDisplayHeight = height;
730
731   /* use forced aspect if any */
732   if( m_fForcedAspectRatio != 0.0f )
733     iDisplayWidth = (int) (iDisplayHeight * m_fForcedAspectRatio);
734   else if( display_aspect != 0.0f )
735     iDisplayWidth = (int) (iDisplayHeight * display_aspect);
736
737   CLog::Log(LOGDEBUG,"%s - change configuration. video:%dx%d. framerate: %4.2f. %dx%d format: BYPASS",
738       __FUNCTION__, video_width, video_height, m_fFrameRate, iDisplayWidth, iDisplayHeight);
739
740   if(!g_renderManager.Configure(width, height,
741         iDisplayWidth, iDisplayHeight, m_fFrameRate, flags, format, 0,
742         m_hints.orientation, 0))
743   {
744     CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__);
745     return;
746   }
747
748   g_renderManager.RegisterRenderUpdateCallBack((const void*)this, RenderUpdateCallBack);
749 }
750
751 void OMXPlayerVideo::ResolutionUpdateCallBack(void *ctx, uint32_t width, uint32_t height, float display_aspect)
752 {
753   OMXPlayerVideo *player = static_cast<OMXPlayerVideo*>(ctx);
754   player->ResolutionUpdateCallBack(width, height, display_aspect);
755 }
756