[XBOX] fixed: ticket #5926 - Smallstep in MPlayer doesn't work properly.
[xbmc:xbmc-antiquated.git] / xbmc / cores / mplayer / mplayer.cpp
1
2
3 #include "stdafx.h"
4 #include "mplayer.h"
5 #include "cores/DllLoader/DllLoader.h"
6 #include "DllMPlayer.h"
7 #include "cores/dlgcache.h"
8 #include "Util.h"
9 #include "FileSystem/FileShoutcast.h"
10 #include "FileSystem/FileSmb.h"
11 #include "XBAudioConfig.h"
12 #include "XBVideoConfig.h"
13 #include "langcodeexpander.h"
14 #include "VideoDatabase.h"
15 #include "utils/GUIInfoManager.h"
16 #include "cores/VideoRenderers/RenderManager.h"
17 #include "utils/win32exception.h"
18 #include "cores/DllLoader/exports/emu_registry.h"
19 #include "Settings.h"
20 #include "FileItem.h"
21
22 using namespace std;
23 using namespace XFILE;
24
25 #define KEY_ENTER 13
26 #define KEY_TAB 9
27
28 #define KEY_BASE 0x100
29
30 /*  Function keys  */
31 #define KEY_F (KEY_BASE+64)
32
33 /* Control keys */
34 #define KEY_CTRL (KEY_BASE)
35 #define KEY_BACKSPACE (KEY_CTRL+0)
36 #define KEY_DELETE (KEY_CTRL+1)
37 #define KEY_INSERT (KEY_CTRL+2)
38 #define KEY_HOME (KEY_CTRL+3)
39 #define KEY_END (KEY_CTRL+4)
40 #define KEY_PAGE_UP (KEY_CTRL+5)
41 #define KEY_PAGE_DOWN (KEY_CTRL+6)
42 #define KEY_ESC (KEY_CTRL+7)
43
44 /* Control keys short name */
45 #define KEY_BS KEY_BACKSPACE
46 #define KEY_DEL KEY_DELETE
47 #define KEY_INS KEY_INSERT
48 #define KEY_PGUP KEY_PAGE_UP
49 #define KEY_PGDOWN KEY_PAGE_DOWN
50 #define KEY_PGDWN KEY_PAGE_DOWN
51
52 /* Cursor movement */
53 #define KEY_CRSR (KEY_BASE+16)
54 #define KEY_RIGHT (KEY_CRSR+0)
55 #define KEY_LEFT (KEY_CRSR+1)
56 #define KEY_DOWN (KEY_CRSR+2)
57 #define KEY_UP (KEY_CRSR+3)
58
59 /* XF86 Multimedia keyboard keys */
60 #define KEY_XF86_BASE (0x100+384)
61 #define KEY_XF86_PAUSE (KEY_XF86_BASE+1)
62 #define KEY_XF86_STOP (KEY_XF86_BASE+2)
63 #define KEY_XF86_PREV (KEY_XF86_BASE+3)
64 #define KEY_XF86_NEXT (KEY_XF86_BASE+4)
65
66 /* Keypad keys */
67 #define KEY_KEYPAD (KEY_BASE+32)
68 #define KEY_KP0 (KEY_KEYPAD+0)
69 #define KEY_KP1 (KEY_KEYPAD+1)
70 #define KEY_KP2 (KEY_KEYPAD+2)
71 #define KEY_KP3 (KEY_KEYPAD+3)
72 #define KEY_KP4 (KEY_KEYPAD+4)
73 #define KEY_KP5 (KEY_KEYPAD+5)
74 #define KEY_KP6 (KEY_KEYPAD+6)
75 #define KEY_KP7 (KEY_KEYPAD+7)
76 #define KEY_KP8 (KEY_KEYPAD+8)
77 #define KEY_KP9 (KEY_KEYPAD+9)
78 #define KEY_KPDEC (KEY_KEYPAD+10)
79 #define KEY_KPINS (KEY_KEYPAD+11)
80 #define KEY_KPDEL (KEY_KEYPAD+12)
81 #define KEY_KPENTER (KEY_KEYPAD+13)
82
83 //Transforms a string into a language code used by dvd's
84 #define DVDLANGCODE(x) ((int)(x[1]|(x[0]<<8)))
85
86 void xbox_audio_do_work();
87 void xbox_audio_wait_completion();
88 void audio_pause();
89 void audio_resume();
90
91 extern void tracker_free_mplayer_dlls(void);
92 extern CFileShoutcast* m_pShoutCastRipper;
93 extern "C" void dllReleaseAll( );
94
95 const char * dvd_audio_stream_types[8] =
96   { "ac3", "unknown", "mpeg1", "mpeg2ext", "lpcm", "unknown", "dts" };
97
98 const char * dvd_audio_stream_channels[6] =
99   { "mono", "stereo", "unknown", "unknown", "5.1/6.1", "5.1" };
100
101 static CDlgCache* m_dlgCache = NULL;
102 static CCriticalSection s_dlgCacheSection;
103
104 #define MPLAYERBACKBUFFER 20
105
106 CMPlayer::Options::Options()
107 {
108   m_bResampleAudio = false;
109   m_bNoCache = false;
110   m_fPrefil = -1.0;
111   m_bNoIdx = false;
112   m_iChannels = 0;
113   m_bAC3PassTru = false;
114   m_bDTSPassTru = false;
115   m_strChannelMapping = "";
116   m_fVolumeAmplification = 0.0f;
117   m_bNonInterleaved = false;
118   m_fSpeed = 1.0f;
119   m_fFPS = 0.0f;
120   m_iAutoSync = -1;
121   m_bForceIndex = false;
122
123   m_iAudioStream = -1;
124   m_iSubtitleStream = -1;
125
126   m_strDvdDevice = "";
127   m_strFlipBiDiCharset = "";
128   m_strHexRawAudioFormat = "";
129
130   m_bLimitedHWAC3 = false;
131   m_bDeinterlace = false;
132   m_subcp = "";
133   m_strEdl = "";
134   m_synccomp = -1.0f;
135 }
136 void CMPlayer::Options::SetFPS(float fFPS)
137 {
138   m_fFPS = fFPS;
139 }
140 float CMPlayer::Options::GetFPS() const
141 {
142   return m_fFPS;
143 }
144
145 bool CMPlayer::Options::GetNoCache() const
146 {
147   return m_bNoCache;
148 }
149 void CMPlayer::Options::SetNoCache(bool bOnOff)
150 {
151   m_bNoCache = bOnOff;
152 }
153
154 bool CMPlayer::Options::GetNoIdx() const
155 {
156   return m_bNoIdx;
157 }
158
159 void CMPlayer::Options::SetNoIdx(bool bOnOff)
160 {
161   m_bNoIdx = bOnOff;
162 }
163
164 void CMPlayer::Options::SetSpeed(float fSpeed)
165 {
166   m_fSpeed = fSpeed;
167 }
168 float CMPlayer::Options::GetSpeed() const
169 {
170   return m_fSpeed;
171 }
172
173 bool CMPlayer::Options::GetNonInterleaved() const
174 {
175   return m_bNonInterleaved;
176 }
177 void CMPlayer::Options::SetNonInterleaved(bool bOnOff)
178 {
179   m_bNonInterleaved = bOnOff;
180 }
181
182 bool CMPlayer::Options::GetForceIndex() const
183 {
184   return m_bForceIndex;
185 }
186
187 void CMPlayer::Options::SetForceIndex(bool bOnOff)
188 {
189   m_bForceIndex = bOnOff;
190 }
191
192
193 int CMPlayer::Options::GetAudioStream() const
194 {
195   return m_iAudioStream;
196 }
197 void CMPlayer::Options::SetAudioStream(int iStream)
198 {
199   m_iAudioStream = iStream;
200 }
201
202 int CMPlayer::Options::GetSubtitleStream() const
203 {
204   return m_iSubtitleStream;
205 }
206
207 void CMPlayer::Options::SetSubtitleStream(int iStream)
208 {
209   m_iSubtitleStream = iStream;
210 }
211
212 float CMPlayer::Options::GetVolumeAmplification() const
213 {
214   return m_fVolumeAmplification;
215 }
216
217 void CMPlayer::Options::SetVolumeAmplification(float fDB)
218 {
219   if (fDB < -200.0f) fDB = -200.0f;
220   if (fDB > 60.0f) fDB = 60.0f;
221   m_fVolumeAmplification = fDB;
222 }
223
224
225 int CMPlayer::Options::GetChannels() const
226 {
227   return m_iChannels;
228 }
229 void CMPlayer::Options::SetChannels(int iChannels)
230 {
231   m_iChannels = iChannels;
232 }
233
234 bool CMPlayer::Options::GetAC3PassTru()
235 {
236   return m_bAC3PassTru;
237 }
238 void CMPlayer::Options::SetAC3PassTru(bool bOnOff)
239 {
240   m_bAC3PassTru = bOnOff;
241 }
242
243 bool CMPlayer::Options::GetDTSPassTru()
244 {
245   return m_bDTSPassTru;
246 }
247 void CMPlayer::Options::SetDTSPassTru(bool bOnOff)
248 {
249   m_bDTSPassTru = bOnOff;
250 }
251
252 bool CMPlayer::Options::GetLimitedHWAC3()
253 {
254   return m_bLimitedHWAC3;
255 }
256 void CMPlayer::Options::SetLimitedHWAC3(bool bOnOff)
257 {
258   m_bLimitedHWAC3 = bOnOff;
259 }
260
261 const string CMPlayer::Options::GetChannelMapping() const
262 {
263   return m_strChannelMapping;
264 }
265
266 void CMPlayer::Options::SetChannelMapping(const string& strMapping)
267 {
268   m_strChannelMapping = strMapping;
269 }
270
271 void CMPlayer::Options::SetDVDDevice(const string & strDevice)
272 {
273   m_strDvdDevice = strDevice;
274 }
275
276 void CMPlayer::Options::SetFlipBiDiCharset(const string& strCharset)
277 {
278   m_strFlipBiDiCharset = strCharset;
279 }
280
281 void CMPlayer::Options::SetRawAudioFormat(const string& strHexRawAudioFormat)
282 {
283   m_strHexRawAudioFormat = strHexRawAudioFormat;
284 }
285
286 void CMPlayer::Options::SetAutoSync(int iAutoSync)
287 {
288   m_iAutoSync = iAutoSync;
289 }
290
291 void CMPlayer::Options::SetEdl(const string& strEdl)
292 {
293   m_strEdl = strEdl;
294 }
295
296 void CMPlayer::Options::GetOptions(int& argc, char* argv[])
297 {
298   CStdString strTmp;
299   m_vecOptions.erase(m_vecOptions.begin(), m_vecOptions.end());
300   m_vecOptions.push_back("xbmc.exe");
301
302 #ifdef PROFILE
303   m_vecOptions.push_back("-benchmark");
304   m_vecOptions.push_back("-nosound");
305 #endif
306
307   // enable direct rendering (mplayer directly draws on xbmc's overlay texture)
308   m_vecOptions.push_back("-dr");
309   if (m_strHexRawAudioFormat.length() > 0)
310   {
311     m_vecOptions.push_back("-rawaudio");
312     m_vecOptions.push_back("on:format=" + m_strHexRawAudioFormat); //0x2000
313   }
314
315   if (LOG_LEVEL_NORMAL == g_advancedSettings.m_logLevel)
316     m_vecOptions.push_back("-quiet");
317   else
318     m_vecOptions.push_back("-v");
319
320   if (m_bNoCache)
321     m_vecOptions.push_back("-nocache");
322
323   if (m_fPrefil >= 0.0)
324   {
325     strTmp.Format("%2.4f", m_fPrefil);
326     m_vecOptions.push_back("-cache-min");
327     m_vecOptions.push_back(strTmp);
328     m_vecOptions.push_back("-cache-prefill");
329     m_vecOptions.push_back(strTmp);
330   }
331
332   if (m_bNoIdx)
333   {
334     m_vecOptions.push_back("-noidx");
335   }
336
337   if (m_subcp.length() > 0)
338   {
339     if (m_subcp == "utf8")
340     {
341       // force utf8 as default charset
342       m_vecOptions.push_back("-utf8");
343       CLog::Log(LOGINFO, "Forcing utf8 charset for subtitle. Setting -utf8");
344     }
345     else 
346     {
347       /* try to autodetect any multicharacter charset */
348       /* then fallback to user specified charset */
349       m_vecOptions.push_back("-subcp");
350       strTmp.Format("enca:__:%s", m_subcp.c_str());
351       m_vecOptions.push_back(strTmp);
352       CLog::Log(LOGINFO, "Using -subcp %s to detect the subtitle charset", strTmp.c_str());
353     }
354   }
355
356   if (m_strEdl.length() > 0)
357   {
358     m_vecOptions.push_back("-edl");
359     m_vecOptions.push_back( m_strEdl.c_str());
360   }
361
362   //MOVED TO mplayer.conf
363   //Enable mplayer's internal highly accurate sleeping.
364   //m_vecOptions.push_back("-softsleep");
365
366   //limit A-V sync correction in order to get smoother playback.
367   //defaults to 0.01 but for high quality videos 0.0001 results in
368   // much smoother playback but slow reaction time to fix A-V desynchronization
369   //m_vecOptions.push_back("-mc");
370   //m_vecOptions.push_back("0.0001");
371
372   if (m_synccomp >= 0.0f)
373   {
374     m_vecOptions.push_back("-mc");
375     strTmp.Format("%2.4f", m_synccomp);
376     m_vecOptions.push_back(strTmp);
377   }
378   // smooth out audio driver timer (audio drivers arent perect)
379   //Higher values mean more smoothing,but avoid using numbers too high,
380   //as they will cause independent timing from the sound card and may result in
381   //an A-V desync
382   //m_vecOptions.push_back("-autosync");
383   //m_vecOptions.push_back("30");
384
385   if (m_fSpeed != 1.0f)
386   {
387     // set playback speed
388     m_vecOptions.push_back("-speed");
389     strTmp.Format("%f", m_fSpeed);
390     m_vecOptions.push_back(strTmp);
391   }
392   //This shouldn't be set as then the speed adjustment will be applied to this new fps, and not original.
393   //Video will play way to fast, while audio will play correctly, so mplayer will constantly need to adjust.
394   //Should only be set on videos that has wrong header info
395   if( m_fFPS != 0.0f )
396   {
397     m_vecOptions.push_back("-fps");
398     strTmp.Format("%f", m_fFPS);
399     m_vecOptions.push_back(strTmp);
400
401     // set subtitle fps
402     m_vecOptions.push_back("-subfps");
403     strTmp.Format("%f", m_fFPS);
404     m_vecOptions.push_back(strTmp);
405   }
406
407   if ( m_iAudioStream >= 0)
408   {
409     CLog::Log(LOGINFO, " Playing audio stream: %d", m_iAudioStream);
410     m_vecOptions.push_back("-aid");
411     strTmp.Format("%i", m_iAudioStream);
412     m_vecOptions.push_back(strTmp);
413   }
414
415   if ( m_iSubtitleStream >= 0)
416   {
417     CLog::Log(LOGINFO, " Playing subtitle stream: %d", m_iSubtitleStream);
418     m_vecOptions.push_back("-sid");
419     strTmp.Format("%i", m_iSubtitleStream);
420     m_vecOptions.push_back(strTmp);
421   }
422   //MOVED TO mplayer.conf to allow it to be overridden on a per file basis
423   // else
424   // {
425   //Force mplayer to allways allocate a subtitle demuxer, otherwise we
426   //might not be able to enable it later. Will make sure later that it isn't visible.
427   //For after 1.0 add command to ask for a specific language as an alternative.
428   //m_vecOptions.push_back("-sid");
429   //m_vecOptions.push_back("0");
430   // }
431
432   if ( m_iChannels)
433   {
434     // set number of audio channels
435     m_vecOptions.push_back("-channels");
436     strTmp.Format("%i", m_iChannels);
437     m_vecOptions.push_back(strTmp);
438   }
439   if ( m_strChannelMapping.size())
440   {
441     // set audio channel mapping
442     m_vecOptions.push_back("-af");
443     m_vecOptions.push_back(m_strChannelMapping);
444   }
445
446   if (m_iAutoSync >= 0)
447   {
448     // Enable autosync
449     m_vecOptions.push_back("-autosync");
450     strTmp.Format("%i", m_iAutoSync);
451     m_vecOptions.push_back(strTmp);
452   }
453
454   if ( m_bAC3PassTru || m_bDTSPassTru)
455   {
456     // this is nice, we can ask mplayer to try hwac3 filter (used for ac3/dts pass-through) first
457     // and if it fails try a52 filter (used for ac3 software decoding) and if that fails
458     // try the other audio codecs (mp3, wma,...)
459     m_vecOptions.push_back("-ac");
460     CStdString buf;
461
462     if (m_bDTSPassTru) buf += "hwdts,";
463     if (m_bAC3PassTru) buf += "hwac3,";
464     m_vecOptions.push_back(buf.c_str());
465
466   }
467   else
468   { // TODO: add a gui option instead of just using "1"? (how applicable is this though?)
469     // dynamic range compression for ac3/dts
470     m_vecOptions.push_back("-a52drc");
471     m_vecOptions.push_back("1");
472   }
473   if ( m_bLimitedHWAC3 )
474     m_vecOptions.push_back("-limitedhwac3");
475
476   if (m_strFlipBiDiCharset.length() > 0)
477   {
478     CLog::Log(LOGINFO, "Flipping bi-directional subtitles in charset %s", m_strFlipBiDiCharset.c_str());
479     m_vecOptions.push_back("-fribidi-charset");
480     m_vecOptions.push_back(m_strFlipBiDiCharset.c_str());
481     m_vecOptions.push_back("-flip-hebrew");
482   }
483   else
484   {
485     CLog::Log(LOGINFO, "Flipping bi-directional subtitles disabled");
486     m_vecOptions.push_back("-noflip-hebrew");
487     m_vecOptions.push_back("-noflip-hebrew-commas");
488   }
489
490   
491   { //Setup any video filter we want, ie postprocessing, noise...
492     strTmp.Empty();
493     vector<CStdString> vecPPOptions;
494
495     if ( m_bDeinterlace )
496     {
497       vecPPOptions.push_back("ci");
498     }
499
500     if ( g_guiSettings.GetBool("postprocessing.enable") )
501     {
502       if (g_guiSettings.GetBool("postprocessing.auto"))
503       {
504         // enable auto quality &postprocessing
505         m_vecOptions.push_back("-autoq");
506         m_vecOptions.push_back("100");
507
508         //Just add an empty string so we know we need to add the pp filter
509         vecPPOptions.push_back("default"); 
510       }
511       else
512       {
513         // manual postprocessing
514         CStdString strOpt;
515
516         if ( g_guiSettings.GetBool("postprocessing.dering") )
517         { // add dering filter
518           vecPPOptions.push_back("dr:a");
519         }
520         if (g_guiSettings.GetBool("postprocessing.verticaldeblocking"))
521         {
522           // add vertical deblocking filter
523           if (g_guiSettings.GetInt("postprocessing.verticaldeblocklevel") > 0) 
524             strOpt.Format("vb:%i", g_guiSettings.GetInt("postprocessing.verticaldeblocklevel"));
525           else 
526             strOpt = "vb:a";
527
528           vecPPOptions.push_back(strOpt);
529         }
530         if (g_guiSettings.GetBool("postprocessing.horizontaldeblocking"))
531         {
532           // add horizontal deblocking filter
533           if (g_guiSettings.GetInt("postprocessing.horizontaldeblocklevel") > 0) 
534             strOpt.Format("hb:%i", g_guiSettings.GetInt("postprocessing.horizontaldeblocklevel"));
535           else 
536             strOpt = "hb:a";
537
538           vecPPOptions.push_back(strOpt);
539         }
540         if (g_guiSettings.GetBool("postprocessing.autobrightnesscontrastlevels"))
541         {
542           // add auto brightness/contrast levels
543           vecPPOptions.push_back("al");
544         }
545       }
546     }
547
548     //Only enable post processing if something is selected
549     if (vecPPOptions.size() > 0)
550     {
551       strTmp.Empty();
552       strTmp += "pp=";
553
554       for (unsigned int i = 0; i < vecPPOptions.size(); ++i)
555       {
556         strTmp += vecPPOptions[i];
557         strTmp += "/";
558       }
559       strTmp.TrimRight("/");
560     }
561   }
562
563   if (g_stSettings.m_currentVideoSettings.m_FilmGrain > 0)
564   {
565     CStdString strOpt;
566     if (strTmp.size() > 0)
567       strTmp += ",";
568
569     strOpt.Format("noise=%dta:%dta", g_stSettings.m_currentVideoSettings.m_FilmGrain, g_stSettings.m_currentVideoSettings.m_FilmGrain);
570     strTmp += strOpt;
571   }
572
573   //Check if we wanted any video filters
574   if (strTmp.size() > 0)
575   {
576     m_vecOptions.push_back("-vf");
577     m_vecOptions.push_back(strTmp);
578   }
579
580
581   if (m_fVolumeAmplification > 0.1f || m_fVolumeAmplification < -0.1f)
582   {
583     //add volume amplification audio filter
584     strTmp.Format("volume=%2.2f:0", m_fVolumeAmplification);
585     m_vecOptions.push_back("-af");
586     m_vecOptions.push_back(strTmp);
587   }
588   //  if (m_bResampleAudio)
589   //{
590   //m_vecOptions.push_back("-af");
591   // 48kHz resampling
592   // format is: rate=sample_rate:bSloppy:quality
593   // where bSloppy is 1 if we don't care about accurate output rate
594   // and quality is:
595   //     0   - linear interpolation (fast, but bad quality)
596   //     1   - polyphase filtered with integer math
597   //     2   - polyphase filtered with float math (slowest)
598   // m_vecOptions.push_back("resample=48000:0:1");//,format=2unsignedint");
599   //}
600
601   if (m_bNonInterleaved)
602   {
603     // open file in non-interleaved way
604     m_vecOptions.push_back("-ni");
605   }
606
607   if (m_bForceIndex)
608     m_vecOptions.push_back("-forceidx");
609
610   if (m_strDvdDevice.length() > 0)
611   {
612     CStdString strDevice;
613     strDevice = """" + m_strDvdDevice;
614
615     //Make sure we only use forward slashes for path
616     //since mplayer is manly *nix based this causes less problems.
617     //Our standard file system handles this aswell.
618     strDevice.Replace("\\", "/");
619     strDevice.TrimRight("/");
620     strDevice += """";
621
622     m_vecOptions.push_back("-dvd-device");
623     m_vecOptions.push_back(strDevice);
624   }
625
626   //Only display forced subs for dvds.
627   //m_vecOptions.push_back("-forcedsubsonly");
628
629   // Turn sub delay on
630   if (g_stSettings.m_currentVideoSettings.m_SubtitleDelay != 0.0f)
631   {
632     m_vecOptions.push_back("-subdelay");
633     CStdString strOpt;
634     strOpt.Format("%2.2f", g_stSettings.m_currentVideoSettings.m_SubtitleDelay);
635     m_vecOptions.push_back(strOpt.c_str());
636   }
637
638   if( m_videooutput.length() > 0 )
639   {
640     m_vecOptions.push_back("-vo");
641     m_vecOptions.push_back(m_videooutput);
642   }
643
644   if( m_audiooutput.length() > 0 )
645   {
646     m_vecOptions.push_back("-vo");
647     m_vecOptions.push_back(m_audiooutput);
648   }
649
650   if( m_videocodec.length() > 0 )
651   {
652     m_vecOptions.push_back("-vc");
653     m_vecOptions.push_back(m_videocodec);
654   }
655
656   if( m_audiocodec.length() > 0 )
657   {
658     m_vecOptions.push_back("-ac");
659     m_vecOptions.push_back(m_audiocodec);
660   }
661
662   if( m_demuxer.length() > 0 )
663   {
664     m_vecOptions.push_back("-demuxer");
665     m_vecOptions.push_back(m_demuxer);
666   }
667
668   if( m_fullscreen )
669     m_vecOptions.push_back("-fs");
670
671   m_vecOptions.push_back("1.avi");
672
673   argc = (int)m_vecOptions.size();
674   for (int i = 0; i < argc; ++i)
675   {
676     argv[i] = (char*)m_vecOptions[i].c_str();
677   }
678   argv[argc] = NULL;
679 }
680
681
682 CMPlayer::CMPlayer(IPlayerCallback& callback)
683     : IPlayer(callback)
684 {
685   m_pDLL = NULL;
686   m_bIsPlaying = false;
687   m_bPaused = false;
688   m_bIsMplayeropenfile = false;
689   m_bCaching = false;
690   m_bSubsVisibleTTF=false;
691   m_bUseFullRecaching = false;
692   m_fAVDelay = 0.0f;
693 }
694
695 CMPlayer::~CMPlayer()
696 {
697   CloseFile();
698
699   //Make sure the thread really is completly closed
700   //things will fail otherwise.
701   while(!WaitForThreadExit(2000))
702   {
703     CLog::Log(LOGWARNING, "CMPlayer::~CMPlayer() - Waiting for thread to exit...");
704   }
705
706   Unload();
707   
708   //save_registry(); //save registry to disk
709   free_registry(); //free memory take by registry structures
710 }
711
712 bool CMPlayer::load()
713 {
714   CloseFile();
715   Unload();
716   if (!m_pDLL)
717   {
718     m_pDLL = new DllLoader("Q:\\system\\players\\mplayer\\mplayer.dll", true);
719
720     if (!m_pDLL->Load())
721     {
722       CLog::Log(LOGERROR, "cmplayer::load() load failed");
723       SAFE_DELETE(m_pDLL)
724       return false;
725     }
726     mplayer_load_dll(*m_pDLL);
727   }
728   return true;
729 }
730
731 void update_cache_dialog(const char* tmp)
732 {
733   static bool bWroteOutput = false;
734   //Make sure we lock here as this is called from the cache thread thread
735   CSingleLock lock(s_dlgCacheSection);
736   if (m_dlgCache)
737   {
738     try {
739
740     CStdString message = tmp;
741     message.Trim();
742     if (int i = message.Find("Cache fill:") >= 0)
743     {
744       if (int j = message.Find('%') >= 0)
745       {
746         CStdString strPercentage = message.Mid(i + 11, j - i + 11);
747
748         //filter percentage, update progressbar
749         float fPercentage = 0;
750         sscanf(strPercentage.c_str(), "%f", &fPercentage);
751         m_dlgCache->ShowProgressBar(true);
752         //assuming here mplayer cache prefill is set to 20%...
753         m_dlgCache->SetPercentage(int(fPercentage * (100 / 20)));
754         if(!bWroteOutput)
755         {
756           m_dlgCache->SetMessage("Caching...");
757           bWroteOutput = true;
758         }
759         return;
760       }
761     }
762     else if(int i = message.Find("VobSub parsing:") >= 0)
763       if (int j = message.Find('%') >= 0)
764       {
765         CStdString strPercentage = message.Mid(i + 15, j - i + 15);
766
767         //filter percentage, update progressbar
768         int iPercentage = 0;
769         sscanf(strPercentage.c_str(), "%d", &iPercentage);
770         m_dlgCache->ShowProgressBar(true);
771         m_dlgCache->SetPercentage(iPercentage);
772         if(!bWroteOutput)
773         {
774           m_dlgCache->SetMessage("Parsing VobSub...");
775           bWroteOutput = true;
776         }
777         return;
778       }
779     else
780     {
781       m_dlgCache->ShowProgressBar(false);
782     }
783     bWroteOutput = false;
784     //Escape are identifiers for infovalues
785     message.Replace("$", "$$");
786
787     m_dlgCache->SetMessage(message);
788
789     }
790     catch(...)
791     {
792       CLog::Log(LOGERROR, "Exception in update_cache_dialog()");
793     }
794   }
795 }
796
797 extern void xbox_audio_switch_channel(int iAudioStream, bool bAudioOnAllSpeakers); //lowlevel audio
798
799 bool CMPlayer::OpenFile(const CFileItem& file, const CPlayerOptions& initoptions)
800 {
801   //Close any prevoiusely playing file
802   CloseFile();
803
804   int iRet = -1;
805   int iCacheSize = 1024;
806   bool bFileOnHD(false);
807   bool bFileOnISO(false);
808   bool bFileOnUDF(false);
809   bool bFileOnInternet(false);
810   bool bFileOnLAN(false);
811   bool bFileIsDVDImage(false);
812   bool bFileIsDVDIfoFile(false);
813   
814   starttime=0;
815   CStdString strFile = file.m_strPath;
816
817
818   /* use our own protocol for ftp to avoid using mplayer's builtin */
819   // not working well with seeking.. curl locks up for some reason. think it's the thread handover
820   // thus any requests to ftpx in curl will now be non seekable
821   if( strFile.Left(6).Equals("ftp://") )
822     strFile.replace(0, 6, "ftpx://");
823
824
825
826   CURL url(strFile);
827   if ( file.IsHD() ) bFileOnHD = true;
828   else if ( file.IsISO9660() ) bFileOnISO = true;
829   else if ( file.IsOnDVD() ) bFileOnUDF = true;
830   else if ( file.IsOnLAN() ) bFileOnLAN = true;
831   else if ( file.IsInternetStream() ) bFileOnInternet = true;  
832
833   bool bIsVideo = file.IsVideo();
834   bool bIsAudio = file.IsAudio();
835   bool bIsDVD(false);
836
837   bFileIsDVDImage = file.IsDVDImage();
838   bFileIsDVDIfoFile = file.IsDVDFile(false, true);
839
840   CLog::Log(LOGDEBUG,"file:%s IsDVDImage:%i IsDVDIfoFile:%i", strFile.c_str(), bFileIsDVDImage , bFileIsDVDIfoFile);
841   if (strFile.Find("dvd://") >= 0 || bFileIsDVDImage || bFileIsDVDIfoFile)
842   {
843     bIsDVD = true;
844     bIsVideo = true;
845   }
846
847   iCacheSize = GetCacheSize(bFileOnHD, bFileOnISO, bFileOnUDF, bFileOnInternet, bFileOnLAN, bIsVideo, bIsAudio, bIsDVD);
848   try
849   {
850     // Enable FullRecaching for "true" internet files/streams (ie. mms)
851     if (bFileOnInternet)
852     {      
853       CSingleLock lock(g_graphicsContext);
854       CSingleLock lock2(s_dlgCacheSection);
855       m_dlgCache = new CDlgCache(0);
856       m_bUseFullRecaching = true;
857     }
858     else
859     {
860       CSingleLock lock(g_graphicsContext);
861       CSingleLock lock2(s_dlgCacheSection);
862       m_dlgCache = new CDlgCache(3000);
863     }
864
865     if (iCacheSize == 0)
866       iCacheSize = -1; //let mplayer figure out what to do with the cache
867
868 //    if (bFileOnLAN || bFileOnHD)
869     // Prefill 5% if it's not an internetstream
870     if (!bFileOnInternet)  
871       options.SetPrefil(5.0);
872
873     CLog::Log(LOGINFO, "mplayer play:%s cachesize:%i", strFile.c_str(), iCacheSize);
874
875     // cache (remote) subtitles to HD
876     if (!bFileOnInternet && bIsVideo && !bIsDVD && g_stSettings.m_currentVideoSettings.m_SubtitleOn && !initoptions.identify)
877     {
878
879       m_dlgCache->SetMessage("Caching subtitles...");
880       CUtil::CacheSubtitles(strFile, _SubtitleExtension, m_dlgCache);
881       
882       if( m_dlgCache )
883       {
884         //If caching was canceled, bail here
885         if( m_dlgCache->IsCanceled() ) throw 0;
886         m_dlgCache->ShowProgressBar(false);
887       }
888
889       CUtil::PrepareSubtitleFonts();
890       g_stSettings.m_currentVideoSettings.m_SubtitleCached = true;
891     }
892     else
893       CUtil::ClearSubtitles();
894     m_iPTS = 0;
895     m_bPaused = false;
896
897     // Read EDL
898     if (!bFileOnInternet && bIsVideo && !bIsDVD )
899     {
900       if (g_guiSettings.GetBool("videoplayer.editdecision"))
901       {
902         if (m_Edl.ReadnCacheAny(strFile))
903           options.SetEdl(m_Edl.GetCachedEdl());
904       }
905     }
906     
907     // first init mplayer. This is needed 2 find out all information
908     // like audio channels, fps etc
909     load();
910
911     char *argv[30];
912     int argc = 8;
913     //Options options;
914     if (file.IsVideo())
915     {
916       options.SetNonInterleaved(g_stSettings.m_currentVideoSettings.m_NonInterleaved);
917       options.SetForceIndex(g_stSettings.m_currentVideoSettings.m_bForceIndex);
918     }
919     options.SetNoCache(g_stSettings.m_currentVideoSettings.m_NoCache);
920
921     CStdString strCharset=g_langInfo.GetSubtitleCharSet();
922     if( CUtil::IsUsingTTFSubtitles() )
923     {
924       /* we only set this if we are using ttf, since the font itself, will handle the charset */
925       /* this needed to do conversion to utf wich we expect */
926       options.SetSubtitleCharset(strCharset);
927
928       /* also we don't want to flip the subtitle since that will be handled by our rendering instead */
929     }
930     else if (g_guiSettings.GetBool("subtitles.flipbidicharset") && g_charsetConverter.isBidiCharset(strCharset))
931     {
932       options.SetFlipBiDiCharset(strCharset);
933     }
934
935     bool bSupportsAC3Out = g_audioConfig.GetAC3Enabled();
936     bool bSupportsDTSOut = g_audioConfig.GetDTSEnabled();
937
938     // shoutcast is always stereo
939     if (file.IsShoutCast() )
940     {
941       options.SetChannels(0);
942       options.SetAC3PassTru(false);
943       options.SetDTSPassTru(false);
944     }
945     else
946     {
947       //Since the xbox downmixes any multichannel track to dolby surround if we don't have a dd reciever,
948       //allways tell mplayer to output the maximum number of channels.
949       options.SetChannels(6);
950
951       // if we're using digital out
952       // then try using direct passtrough
953       if (g_guiSettings.GetInt("audiooutput.mode") == AUDIO_DIGITAL)
954       {
955         options.SetAC3PassTru(bSupportsAC3Out);
956         options.SetDTSPassTru(bSupportsDTSOut);
957
958         if ((g_stSettings.m_currentVideoSettings.m_OutputToAllSpeakers && bIsVideo) || (g_guiSettings.GetBool("musicplayer.outputtoallspeakers")) && (!bIsVideo))
959           options.SetLimitedHWAC3(true); //Will limit hwac3 to not kick in on 2.0 channel streams
960       }
961     }
962
963     // Volume amplification has been replaced with dynamic range compression
964     // TODO DRC Remove this code once we've stabilised the DRC.
965 /*    if (bIsVideo)
966     {
967       options.SetVolumeAmplification(g_stSettings.m_currentVideoSettings.m_VolumeAmplification);
968     }*/
969
970     //Make sure we set the dvd-device parameter if we are playing dvdimages or dvdfolders
971     if (bFileIsDVDImage)
972     {
973       options.SetDVDDevice(strFile);
974       CLog::Log(LOGINFO, " dvddevice: %s", strFile.c_str());
975     }
976     else if (bFileIsDVDIfoFile)
977     {
978       CStdString strPath;
979       CUtil::GetParentPath(strFile, strPath);
980       if (strPath.Equals("D:\\VIDEO_TS\\", false) || strPath.Equals("D:\\VIDEO_TS", false))
981         options.SetDVDDevice("D:\\"); //Properly mastered dvd, lets mplayer open the dvd properly
982       else
983         options.SetDVDDevice(strPath);
984       CLog::Log(LOGINFO, " dvddevice: %s", strPath.c_str());
985     }
986
987     CStdString strExtension;
988     CUtil::GetExtension(strFile, strExtension);
989     strExtension.MakeLower();
990
991
992     if (strExtension.Equals(".avi", false))
993     {
994       // check length of file, as mplayer can't handle opendml very well
995       CFile* pFile = new CFile();
996       __int64 len = 0;
997       if (pFile->Open(strFile.c_str(), true))
998       {
999         len = pFile->GetLength();
1000       }
1001       delete pFile;
1002
1003       if (len > 0x7fffffff)
1004       {
1005         // fixes large opendml avis - mplayer can't handle big indices
1006         options.SetNoIdx(true);
1007         CLog::Log(LOGINFO, "Trying to play a large avi file. Setting -noidx");
1008       }
1009     }
1010
1011     if (file.IsRAR())
1012     {
1013       options.SetNoIdx(true);
1014       CLog::Log(LOGINFO, "Trying to play a rar file (%s). Setting -noidx", strFile.c_str());
1015       // -noidx enables mplayer to play an .avi file from a streaming source that is not seekable.
1016       // it tells mplayer to _not_ try getting the avi index from the end of the file.
1017       // this option is enabled if we try play video from a rar file, as there is a modified version
1018       // of ccxstream which sends unrared data when you request the first .rar of a movie.
1019       // This means you can play a movie gaplessly from 50 rar files without unraring, which is neat.
1020     }
1021 #if 0 // sadly, libavformat is much worse at detecting that we actually have a nsv stream.
1022       // and there is no way to force it.
1023
1024     // libavformats demuxer is better than the internal mplayers
1025     // this however also causes errors if mplayer.dll doesn't have libavformat
1026     if (file.GetContentType().Equals("video/nsv", false)
1027       || url.GetOptions().Equals(";stream.nsv", false))
1028     {
1029       options.SetDemuxer("35"); // libavformat
1030       options.SetSyncSpeed(1); // number of seconds per frame mplayer is allowed to correct
1031     }
1032 #endif
1033     //Make sure we remeber what subtitle stream and audiostream we where playing so that stacked items gets the same.
1034     //These will be reset in Application.Playfile if the restart parameter isn't set.
1035     if (g_stSettings.m_currentVideoSettings.m_AudioStream >= 0)
1036       options.SetAudioStream(g_stSettings.m_currentVideoSettings.m_AudioStream);
1037
1038     if (g_stSettings.m_currentVideoSettings.m_SubtitleStream >= 0)
1039       options.SetSubtitleStream(g_stSettings.m_currentVideoSettings.m_SubtitleStream);
1040
1041
1042     //force mplayer to play ac3 and dts files with correct codec
1043     if (strExtension == ".ac3")
1044     {
1045       options.SetRawAudioFormat("0x2000");
1046     }
1047     else if (strExtension == ".dts")
1048     {
1049       options.SetRawAudioFormat("0x2001");
1050     }
1051
1052     //Enable smoothing of audio clock to create smoother playback.
1053     //This is now done in mplayer.conf
1054     //if( g_guiSettings.GetBool("filters.useautosync") )
1055     //  options.SetAutoSync(30);
1056
1057     if( g_stSettings.m_currentVideoSettings.m_InterlaceMethod == VS_INTERLACEMETHOD_DEINTERLACE )
1058       options.SetDeinterlace(true);
1059     else
1060       options.SetDeinterlace(false);
1061
1062
1063     if(initoptions.identify)
1064     {
1065       options.SetVideoOutput("null");
1066       options.SetAudioOutput("null");
1067       options.SetVideoCodec("null");
1068       options.SetAudioCodec("null");
1069       options.SetNoCache(true);
1070     }
1071
1072     options.SetFullscreen(initoptions.fullscreen);
1073
1074     options.GetOptions(argc, argv);
1075
1076
1077     //CLog::Log(LOGINFO, "  open 1st time");
1078
1079     mplayer_init(argc, argv);
1080     mplayer_setcache_size(iCacheSize);
1081     mplayer_setcache_backbuffer(MPLAYERBACKBUFFER);
1082     mplayer_SlaveCommand("osd 0");    
1083
1084     if (bFileIsDVDImage || bFileIsDVDIfoFile)
1085     {
1086       m_bIsMplayeropenfile = true;
1087       iRet = mplayer_open_file(GetDVDArgument(strFile).c_str());
1088     }
1089     else
1090     {
1091       m_bIsMplayeropenfile = true;
1092       iRet = mplayer_open_file(strFile.c_str());
1093     }
1094     if (iRet <= 0 || (m_dlgCache && m_dlgCache->IsCanceled()))
1095     {
1096       throw iRet;
1097     }
1098
1099     // Set the correct starting position
1100     if (initoptions.starttime) 
1101     {
1102       starttime = (__int64)(initoptions.starttime);
1103     }
1104
1105     if (bFileOnInternet || initoptions.identify)
1106     {
1107       // for streaming we're done.
1108     }
1109     else
1110     {
1111       // for other files, check the codecs/audio channels etc etc...
1112       char strFourCC[10], strVidFourCC[10];
1113       char strAudioCodec[128], strVideoCodec[128];
1114       long lBitRate;
1115       long lSampleRate;
1116       int iChannels;
1117       BOOL bVBR;
1118       float fFPS;
1119       unsigned int iWidth;
1120       unsigned int iHeight;
1121       long lFrames2Early;
1122       long lFrames2Late;
1123       bool bNeed2Restart = false;
1124
1125       // get the audio & video info from the file
1126       mplayer_GetAudioInfo(strFourCC, strAudioCodec, &lBitRate, &lSampleRate, &iChannels, &bVBR);
1127       mplayer_GetVideoInfo(strVidFourCC, strVideoCodec, &fFPS, &iWidth, &iHeight, &lFrames2Early, &lFrames2Late);
1128
1129
1130       // do we need 2 do frame rate conversions ?
1131       if (g_guiSettings.GetInt("videoplayer.framerateconversions") == FRAME_RATE_CONVERT && file.IsVideo() )
1132       {
1133         if (g_videoConfig.HasPAL())
1134         {
1135           // PAL. Framerate for pal=25.0fps
1136           // do frame rate conversions for NTSC movie playback under PAL
1137           if (fFPS >= 23.0 && fFPS <= 24.5f )
1138           {
1139             // 23.978  fps -> 25fps frame rate conversion
1140             options.SetSpeed(25.0f / fFPS);
1141             options.SetAC3PassTru(false);
1142             options.SetDTSPassTru(false);
1143             bNeed2Restart = true;
1144             CLog::Log(LOGINFO, "  --restart cause we use ntsc->pal framerate conversion");
1145           }
1146         }
1147         else
1148         {
1149           //NTSC framerate=23.976 fps
1150           // do frame rate conversions for PAL movie playback under NTSC
1151           if (fFPS >= 24 && fFPS <= 25.5)
1152           {
1153             options.SetSpeed(23.976f / fFPS);
1154             options.SetAC3PassTru(false);
1155             options.SetDTSPassTru(false);
1156             bNeed2Restart = true;
1157             CLog::Log(LOGINFO, "  --restart cause we use pal->ntsc framerate conversion");
1158           }
1159         }
1160       }
1161       // check if the codec is AC3 or DTS
1162       bool bDTS = strstr(strAudioCodec, "DTS") != 0;
1163       bool bAC3 = strstr(strAudioCodec, "AC3") != 0;
1164
1165
1166       if (lSampleRate != 48000 && (bAC3 || bDTS)) //Fallback if we run into a weird ac3/dts track.
1167       {
1168         options.SetAC3PassTru(false);
1169         options.SetDTSPassTru(false);
1170         bNeed2Restart = true;
1171       }
1172
1173       //Solve 3/5/>6 channels issue, all AC3/DTS passthrough exception code need place before
1174       //this block, because here we need decisive answer to passthrough or not.
1175       //bNeed2Restart Catch those SPDIF codec need to restart case, when restart they changed
1176       //to none passthrough mode
1177       if ( strstr(strAudioCodec, "SPDIF") == 0 || bNeed2Restart)
1178         if ( iChannels == 5 || iChannels > 6 )
1179         {
1180           options.SetChannelMapping("channels=6");
1181           bNeed2Restart = true;
1182         }
1183         else if ( iChannels == 3 )
1184         {
1185           options.SetChannelMapping("channels=4");
1186           bNeed2Restart = true;
1187         }
1188
1189       if (bNeed2Restart)
1190       {
1191         CLog::Log(LOGINFO, "  --------------- restart ---------------");
1192         //CLog::Log(LOGINFO, "  open 2nd time");
1193         if (m_bIsMplayeropenfile)
1194         {
1195           m_bIsMplayeropenfile = false;
1196           mplayer_close_file();
1197         }
1198         options.GetOptions(argc, argv);
1199         load();
1200
1201         mplayer_init(argc, argv);
1202         mplayer_setcache_size(iCacheSize);
1203         mplayer_setcache_backbuffer(MPLAYERBACKBUFFER);
1204         mplayer_SlaveCommand("osd 0");
1205
1206         if (bFileIsDVDImage || bFileIsDVDIfoFile)
1207         {
1208           m_bIsMplayeropenfile = true;
1209           iRet = mplayer_open_file(GetDVDArgument(strFile).c_str());
1210         }
1211         else
1212         {
1213           m_bIsMplayeropenfile = true;
1214           iRet = mplayer_open_file(strFile.c_str());
1215         }
1216         if (iRet <= 0 || (m_dlgCache && m_dlgCache->IsCanceled()))
1217         {
1218           throw iRet;
1219         }
1220         // Set the correct starting position
1221         if (initoptions.starttime) 
1222         {
1223           starttime = (__int64)(initoptions.starttime);
1224         }
1225       }
1226     }
1227
1228     // set up defaults
1229     SetSubtitleVisible(g_stSettings.m_currentVideoSettings.m_SubtitleOn);
1230     SetAVDelay(g_stSettings.m_currentVideoSettings.m_AudioDelay);
1231
1232     if (g_stSettings.m_currentVideoSettings.m_AudioStream < -1)
1233     { // check + fix up the stereo/left/right setting
1234       bool bAudioOnAllSpeakers = (g_guiSettings.GetInt("audiooutput.mode") == AUDIO_DIGITAL) && ((g_stSettings.m_currentVideoSettings.m_OutputToAllSpeakers && HasVideo()) || (g_guiSettings.GetBool("musicplayer.outputtoallspeakers") && !HasVideo()));
1235       xbox_audio_switch_channel(-1 - g_stSettings.m_currentVideoSettings.m_AudioStream, bAudioOnAllSpeakers);
1236     }
1237     bIsVideo = HasVideo();
1238     bIsAudio = HasAudio();
1239
1240
1241     //Close progress dialog completly without fade if this is video.
1242     if( m_dlgCache && bIsVideo)
1243     {
1244       // grab the graphicscontext lock, as we're closing a dialog
1245       CSingleLock lock(g_graphicsContext);
1246       // also grab the cache dialog's lock, to ensure that printf() can't do anything untoward
1247       CSingleLock lock2(s_dlgCacheSection);
1248       m_dlgCache->Close(true); 
1249       m_dlgCache = NULL;
1250     }
1251
1252     m_bIsPlaying = true;
1253     if ( ThreadHandle() == NULL)
1254     {
1255       Create();
1256     }
1257
1258   }
1259   catch(int e)
1260   {
1261     CLog::Log(LOGERROR, __FUNCTION__" %s failed with code %d", strFile.c_str(), e);
1262     iRet=-1;
1263     CloseFile();
1264     Unload();
1265   }
1266   catch (win32_exception &e)
1267   {
1268     e.writelog(__FUNCTION__);
1269     iRet=-1;
1270     CloseFile();
1271     Unload();
1272   }
1273
1274   if( m_dlgCache )
1275   {
1276     // lock graphics context, as we're closing a dialog
1277     CSingleLock lock(g_graphicsContext);
1278
1279     // Also lock the cache dialog so that mplayer is not using the the object
1280     CSingleLock lock2(s_dlgCacheSection);
1281     //Only call Close, the object will be deleted when it's thread ends.
1282     //this makes sure the object is not deleted while in use
1283     m_dlgCache->Close(false); 
1284     m_dlgCache = NULL;
1285   }
1286
1287   // mplayer return values:
1288   // -1 internal error
1289   // 0  try next file (eg. file doesn't exitst)
1290   // 1  successfully started playing
1291   return (iRet > 0);
1292 }
1293
1294 bool CMPlayer::CloseFile()
1295 {
1296   CLog::Log(LOGNOTICE, "CMPlayer::CloseFile()");
1297   
1298   if( m_bIsPlaying )
1299   {
1300     StopThread();
1301     m_bIsPlaying = false;
1302   }
1303
1304   //Check if file is still open
1305   if(m_bIsMplayeropenfile)
1306   { //Attempt to let mplayer clean up after it self
1307     try
1308     {
1309       m_bIsMplayeropenfile = false;
1310       mplayer_close_file();
1311     }
1312     catch(...)
1313     {
1314       char buf[255];
1315       mplayer_get_current_module(buf, 255);
1316       CLog::Log(LOGERROR, "CMPlayer::CloseFile() - Unknown Exception in mplayer_close_file() - %s", buf);
1317     }
1318   }
1319
1320   return true;
1321 }
1322
1323 bool CMPlayer::IsPlaying() const
1324 {
1325   return m_bIsPlaying;
1326 }
1327
1328
1329 void CMPlayer::OnStartup()
1330 {}
1331
1332 void CMPlayer::OnExit()
1333 {}
1334
1335 void CMPlayer::Process()
1336 {
1337   bool bHasVideo = HasVideo();
1338   bool bWaitingRestart = false;
1339   CThread::SetName("MPlayer");
1340
1341   if (!m_pDLL || !m_bIsPlaying) return;
1342
1343   m_callback.OnPlayBackStarted();
1344
1345   int exceptionCount = 0;
1346   time_t mark = time(NULL);
1347   bool FirstLoop = true;
1348
1349   do
1350   {
1351     try
1352     {
1353       if (!m_bPaused)
1354       {
1355
1356         //Set audio delay we wish to use, since mplayer 
1357         //does the sleeping for us, we present as soon as possible
1358         //so mplayer has to take presentation delay into account
1359         mplayer_setAVDelay(m_fAVDelay + g_renderManager.GetPresentDelay() * 0.001f );
1360
1361         // we're playing
1362         int iRet = mplayer_process();
1363
1364         //Set to notify that we are out of the process loop
1365         //can be used to syncronize seeking
1366         m_evProcessDone.Set();
1367
1368         if (iRet < 0) break;
1369
1370         __int64 iPTS = mplayer_get_pts();
1371         if (iPTS)
1372         {
1373           m_iPTS = iPTS;
1374         }
1375
1376         if (FirstLoop)
1377         {
1378           FirstLoop = false;
1379           // Resume from starttime, if specified
1380           if (starttime) SeekTime( starttime*1000 );
1381         }  
1382       }
1383       else // we're paused
1384       {
1385         Sleep(100);
1386       }
1387
1388       //Only count forward buffer as part of buffer level
1389       //Cachelevel will be set to 0 when decoder has to wait for more data
1390       //Cachelevel will be negative if the current mplayer.dll doesn't support it
1391       m_CacheLevel = mplayer_GetCacheLevel() * 100 / (100 - MPLAYERBACKBUFFER);
1392       if (m_bUseFullRecaching && !options.GetNoCache() && m_CacheLevel >= 0)
1393       {
1394         if(!m_bPaused && !m_bCaching && m_CacheLevel==0 )
1395         {
1396           m_bCaching=true;
1397           Pause();
1398         }
1399         else if( m_bPaused && m_bCaching && m_CacheLevel > 85 )
1400         {
1401           m_bCaching=false;
1402           Pause();
1403         }
1404       }
1405
1406       //Check to see we are not rendering text subtitles internal
1407       if( CUtil::IsUsingTTFSubtitles() && mplayer_SubtitleVisible() && mplayer_isTextSubLoaded())
1408       {
1409         mplayer_showSubtitle(false);
1410         m_bSubsVisibleTTF=true;
1411       }
1412       
1413       if( (options.GetDeinterlace() && g_stSettings.m_currentVideoSettings.m_InterlaceMethod != VS_INTERLACEMETHOD_DEINTERLACE) 
1414         || (!options.GetDeinterlace() && g_stSettings.m_currentVideoSettings.m_InterlaceMethod == VS_INTERLACEMETHOD_DEINTERLACE) )
1415       {
1416         if( !bWaitingRestart )
1417         {
1418           //We need to restart now as interlacing mode has changed
1419           bWaitingRestart = true;
1420           g_applicationMessenger.MediaRestart(false);
1421         }
1422       }
1423
1424       //Let other threads do something, should mplayer be occupying full cpu
1425       //Sleep(0);
1426     }
1427     catch (...)
1428     {
1429       // TODO: Check for the out of memory condition.
1430       // We should add detection for out of memory here.
1431
1432       char module[100];
1433       mplayer_get_current_module(module, sizeof(module));
1434       CLog::Log(LOGERROR, "mplayer generated exception in %s", module);
1435       //CLog::Log(LOGERROR, "mplayer generated exception!");
1436       exceptionCount++;
1437
1438       // bad codec detection
1439       if (FirstLoop) break;
1440
1441     }
1442
1443     if (exceptionCount > 0)
1444     {
1445       time_t t = time(NULL);
1446       if (t != mark)
1447       {
1448         mark = t;
1449         exceptionCount--;
1450       }
1451     }
1452   }
1453   while ((!m_bStop) && (exceptionCount < 5));
1454
1455   if (!m_bStop)
1456   {
1457     xbox_audio_wait_completion();
1458   }
1459   _SubtitleExtension.Empty();
1460   
1461   //Set m_bIsPlaying to false here to make sure closefile doesn't try to close the file again
1462   m_bIsPlaying = false;
1463   CloseFile();
1464
1465   if (m_bStop)
1466     m_callback.OnPlayBackStopped();
1467   else
1468     m_callback.OnPlayBackEnded();
1469 }
1470
1471 void CMPlayer::Unload()
1472 {
1473   if (m_pDLL)
1474   {
1475     //Make sure we stop playback before unloading
1476     CloseFile();
1477     try
1478     {
1479       delete m_pDLL;
1480       dllReleaseAll( );
1481       m_pDLL = NULL;
1482     }
1483     catch(std::exception& e)
1484     {
1485       CLog::Log(LOGERROR, "CMPlayer::Unload() - Exception: %s", e.what());
1486     }
1487     catch(...)
1488     {
1489       CLog::Log(LOGERROR, "CMPlayer::Unload() - Unknown Exception");
1490     }
1491   }
1492 }
1493
1494 void CMPlayer::Pause()
1495 {
1496   if (!m_bPaused)
1497   {
1498     m_bPaused = true;
1499     if (!HasVideo())
1500       audio_pause();
1501   }
1502   else
1503   {
1504     m_bPaused = false;
1505     m_bCaching = false;
1506     if (!HasVideo())
1507       audio_resume();
1508     mplayer_ToFFRW(1); //Tell mplayer we have resumed playback
1509   }
1510 }
1511
1512 bool CMPlayer::IsPaused() const
1513 {
1514   return m_bPaused;
1515 }
1516
1517 bool CMPlayer::HasVideo() const
1518 {
1519   return (mplayer_HasVideo() == TRUE);
1520 }
1521
1522 bool CMPlayer::HasAudio() const
1523 {
1524   return (mplayer_HasAudio() == TRUE);
1525 }
1526
1527 void CMPlayer::Seek(bool bPlus, bool bLargeStep)
1528 {
1529   // Use relative time seeking if we dont know the length of the video
1530   // or its explicitly enabled, and the length is alteast twice the size of the largest forward seek value
1531   int iSeek=0;
1532
1533   if(m_bPaused && bPlus && !bLargeStep)
1534   {
1535     mplayer_SlaveCommand("frame_step");
1536     mplayer_process();
1537     return;
1538   }
1539
1540   __int64 iTime = GetTotalTime();
1541
1542   if ((iTime == 0) || (g_advancedSettings.m_videoUseTimeSeeking && iTime > 2*g_advancedSettings.m_videoTimeSeekForwardBig))
1543   {
1544     if (bLargeStep)
1545     {
1546       iSeek= bPlus ? g_advancedSettings.m_videoTimeSeekForwardBig : g_advancedSettings.m_videoTimeSeekBackwardBig;
1547     }
1548     else
1549     {
1550       iSeek= bPlus ? g_advancedSettings.m_videoTimeSeekForward : g_advancedSettings.m_videoTimeSeekBackward;
1551     }
1552
1553     if (m_Edl.HaveCutpoints())
1554       SeekTime(GetTime() + iSeek*1000);
1555     else
1556       SeekRelativeTime(iSeek);
1557   }
1558   else
1559   {
1560     int percent;
1561     if (bLargeStep)
1562       percent = bPlus ? g_advancedSettings.m_videoPercentSeekForwardBig : g_advancedSettings.m_videoPercentSeekBackwardBig;
1563     else
1564       percent = bPlus ? g_advancedSettings.m_videoPercentSeekForward : g_advancedSettings.m_videoPercentSeekBackward;
1565
1566     //If current time isn't bound by the total time, 
1567     //we have to seek using absolute percentage instead
1568     if( GetTime() > iTime * 1000 )
1569     {
1570       //TODO EDL compensation for this?
1571       SeekPercentage(GetPercentage()+percent);
1572     }
1573     else
1574     {
1575       // time based seeking
1576       float timeInSecs = percent * 0.01f * iTime;
1577       
1578       //Seek a minimum of 1 second
1579       if( timeInSecs < 1 && timeInSecs > 0 )
1580         timeInSecs = 1;
1581       else if( timeInSecs > -1 && timeInSecs < 0 )
1582         timeInSecs = -1;
1583
1584       iSeek=(int)timeInSecs;
1585
1586       if (m_Edl.HaveCutpoints())
1587         SeekTime(GetTime() + iSeek*1000);
1588       else
1589         SeekRelativeTime(iSeek);
1590     }    
1591   }
1592 }
1593
1594 bool CMPlayer::SeekScene(bool bPlus)
1595 {
1596   __int64 iScenemarker;
1597   if( m_Edl.HaveScenes() && m_Edl.SeekScene(bPlus,&iScenemarker) )
1598   {
1599     SeekTime(m_Edl.RemoveCutTime(iScenemarker));
1600     return true;
1601   }
1602   return false;
1603 }
1604
1605 void CMPlayer::SeekRelativeTime(int iSeconds)
1606 {
1607   CStdString strCommand;
1608   strCommand.Format("seek %+i 0",iSeconds);
1609   mplayer_SlaveCommand(strCommand.c_str());
1610   WaitOnCommand();
1611 }
1612
1613 void CMPlayer::ToggleFrameDrop()
1614 {
1615   mplayer_put_key('d');
1616 }
1617
1618 void CMPlayer::SetVolume(long nVolume)
1619 {
1620   mplayer_setVolume(nVolume);
1621 }
1622
1623 void CMPlayer::SetDynamicRangeCompression(long drc)
1624 {
1625   mplayer_setDRC(drc);
1626 }
1627
1628 void CMPlayer::GetAudioInfo( CStdString& strAudioInfo)
1629 {
1630   char strFourCC[10];
1631   char strAudioCodec[128];
1632   long lBitRate;
1633   long lSampleRate;
1634   int iChannels;
1635   BOOL bVBR;
1636   if (!m_bIsPlaying || !mplayer_HasAudio())
1637   {
1638     strAudioInfo = "";
1639     return ;
1640   }
1641   mplayer_GetAudioInfo(strFourCC, strAudioCodec, &lBitRate, &lSampleRate, &iChannels, &bVBR);
1642   float fSampleRate = ((float)lSampleRate) / 1000.0f;
1643   if (strstr(strAudioCodec, "SPDIF")) // don't state channels if passthrough (we don't know them!)
1644     strAudioInfo.Format("audio:(%s) br:%i sr:%02.2f khz",
1645                         strAudioCodec, lBitRate, fSampleRate);
1646   else
1647     strAudioInfo.Format("audio:(%s) br:%i sr:%02.2f khz chns:%i",
1648                         strAudioCodec, lBitRate, fSampleRate, iChannels);
1649 }
1650
1651 void CMPlayer::GetVideoInfo( CStdString& strVideoInfo)
1652 {
1653
1654   char strFourCC[10];
1655   char strVideoCodec[128];
1656   float fFPS;
1657   unsigned int iWidth;
1658   unsigned int iHeight;
1659   long lFrames2Early;
1660   long lFrames2Late;
1661   if (!m_bIsPlaying)
1662   {
1663     strVideoInfo = "";
1664     return ;
1665   }
1666   mplayer_GetVideoInfo(strFourCC, strVideoCodec, &fFPS, &iWidth, &iHeight, &lFrames2Early, &lFrames2Late);
1667   strVideoInfo.Format("video:%s fps:%02.2f %ix%i early/late:%i/%i",
1668                       strVideoCodec, fFPS, iWidth, iHeight, lFrames2Early, lFrames2Late);
1669 }
1670
1671
1672 void CMPlayer::GetGeneralInfo( CStdString& strVideoInfo)
1673 {
1674   long lFramesDropped;
1675   int iQuality;
1676   int iCacheFilled;
1677   float fTotalCorrection;
1678   float fAVDelay;
1679   char cEdlStatus;
1680   if (!m_bIsPlaying)
1681   {
1682     strVideoInfo = "";
1683     return ;
1684   }
1685   cEdlStatus = m_Edl.GetEdlStatus();
1686   mplayer_GetGeneralInfo(&lFramesDropped, &iQuality, &iCacheFilled, &fTotalCorrection, &fAVDelay);
1687   strVideoInfo.Format("dropped:%i Q:%i cache:%i%% ct:%2.2f edl:%c av:%2.2f",
1688                       lFramesDropped, iQuality, iCacheFilled, fTotalCorrection, cEdlStatus, fAVDelay );
1689 }
1690
1691 void CMPlayer::Update(bool bPauseDrawing)
1692 {
1693   g_renderManager.Update(bPauseDrawing);
1694 }
1695
1696 void CMPlayer::GetVideoRect(RECT& SrcRect, RECT& DestRect)
1697 {
1698   g_renderManager.GetVideoRect(SrcRect, DestRect);
1699 }
1700
1701 void CMPlayer::GetVideoAspectRatio(float& fAR)
1702 {
1703   fAR = g_renderManager.GetAspectRatio();
1704 }
1705
1706 extern void xbox_audio_registercallback(IAudioCallback* pCallback);
1707 extern void xbox_audio_unregistercallback();
1708
1709 void CMPlayer::RegisterAudioCallback(IAudioCallback* pCallback)
1710 {
1711   xbox_audio_registercallback(pCallback);
1712 }
1713
1714 void CMPlayer::UnRegisterAudioCallback()
1715 {
1716   xbox_audio_unregistercallback();
1717 }
1718
1719 bool CMPlayer::CanRecord()
1720 {
1721   if (!m_pShoutCastRipper) return false;
1722   return m_pShoutCastRipper->CanRecord();
1723 }
1724 bool CMPlayer::IsRecording()
1725 {
1726   if (!m_pShoutCastRipper) return false;
1727   return m_pShoutCastRipper->IsRecording();
1728 }
1729 bool CMPlayer::Record(bool bOnOff)
1730 {
1731   if (!m_pShoutCastRipper) return false;
1732   if (bOnOff && IsRecording()) return true;
1733   if (bOnOff == false && IsRecording() == false) return true;
1734   if (bOnOff)
1735     return m_pShoutCastRipper->Record();
1736
1737   m_pShoutCastRipper->StopRecording();
1738   return true;
1739 }
1740
1741
1742 void CMPlayer::SeekPercentage(float percent)
1743 {
1744   // No EDL compensation possible, because we don't know the total time.
1745   if (percent > 100) percent = 100;
1746   if (percent < 0) percent = 0;
1747
1748   mplayer_setPercentage( (int)percent );
1749   WaitOnCommand();
1750 }
1751
1752 float CMPlayer::GetPercentage()
1753 {
1754   if (m_Edl.HaveCutpoints())
1755     return ( (float)(100 / ((double)(GetTotalTime()*1000)/(double)GetTime())) ); 
1756
1757   return (float)mplayer_getPercentage(); 
1758 }
1759
1760
1761 void CMPlayer::SetAVDelay(float fValue)
1762 {
1763   m_fAVDelay = fValue;
1764 }
1765
1766 float CMPlayer::GetAVDelay()
1767 {
1768   return m_fAVDelay;
1769 }
1770
1771 void CMPlayer::SetSubTitleDelay(float fValue)
1772 {
1773   mplayer_setSubtitleDelay(fValue);
1774 }
1775
1776 float CMPlayer::GetSubTitleDelay()
1777 {
1778   return mplayer_getSubtitleDelay();
1779 }
1780
1781 int CMPlayer::GetSubtitleCount()
1782 {
1783   return mplayer_getSubtitleCount();
1784 }
1785
1786 bool CMPlayer::AddSubtitle(const CStdString& strSubPath)
1787 {
1788   CStdString strFile = strSubPath;
1789   strFile.Replace("\\","\\\\");
1790   mplayer_SlaveCommand("sub_load \"%s\"", strFile.c_str());
1791   return true;
1792 }
1793
1794 int CMPlayer::GetSubtitle()
1795 {
1796   return mplayer_getSubtitle();
1797 };
1798
1799 void CMPlayer::GetSubtitleName(int iStream, CStdString &strStreamName)
1800 {
1801
1802   xbmc_subtitle sub;
1803   memset(&sub, 0, sizeof(xbmc_subtitle));
1804
1805   mplayer_getSubtitleInfo(iStream, &sub);
1806
1807   if (strlen(sub.name) > 0)
1808   {
1809     if (!g_LangCodeExpander.Lookup(strStreamName, sub.name))
1810     {
1811       strStreamName = sub.name;
1812     }
1813   }
1814   else
1815   {
1816     strStreamName = "";
1817   }
1818
1819 };
1820
1821 void CMPlayer::SetSubtitle(int iStream)
1822 {
1823   mplayer_setSubtitle(iStream);
1824   options.SetSubtitleStream(iStream);
1825   g_stSettings.m_currentVideoSettings.m_SubtitleStream = iStream;
1826
1827   WaitOnCommand();
1828   if( CUtil::IsUsingTTFSubtitles() )
1829   { // wait two frames to make sure subtitle change has been handled
1830     SetSubtitleVisible(GetSubtitleVisible());
1831   }
1832 };
1833
1834 bool CMPlayer::GetSubtitleVisible()
1835 {
1836   return( m_bSubsVisibleTTF || mplayer_SubtitleVisible() != 0 );
1837 }
1838 void CMPlayer::SetSubtitleVisible(bool bVisible)
1839 {
1840   g_stSettings.m_currentVideoSettings.m_SubtitleOn = bVisible;
1841   if (CUtil::IsUsingTTFSubtitles() && mplayer_isTextSubLoaded())
1842   {
1843     m_bSubsVisibleTTF = bVisible;
1844     mplayer_showSubtitle(false);
1845   }
1846   else
1847   {
1848     m_bSubsVisibleTTF = false;
1849     mplayer_showSubtitle(bVisible);
1850   }
1851 }
1852
1853 int CMPlayer::GetAudioStreamCount()
1854 {
1855   return mplayer_getAudioStreamCount();
1856 }
1857
1858 int CMPlayer::GetAudioStream()
1859 {
1860   return mplayer_getAudioStream();
1861 }
1862
1863 void CMPlayer::GetAudioStreamName(int iStream, CStdString& strStreamName)
1864 {
1865   stream_language_t slt;
1866   memset(&slt, 0, sizeof(stream_language_t));
1867   mplayer_getAudioStreamInfo(iStream, &slt);
1868   if (slt.language != 0)
1869   {
1870     CStdString strName;
1871     if (!g_LangCodeExpander.Lookup(strName, slt.language))
1872     {
1873       strName = "UNKNOWN:";
1874       strName += (char)(slt.language >> 8) & 255;
1875       strName += (char)(slt.language & 255);
1876     }
1877
1878     strStreamName.Format("%s", strName.c_str());
1879   }
1880
1881   if(slt.type>=0)
1882   {
1883     if(!strStreamName.IsEmpty())
1884       strStreamName += " - ";
1885     strStreamName += dvd_audio_stream_types[slt.type];
1886   }
1887
1888   if(slt.channels>0)
1889     strStreamName += CStdString("(") +  dvd_audio_stream_channels[slt.channels-1] + CStdString(")");
1890 }
1891
1892 void CMPlayer::SetAudioStream(int iStream)
1893 {
1894   //Make sure we get the correct aid for the stream
1895   //Really bad way cause we need to restart and there is no good way currently to restart mplayer without onloading it first
1896   g_stSettings.m_currentVideoSettings.m_AudioStream = mplayer_getAudioStreamInfo(iStream, NULL);
1897   options.SetAudioStream(g_stSettings.m_currentVideoSettings.m_AudioStream);
1898   //we need to restart after here for change to take effect
1899   g_applicationMessenger.MediaRestart(false);
1900 }
1901
1902 bool CMPlayer::CanSeek()
1903 {
1904   return GetTotalTime() > 0;
1905 }
1906
1907 void CMPlayer::SeekTime(__int64 iTime)
1908 {
1909   // Use relative seeking for short seeks as TimeSeek doesn't work properly for that
1910   if ((iTime>GetTime() && iTime<GetTime()+30) || (iTime<GetTime() && iTime>GetTime()-30))
1911   {
1912     SeekRelativeTime(iTime-GetTime());
1913   }
1914   else  
1915   if (m_bIsPlaying)
1916   {
1917     try 
1918     {
1919       iTime=m_Edl.RestoreCutTime(iTime);
1920       mplayer_setTimeMs(iTime);
1921     }
1922     catch(win32_exception e)
1923     {
1924       e.writelog(__FUNCTION__);
1925       g_applicationMessenger.MediaStop();
1926     }
1927     g_infoManager.m_performingSeek = false;
1928     WaitOnCommand();
1929   }
1930 }
1931
1932 //Time in milleseconds
1933 __int64 CMPlayer::GetTime()
1934 {
1935   __int64 time = 0;
1936   if (m_bIsPlaying)
1937   {
1938     try 
1939     {
1940       if (HasVideo()) //As mplayer has the audio counter 10 times to big. Should be fixed
1941         time = 1000*mplayer_getCurrentTime();
1942       else
1943         time = 100*m_iPTS;
1944     }
1945     catch(win32_exception e)
1946     {
1947       e.writelog(__FUNCTION__);
1948       g_applicationMessenger.MediaStop();
1949     }
1950   }
1951
1952   if(m_Edl.HaveCutpoints())
1953     time = m_Edl.RemoveCutTime(time);
1954
1955   return time;
1956 }
1957
1958 int CMPlayer::GetTotalTime()
1959 {
1960   int time = 0;
1961   if (m_bIsPlaying)
1962   {
1963     try 
1964     {
1965       time = mplayer_getTime();
1966     }
1967     catch(win32_exception e)
1968     {
1969       e.writelog(__FUNCTION__);
1970       g_applicationMessenger.MediaStop();
1971     }
1972   }
1973
1974   if(m_Edl.HaveCutpoints())
1975     time -= (int)(m_Edl.TotalCutTime()/1000);
1976
1977   return time;
1978 }
1979
1980 void CMPlayer::ToFFRW(int iSpeed)
1981 {
1982   if (m_bIsPlaying)
1983   {
1984     try 
1985     {
1986       mplayer_ToFFRW( iSpeed);
1987     }
1988     catch(win32_exception e)
1989     {
1990       e.writelog(__FUNCTION__);
1991     }
1992   }
1993 }
1994
1995
1996 int CMPlayer::GetCacheSize(bool bFileOnHD, bool bFileOnISO, bool bFileOnUDF, bool bFileOnInternet, bool bFileOnLAN, bool bIsVideo, bool bIsAudio, bool bIsDVD)
1997 {
1998   if (g_stSettings.m_currentVideoSettings.m_NoCache) return 0;
1999
2000   if (bFileOnHD)
2001   {
2002     if ( bIsDVD ) return g_guiSettings.GetInt("cache.harddisk");
2003     if ( bIsVideo) return g_guiSettings.GetInt("cache.harddisk");
2004     if ( bIsAudio) return g_guiSettings.GetInt("cache.harddisk");
2005   }
2006   if (bFileOnISO || bFileOnUDF)
2007   {
2008     if ( bIsDVD ) return g_guiSettings.GetInt("cachedvd.dvdrom");
2009     if ( bIsVideo) return g_guiSettings.GetInt("cachevideo.dvdrom");
2010     if ( bIsAudio) return g_guiSettings.GetInt("cacheaudio.dvdrom");
2011   }
2012   if (bFileOnLAN)
2013   {
2014     if ( bIsDVD ) return g_guiSettings.GetInt("cachedvd.lan");
2015     if ( bIsVideo) return g_guiSettings.GetInt("cachevideo.lan");
2016     if ( bIsAudio) return g_guiSettings.GetInt("cacheaudio.lan");
2017   }
2018
2019   // assume bFileOnInternet
2020   if ( bIsVideo) return g_guiSettings.GetInt("cachevideo.internet");
2021   if ( bIsAudio) return g_guiSettings.GetInt("cacheaudio.internet");
2022   //File is on internet however we don't know what type.
2023   return g_guiSettings.GetInt("cacheunknown.internet");
2024   //Apperently fixes DreamBox playback.
2025   //return 4096;
2026 }
2027
2028 CStdString CMPlayer::GetDVDArgument(const CStdString& strFile)
2029 {
2030
2031   int iTitle = CUtil::GetDVDIfoTitle(strFile);
2032   if (iTitle == 0)
2033     return CStdString("dvd://");
2034   else
2035   {
2036     CStdString strBuf;
2037     strBuf.Format("dvd://%i", iTitle);
2038     return strBuf;
2039   }
2040 }
2041
2042 void CMPlayer::DoAudioWork()
2043 {
2044   xbox_audio_do_work();
2045 }
2046
2047 bool CMPlayer::GetSubtitleExtension(CStdString &strSubtitleExtension)
2048 {
2049   strSubtitleExtension = _SubtitleExtension;
2050   return (!_SubtitleExtension.IsEmpty());
2051 }
2052
2053 float CMPlayer::GetActualFPS()
2054 {
2055   char strFourCC[10];
2056   char strVideoCodec[128];
2057   float fFPS;
2058   unsigned int iWidth;
2059   unsigned int iHeight;
2060   long lFrames2Early;
2061   long lFrames2Late;
2062   mplayer_GetVideoInfo(strFourCC, strVideoCodec, &fFPS, &iWidth, &iHeight, &lFrames2Early, &lFrames2Late);
2063   return options.GetSpeed()*fFPS;
2064 }
2065
2066 bool CMPlayer::GetCurrentSubtitle(CStdString& strSubtitle)
2067 {
2068   strSubtitle = "";
2069   subtitle* sub = NULL;
2070   try 
2071   {
2072     sub = mplayer_GetCurrentSubtitle();
2073   }
2074   catch(win32_exception e)
2075   {
2076     e.writelog(__FUNCTION__);
2077   }
2078
2079   if (sub)
2080   {
2081     for (int i = 0; i < sub->lines; i++)
2082     {
2083       if (i != 0)
2084       {
2085         strSubtitle += "\n";
2086       }
2087       
2088       strSubtitle += sub->text[i];
2089     }
2090     
2091     return true;
2092   }
2093     
2094   return false;
2095
2096   
2097 }
2098
2099 bool CMPlayer::OnAction(const CAction &action)
2100 {
2101   switch(action.wID)
2102   {
2103     case ACTION_SHOW_MPLAYER_OSD:
2104     {
2105       OutputDebugString("toggle mplayer OSD\n");
2106       mplayer_put_key('o');
2107       //if (bOnoff) mplayer_showosd(1);
2108       //else mplayer_showosd(0);
2109       return true;
2110     }
2111     break;
2112   }
2113
2114   return false;
2115 }
2116
2117 void CMPlayer::WaitOnCommand()
2118 {
2119   //We are in the normal mplayer thread, return as otherwise we would
2120   //hardlock waiting for those events
2121   if( GetCurrentThreadId() == ThreadId() ) return;
2122
2123   //If we hold graphiccontext, this may stall mplayer process
2124   if( OwningCriticalSection(g_graphicsContext) ) return;
2125
2126   if( m_bPaused )
2127   {
2128     mplayer_process();
2129     mplayer_process();
2130   }
2131   else
2132   {
2133     //Wait till process has finished twice, 
2134     //otherwise we can't be sure the seek has finished
2135     m_evProcessDone.WaitMSec(1000);
2136     m_evProcessDone.WaitMSec(1000);
2137   }
2138 }