#ifndef __MPlayerControl2__ #define __MPlayerControl2__ #include "misc/defs.h" #include "Thread.h" //#define MPLAYER_EXE "c:\\progs\\mplayer\\mplayer.exe" //#define MPLAYER_EXE2 "c:\\Coding\\download\\MPlayer-1.0pre5\\mplayer.exe" class MPlayerControl2 : public Thread { String m_MPlayerPath; HANDLE m_hMPlayer; HANDLE m_hMPlayerInput; HANDLE m_hMPlayerOutput; bool m_bStarted; uint m_PlayTime; bool m_bPaused; bool m_bDoQuit; public: MPlayerControl2() : m_hMPlayer(NULL) , m_hMPlayerInput(NULL) , m_hMPlayerOutput(NULL) , m_bStarted(false) , m_PlayTime(0) { } ~MPlayerControl2() { Quit(); } bool Init(const String& _path) { m_MPlayerPath = _path; if (FileInfo().CreateFromPath(_path)) return true; fprintf(stderr, "[ERROR] MPlayerControl2: '%s' not found\n", _path.Str()); return false; } bool IsRunning() const { return ::GetProcessId(m_hMPlayer) != 0; } bool IsPaused() const { return m_bPaused; } bool IsPlaying() const { return IsRunning() && !IsPaused(); } uint GetPlayTime() const { return m_PlayTime; } bool HasQuit() { if (m_bStarted && !IsRunning()) { m_bStarted = false; CloseHandles(); return true; } return false; } bool SendCommand(const char* _pCommand) { if (IsRunning()) { char buf[100]; snprintf(buf, 100, "%s\n", _pCommand); ulong n, len = strlen(buf); return (::WriteFile(m_hMPlayerInput, buf, len, &n, NULL) != 0); } return false; } void Quit() { SendCommand("quit"); m_bDoQuit = true; while (Thread::IsRunning()) ::Sleep(10); m_bStarted = false; m_bDoQuit = false; //CloseHandles(); } void Stop() { Quit(); } void TogglePause() { SendCommand("pause"); } void Play() { if (IsPaused()) TogglePause(); } void Pause() { if (!IsPaused()) TogglePause(); } void VolumeDown() { SendCommand("volume -1"); } void VolumeUp() { SendCommand("volume 1"); } void Rewind() { SendCommand("seek -10"); } void FastForward() { SendCommand("seek +10"); } void ToggleDisplay() { SendCommand("osd"); SendCommand("osd"); } //TODO: send argument instead void SkipBackward() { SendCommand("seek -600"); } void SkipForward() { SendCommand("seek 600"); } void ToggleSubtitles() { SendCommand("sub_visibility"); } void PlayNewSong(const char* _pFilename) { char buf[1000]; snprintf(buf, 1000, "loadfile \"%s\"", _pFilename); for (int i=0; buf[i]; i++) if (buf[i] == '\\') buf[i] = '/'; if (!SendCommand(buf)) Launch_Music(_pFilename); } bool Launch_Music(const char* _pFilename) { Quit(); char command[1000]; snprintf(command, sizeof(command), "%s -slave \"%s\"", m_MPlayerPath.Str(), _pFilename); return Launch(command); } bool Launch_Movie(const char* _pFilename, bool _bWidescreen) { Quit(); char command[1000]; snprintf(command, sizeof(command), "%s -slave -fs -monitoraspect %s \"%s\"", m_MPlayerPath.Str(), _bWidescreen ? "16:9" : "4:3", _pFilename); return Launch(command); } bool Launch(char* _pCmd) { SECURITY_ATTRIBUTES saAttr; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; // Create handle for reading parent <- child HANDLE hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup; if (!::CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) return false; if (!::DuplicateHandle(::GetCurrentProcess(), hChildStdoutRd, ::GetCurrentProcess(), &hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS)) return false; ::CloseHandle(hChildStdoutRd); // Create handle for writing parent -> child HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup; if (!::CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) return false; if (!::DuplicateHandle(::GetCurrentProcess(), hChildStdinWr, ::GetCurrentProcess(), &hChildStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS)) return false; ::CloseHandle(hChildStdinWr); // Create process PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdError = hChildStdoutWr; siStartInfo.hStdOutput = hChildStdoutWr; siStartInfo.hStdInput = hChildStdinRd; siStartInfo.dwFlags |= STARTF_USESTDHANDLES; BOOL bFuncRetn = ::CreateProcess(NULL, _pCmd, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &siStartInfo, &piProcInfo); if (bFuncRetn == 0) return false; ::CloseHandle(piProcInfo.hThread); m_hMPlayer = piProcInfo.hProcess; m_hMPlayerInput = hChildStdinWrDup; m_hMPlayerOutput = hChildStdoutRdDup; ::SetPriorityClass(m_hMPlayer, HIGH_PRIORITY_CLASS); Thread::Start(); m_bStarted = true; return true; } void CloseHandles() { if (m_hMPlayer) ::CloseHandle(m_hMPlayer); if (m_hMPlayerInput) ::CloseHandle(m_hMPlayerInput); if (m_hMPlayerOutput) ::CloseHandle(m_hMPlayerOutput); m_hMPlayer = NULL; m_hMPlayerInput = NULL; m_hMPlayerOutput = NULL; } static bool ReadLine(HANDLE hFile, char* buf, int size) { ulong nRead; int i; for (i=0; i<(size-2); i++) { if (!::ReadFile(hFile, buf+i, 1, &nRead, NULL) || !nRead) return false; if (buf[i] == '\r' || buf[i] == '\n') break; } buf[i+1] = 0; return true; } virtual int DoWork() // Started from Thread::Start() { char buf[200]; while (!m_bDoQuit && IsRunning()) { if (!m_hMPlayerOutput || !ReadLine(m_hMPlayerOutput, buf, sizeof(buf))) break; if (strncasecmp(buf, "Exiting", 7) == 0) break; else if (strncasecmp(buf, " ===== PAUSE =====", 21) == 0) { fprintf(stderr, "[INFO] paused\n"); m_bPaused = true; } else if (strncmp(buf, "A:", 2) == 0) { if (m_bPaused) fprintf(stderr, "[INFO] unpaused\n"); m_bPaused = false; int m, s, t; if (sscanf(buf+2, "%d:%02d.%d ", &m, &s, &t) == 3) m_PlayTime = 60*m + s; else if (sscanf(buf+2, "%d.%d ", &s, &t) == 2) m_PlayTime = s; else fprintf(stderr, "UNKNOWN FORMAT: [%s]\n", buf); } else if (!String::IsSpace(buf[0])) { m_PlayTime = 0; } } fprintf(stderr, "[INFO] MPlayerControl2 thread done\n"); CloseHandles(); return 0; } }; #endif