/*************************************************************************** kplayerprocess.cpp ------------------ begin : Sat Jan 11 2003 copyright : (C) 2002-2007 by kiriuja email : http://kplayer.sourceforge.net/email.html ***************************************************************************/ /*************************************************************************** * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DEBUG #define DEBUG_KPLAYER_PROCESS //#define DEBUG_KPLAYER_PROGRESS #define DEBUG_KPLAYER_HELPER //#define DEBUG_KPLAYER_LINEOUT //#define DEBUG_KPLAYER_KIOSLAVE //#define DEBUG_KPLAYER_DUMP #endif #include "kplayerprocess.h" #include "kplayerprocess.moc" #include "kplayerengine.h" #include "kplayersettings.h" #include "kplayerwidget.h" #define MIN_VIDEO_LENGTH 5 #define NO_SEEK_ORIGIN -5 #ifdef DEBUG_KPLAYER_DUMP static TQFile s_dump (TQDir::homeDirPath() + "/tdeioslave.dump"); #endif static TQRegExp re_ext ("^[A-Za-z0-9]+$"); static TQRegExp re_a_or_v ("^[AV]: *([0-9,:.-]+)"); static TQRegExp re_a_and_v ("^A: *([0-9,:.-]+) +V: *([0-9,:.-]+)"); static TQRegExp re_start ("^(?:Start playing|Starting playback|Zanm pehrvat|Starte Wiedergabe|Pbegynder afspilning| |Empezando reproduccin|Dmarre la lecture|Lejtszs indtsa|Inizio la riproduzione||재생을 시작합니다|Почнува плејбекот|Start afspelen|Starter avspilling|Zaczynam odtwarzanie|Inciando reproduo|Rulez| c|Zanam prehrva|almaya balanyor| |ʼ|\\}l)\\.\\.\\.", false); //static TQRegExp re_playing ("(?:^(?:Playing|Pehrvm|Spiele|Afspiller| |Reproduciendo|Joue|In riproduzione|Пуштено|Bezig met het afspelen van|Spiller|Odtwarzam|Reproduzindo|Rulez||Prehrvam|||b) | (?:lejtszsa||재생 중|alnyor)\\.*$)", false); static TQRegExp re_exiting ("^(?:Exiting||Konm|Beende| ?Afslutter| ?|Saliendo|Sortie|Kilpek|In uscita|λƤޤ|종료합니다.|Излегу|Bezig met afsluiten|Avslutter|Wychodz|Saindo|Ieire||Konm|klyor||˳|bhX)", false); static TQRegExp re_quit ("^(?:Exiting||Konm|Beende| ?Afslutter| ?|Saliendo|Sortie|Kilpek|In uscita|λƤޤ|종료합니다.|Излегу|Bezig met afsluiten|Avslutter|Wychodz|Saindo|Ieire||Konm|klyor||˳|bhX)\\.\\.\\. \\((?:Quit||Konec|Ende|Afslut||Salida\\.?|Fin|Kilps|Uscita|λ|종료|Откажи|Stop|Avslutt|Wyjcie|Sair|Ieire||Koniec|k|Ȧ|˳|\\})\\)", false); static TQRegExp re_success ("^(?:Exiting||Konm|Beende| ?Afslutter| ?|Saliendo|Sortie|Kilpek|In uscita|λƤޤ|մϴ|злегва|Bezig met afsluiten|Avslutter|Wychodz|Saindo|Ieire||Konm|klyor||˳|bhX)\\.\\.\\. \\((?:End of file| |Konec souboru|Ende der Datei|Slut p filen| |Fin del archivo\\.?|Fin du fichier|Vge a file-nak|Fine del file|եüǤ|파일의 끝|Крај на датотеката|Einde van bestand|Slutt p filen|Koniec pliku|Fim do arquivo|Sfrit fiier| |Koniec sboru|Dosyann Sonu| |ļ|ɮץ)\\)", false); static TQRegExp re_cache_fill ("^Cache fill: *([0-9]+[.,]?[0-9]*) *%", false); static TQRegExp re_generating_index ("^Generating Index: *([0-9]+[.,]?[0-9]*) *%", false); static TQRegExp re_mpeg12 ("mpeg[12]", false); static TQRegExp re_version ("^MPlayer *0\\.9.* \\(C\\) "); static TQRegExp re_crash ("^ID_SIGNAL=([0-9]+)$"); static TQRegExp re_paused ("^ID_PAUSED$"); static TQCString command_quit ("quit\n"); static TQCString command_pause ("pause\n"); static TQCString command_visibility ("sub_visibility\n"); static TQCString command_seek_100 ("seek 100 1\n"); static TQCString command_seek_99 ("seek 99 1\n"); static TQCString command_seek_95 ("seek 95 1\n"); static TQCString command_seek_90 ("seek 90 1\n"); static TQCString command_seek_50 ("seek 50 1\n"); KPlayerLineOutputProcess::KPlayerLineOutputProcess (void) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Creating MPlayer process\n"; #endif m_stdout_line_length = m_stderr_line_length = 0; m_stdout_buffer_length = m_stderr_buffer_length = 129; m_stdout_buffer = new char [m_stdout_buffer_length]; m_stderr_buffer = new char [m_stderr_buffer_length]; #if 0 m_merge = false; #endif connect (this, TQ_SIGNAL (receivedStdout (TDEProcess*, char*, int)), TQ_SLOT (slotReceivedStdout (TDEProcess*, char*, int))); connect (this, TQ_SIGNAL (receivedStderr (TDEProcess*, char*, int)), TQ_SLOT (slotReceivedStderr (TDEProcess*, char*, int))); } KPlayerLineOutputProcess::~KPlayerLineOutputProcess() { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Destroying MPlayer process\n"; #endif delete [] m_stdout_buffer; delete [] m_stderr_buffer; } void KPlayerLineOutputProcess::processHasExited (int state) { status = state; runs = false; commClose(); if ( m_stdout_line_length ) emit receivedStdoutLine (this, m_stdout_buffer, m_stdout_line_length); // , None if ( m_stderr_line_length ) emit receivedStderrLine (this, m_stderr_buffer, m_stderr_line_length); // , None if ( run_mode != DontCare ) emit processExited (this); } void KPlayerLineOutputProcess::slotReceivedStdout (TDEProcess* proc, char* str, int len) { #ifdef DEBUG_KPLAYER_LINEOUT kdDebugTime() << "StdOut: " << len << " '" << str << "'\n"; #endif receivedOutput (proc, str, len, m_stdout_buffer, m_stdout_buffer_length, m_stdout_line_length, true); } void KPlayerLineOutputProcess::slotReceivedStderr (TDEProcess* proc, char* str, int len) { #if 0 if ( m_merge ) slotReceivedStdout (proc, str, len); else #endif receivedOutput (proc, str, len, m_stderr_buffer, m_stderr_buffer_length, m_stderr_line_length, false); } void KPlayerLineOutputProcess::receivedOutput (TDEProcess* proc, char* str, int len, char* buf, int blen, int llen, bool bstdout) { static int avlen = 0; static char* av = 0; if ( proc != this ) return; #ifdef DEBUG_KPLAYER_LINEOUT kdDebugTime() << "stdout received length: " << len << "\n"; kdDebugTime() << llen << "/" << blen << ": " << buf << "\n"; #endif while ( len > 0 && ! str [len - 1] ) len --; while ( len > 0 ) { char* lf = (char*) memchr (str, '\n', len); if ( ! lf ) lf = str + len; char* eol = (char*) memchr (str, '\r', lf - str); if ( ! eol ) eol = lf; if ( eol - str + llen >= blen ) { char* old_buffer = buf; blen = eol - str + llen + 10; #ifdef DEBUG_KPLAYER_LINEOUT kdDebugTime() << "new buffer length: " << blen << "\n"; #endif buf = new char [blen]; if ( bstdout ) { m_stdout_buffer = buf; m_stdout_buffer_length = blen; } else { m_stderr_buffer = buf; m_stderr_buffer_length = blen; } if ( llen ) memcpy (buf, old_buffer, llen); delete[] old_buffer; } if ( eol > str ) { memcpy (buf + llen, str, eol - str); llen += eol - str; if ( bstdout ) m_stdout_line_length = llen; else m_stderr_line_length = llen; } buf [llen] = 0; if ( eol - str == len ) break; if ( av && *av && re_paused.search (buf) >= 0 ) { #ifdef DEBUG_KPLAYER_LINEOUT kdDebugTime() << "Sending AV Buffer On Pause: '" << av << "'\n"; #endif if ( bstdout ) emit receivedStdoutLine (this, av, strlen (av) - 1); else emit receivedStderrLine (this, av, strlen (av) - 1); *av = 0; } if ( re_a_or_v.search (buf) >= 0 || re_cache_fill.search (buf) >= 0 || re_generating_index.search (buf) >= 0 ) { if ( avlen <= llen ) { if ( av ) delete[] av; avlen = llen + 10; av = new char [avlen]; #ifdef DEBUG_KPLAYER_LINEOUT kdDebugTime() << "new av buffer length: " << avlen << "\n"; #endif } memcpy (av, buf, llen + 1); #ifdef DEBUG_KPLAYER_LINEOUT kdDebugTime() << "AV Buffer: '" << av << "'\n"; #endif } else if ( bstdout ) emit receivedStdoutLine (this, buf, llen); // , *cr == '\r' ? CR : LF else emit receivedStderrLine (this, buf, llen); // , *cr == '\r' ? CR : LF // if ( *buf ) // && eol == lf // { // write (STDOUT_FILENO, buf, llen); // write (STDOUT_FILENO, "\n", 1); // } #ifdef DEBUG_KPLAYER_LINEOUT kdDebugTime() << "Buffer: '" << buf << "'\n"; #endif llen = 0; if ( bstdout ) m_stdout_line_length = llen; else m_stderr_line_length = llen; len -= eol - str + 1; str = eol + 1; } if ( av && *av ) { #ifdef DEBUG_KPLAYER_LINEOUT kdDebugTime() << "Sending AV Buffer: '" << av << "'\n"; #endif if ( bstdout ) emit receivedStdoutLine (this, av, strlen (av) - 1); else emit receivedStderrLine (this, av, strlen (av) - 1); *av = 0; } //kdDebugTime() << "normal return\n"; } inline KPlayerSettings* KPlayerProcess::settings (void) const { return KPlayerEngine::engine() -> settings(); } inline KPlayerTrackProperties* KPlayerProcess::properties (void) const { return settings() -> properties(); } inline KPlayerConfiguration* KPlayerProcess::configuration (void) const { return KPlayerEngine::engine() -> configuration(); } KPlayerProcess::KPlayerProcess (void) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Creating process\n"; #endif m_player = m_helper = 0; m_temporary_file = 0; m_state = Idle; m_pausing = m_paused = m_quit = m_kill = m_seek = m_success = m_size_sent = m_info_available = false; m_delayed_player = m_delayed_helper = m_sent = m_send_seek = false; m_seekable = m_09_version = m_first_chunk = false; m_position = m_max_position = m_helper_position = 0; m_seek_origin = NO_SEEK_ORIGIN; m_helper_seek = m_helper_seek_count = m_absolute_seek = m_seek_count = m_sent_count = m_cache_size = 0; m_slave_job = m_temp_job = 0; m_send_volume = m_send_contrast = m_send_brightness = m_send_hue = m_send_saturation = false; m_send_frame_drop = m_send_audio_id = m_send_subtitle_load = m_send_subtitle_visibility = false; m_send_audio_delay = m_send_subtitle_delay = m_send_subtitle_position = 0; m_audio_delay = m_subtitle_delay = m_subtitle_position = 0; m_audio_id = m_subtitle_index = -1; m_send_subtitle_index = -2; m_subtitle_visibility = true; m_fifo_handle = -1; m_fifo_offset = 0; m_fifo_notifier = 0; m_fifo_timer = 0; TQString home (TQDir::homeDirPath()); TQDir (home).mkdir (".mplayer"); m_cache.setAutoDelete (true); } KPlayerProcess::~KPlayerProcess() { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Destroying process\n"; #endif if ( m_player ) delete m_player; if ( m_helper ) delete m_helper; if ( m_slave_job ) m_slave_job -> kill (true); if ( m_temp_job ) m_temp_job -> kill (true); if ( m_temporary_file ) { m_temporary_file -> close(); m_temporary_file -> unlink(); delete m_temporary_file; } removeDataFifo(); } void KPlayerProcess::transferTemporaryFile (void) { if ( properties() -> useKioslave() && properties() -> useTemporaryFile() && ! m_temporary_file ) { TQFileInfo fi (properties() -> url().fileName()); TQString extension (fi.extension(false).lower()); if ( ! extension.isEmpty() ) extension = "." + extension; m_temporary_file = new KTempFile (locateLocal ("tmp", "kpl"), extension); #ifdef DEBUG_KPLAYER_PROCESS if ( m_temporary_file ) { kdDebugTime() << "Temporary file: " << m_temporary_file -> name() << "\n"; kdDebugTime() << "Temporary file creation status: " << m_temporary_file -> status() << "\n"; } kdDebugTime() << "Process: Creating temp job\n"; #endif m_temp_job = TDEIO::get (properties() -> url(), false, false); m_temp_job -> setWindow (kPlayerWorkspace()); m_temp_job -> addMetaData ("PropagateHttpHeader", "true"); connect (m_temp_job, TQ_SIGNAL (data (TDEIO::Job*, const TQByteArray&)), TQ_SLOT (transferTempData (TDEIO::Job*, const TQByteArray&))); connect (m_temp_job, TQ_SIGNAL (result (TDEIO::Job*)), TQ_SLOT (transferTempDone (TDEIO::Job*))); connect (m_temp_job, TQ_SIGNAL (percent (TDEIO::Job*, unsigned long)), TQ_SLOT (transferProgress (TDEIO::Job*, unsigned long))); connect (m_temp_job, TQ_SIGNAL (infoMessage (TDEIO::Job*, const TQString&)), TQ_SLOT (transferInfoMessage (TDEIO::Job*, const TQString&))); transferProgress (m_temp_job, 0); m_delayed_helper = true; } } void KPlayerProcess::load (KURL) { m_position = 0; m_delayed_player = m_delayed_helper = false; m_size_sent = properties() -> hasVideo() || properties() -> hasNoVideo(); m_info_available = properties() -> hasLength(); if ( m_temp_job ) m_temp_job -> kill (false); if ( m_temporary_file ) { m_temporary_file -> close(); m_temporary_file -> unlink(); delete m_temporary_file; m_temporary_file = 0; } transferTemporaryFile(); } void KPlayerProcess::setState (State state) { if ( m_state == state && state != Paused ) return; State previous = m_state; m_state = state; #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: New state: " << state << ", previous state: " << previous << ", position: " << m_position << "\n"; #endif if ( previous == Running && state == Idle && ! m_quit ) emit errorDetected(); if ( ! m_quit || state == Idle ) emit stateChanged (state, previous); } TQString KPlayerProcess::positionString (void) const { TQString l (properties() -> lengthString()), p (timeString (position(), true)); return l.isEmpty() ? p : p + " / " + l; } void KPlayerProcess::sendHelperCommand (TQCString& command) { if ( ! m_helper ) return; m_helper -> writeStdin (command, command.length()); #ifdef DEBUG_KPLAYER_HELPER kdDebugTime() << "helper << " << command; #endif } void KPlayerProcess::sendPlayerCommand (TQCString& command) { if ( ! m_player ) return; m_player -> writeStdin (command, command.length()); #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "process << " << command; #endif m_sent = true; m_sent_count = 0; } void KPlayerProcess::get_info (void) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Get info\n"; kdDebugTime() << " Widget " << kPlayerWorkspace() -> hiddenWidget() -> x() << "x" << kPlayerWorkspace() -> hiddenWidget() -> y() << " " << kPlayerWorkspace() -> hiddenWidget() -> width() << "x" << kPlayerWorkspace() -> hiddenWidget() -> height() << "\n"; #endif m_delayed_helper = m_kill = false; m_helper_seek = m_helper_seek_count = 0; m_helper_position = 0; if ( properties() -> url().isEmpty() || ! properties() -> deviceOption().isEmpty() ) return; if ( properties() -> useKioslave() ) { if ( ! properties() -> useTemporaryFile() ) return; if ( m_temporary_file && m_temporary_file -> handle() >= 0 ) { m_delayed_helper = true; return; } } m_helper = new KPlayerLineOutputProcess; *m_helper << properties() -> executablePath() << "-slave" << "-ao" << "null" << "-vo" << "x11" << "-wid" << TQString::number (kPlayerWorkspace() -> hiddenWidget() -> winId()); if ( properties() -> cache() == 1 || ! properties() -> url().isLocalFile() && ! properties() -> useKioslave() ) *m_helper << "-nocache"; else if ( properties() -> cache() == 2 ) *m_helper << "-cache" << TQString::number (properties() -> cacheSize()); connect (m_helper, TQ_SIGNAL (receivedStdoutLine (KPlayerLineOutputProcess*, char*, int)), TQ_SLOT (receivedHelperLine (KPlayerLineOutputProcess*, char*, int))); if ( ! run (m_helper) ) { delete m_helper; m_helper = 0; #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Could not start helper\n"; #endif return; } } void KPlayerProcess::play (void) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Play\n"; #endif if ( properties() -> url().isEmpty() ) return; m_position = 0; emit progressChanged (m_position, Position); start(); } TQString resourcePath (const TQString& filename) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Looking for " << filename << "\n"; #endif TQString path (TDEGlobal::dirs() -> findResource ("appdata", filename)); #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << " appdata '" << path << "'\n"; #endif if ( path.isEmpty() ) path = TDEGlobal::dirs() -> findResource ("data", "kplayer/" + filename); #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << " found '" << path << "'\n"; #endif return path; } void KPlayerProcess::start (void) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Start\n"; #endif if ( m_slave_job ) m_slave_job -> kill (false); m_position = m_max_position = 0; m_seek_count = m_cache_size = m_sent_count = 0; m_pausing = m_paused = m_quit = m_kill = m_09_version = m_delayed_player = m_first_chunk = false; m_seek = m_success = m_send_seek = m_sent = false; m_send_volume = m_send_contrast = m_send_brightness = m_send_hue = m_send_saturation = false; m_send_frame_drop = m_send_audio_id = m_send_subtitle_load = m_send_subtitle_visibility = false; m_send_audio_delay = m_send_subtitle_delay = m_send_subtitle_position = 0; m_send_subtitle_index = -2; m_seekable = m_subtitle_visibility = true; m_cache.clear(); setState (Running); transferTemporaryFile(); if ( properties() -> useKioslave() && properties() -> useTemporaryFile() && m_temporary_file && m_temporary_file -> handle() >= 0 ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Delaying play...\n"; #endif m_delayed_player = true; return; } /*if ( m_helper && re_dvd_vcd.search (settings() -> url().url()) >= 0 ) { m_delayed_play = true; #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Delaying play...\n"; #endif return; }*/ m_player = new KPlayerLineOutputProcess; *m_player << properties() -> executablePath() << "-zoom" << "-noautosub" << "-slave" << "-wid" << TQString::number (kPlayerWidget() -> winId()) << "-stop-xscreensaver"; TQString driver (properties() -> videoDriverString()); if ( ! driver.isEmpty() ) { if ( driver.startsWith ("xvmc") ) driver = "xvmc:ck=set" + driver.mid (4); else if ( driver.startsWith ("xv,") || driver.startsWith ("xv:") ) driver = "xv:ck=set" + driver.mid (2); *m_player << "-vo" << driver << "-colorkey" << "0x020202"; } driver = properties() -> audioDriverString(); if ( ! driver.isEmpty() ) *m_player << "-ao" << driver; if ( properties() -> softwareVolume() ) *m_player << "-softvol" << "-softvol-max" << TQString::number (properties() -> maximumSoftwareVolume()); else if ( driver.startsWith ("alsa") || driver.startsWith ("oss") ) { driver = properties() -> mixerDevice(); if ( ! driver.isEmpty() ) *m_player << "-mixer" << driver; driver = properties() -> mixerChannel(); if ( ! driver.isEmpty() ) *m_player << "-mixer-channel" << driver; } *m_player << "-osdlevel" << TQCString().setNum (properties() -> osdLevel()); *m_player << "-contrast" << TQCString().setNum (settings() -> contrast()); *m_player << "-brightness" << TQCString().setNum (settings() -> brightness()); *m_player << "-hue" << TQCString().setNum (settings() -> hue()); *m_player << "-saturation" << TQCString().setNum (settings() -> saturation()); if ( settings() -> frameDrop() == 0 ) *m_player << "-noframedrop"; else if ( settings() -> frameDrop() == 1 ) *m_player << "-framedrop"; else if ( settings() -> frameDrop() == 2 ) *m_player << "-hardframedrop"; int cache = properties() -> cache(); if ( cache == 0 && properties() -> useKioslave() && (! properties() -> useTemporaryFile() || ! m_temporary_file) ) *m_player << "-cache" << "1024"; else if ( cache == 2 ) *m_player << "-cache" << TQString().setNum (properties() -> cacheSize()); else if ( cache == 1 ) *m_player << "-nocache"; if ( properties() -> videoScaler() > 0 ) *m_player << "-sws" << TQCString().setNum (properties() -> videoScaler()); m_audio_delay = settings() -> audioDelay(); if ( m_audio_delay != 0 ) *m_player << "-delay" << TQCString().setNum (m_audio_delay); if ( properties() -> hasVideoID() ) *m_player << "-vid" << TQCString().setNum (properties() -> videoID()); m_audio_id = properties() -> audioID(); if ( m_audio_id > -1 ) *m_player << "-aid" << TQCString().setNum (m_audio_id); m_subtitles.clear(); m_vobsub = TQString::null; m_subtitle_index = properties() -> subtitleIndex(); if ( settings() -> hasSubtitles() ) { if ( settings() -> showVobsubSubtitles() || settings() -> hasVobsubSubtitles() && ! settings() -> showSubtitles() ) { m_vobsub = settings() -> vobsubSubtitles(); *m_player << "-vobsub" << m_vobsub; if ( properties() -> hasVobsubID() ) *m_player << "-vobsubid" << TQString::number (properties() -> vobsubID()); else m_send_subtitle_index = m_subtitle_index; } else if ( settings() -> showSubtitles() ) { if ( properties() -> hasSubtitleID() ) *m_player << "-sid" << TQString::number (properties() -> subtitleID()); else if ( settings() -> hasExternalSubtitles() ) { TQString urls (settings() -> currentSubtitles()); if ( urls.find (',') < 0 ) *m_player << "-sub" << urls; else { m_subtitle_index = -1; m_send_subtitle_load = true; } } } } m_subtitle_delay = settings() -> subtitleDelay(); if ( m_subtitle_delay != 0 ) *m_player << "-subdelay" << TQCString().setNum (m_subtitle_delay); m_subtitle_position = settings() -> subtitlePosition(); if ( m_subtitle_position != 100 ) *m_player << "-subpos" << TQCString().setNum (m_subtitle_position); TQString font (configuration() -> subtitleFontName()); if ( configuration() -> subtitleFontBold() ) font += ":bold"; if ( configuration() -> subtitleFontItalic() ) font += ":italic"; *m_player << "-fontconfig" << "-font" << font; *m_player << "-subfont-autoscale" << (configuration() -> subtitleAutoscale() ? "3" : "0"); if ( configuration() -> subtitleTextSize() ) *m_player << "-subfont-text-scale" << TQString::number (configuration() -> subtitleTextSize()); if ( configuration() -> hasSubtitleFontOutline() ) *m_player << "-ffactor" << configuration() -> subtitleFontOutlineString(); if ( configuration() -> hasSubtitleTextWidth() ) *m_player << "-subwidth" << configuration() -> subtitleTextWidthString(); const TQString& encoding (properties() -> subtitleEncoding()); if ( encoding == "UTF-8" ) *m_player << "-utf8"; else if ( ! encoding.isEmpty() ) *m_player << "-subcp" << encoding; if ( properties() -> hasSubtitleFramerate() ) *m_player << "-subfps" << properties() -> subtitleFramerateString(); *m_player << (configuration() -> subtitleEmbeddedFonts() ? "-embeddedfonts" : "-noembeddedfonts"); if ( properties() -> subtitleClosedCaption() ) *m_player << "-subcc"; if ( properties() -> videoDoubleBuffering() ) *m_player << "-double"; if ( properties() -> videoDirectRendering() && ! settings() -> showSubtitles() ) *m_player << "-dr"; if ( ! properties() -> videoDriverString().startsWith ("sdl") && ! properties() -> videoDriverString().startsWith ("svga") ) { TQString path = resourcePath ("input.conf"); if ( ! path.isEmpty() ) *m_player << "-input" << "conf=" + path; #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Input.conf: '" << path << "'\n"; #endif } if ( properties() -> useKioslave() && (! properties() -> useTemporaryFile() || ! m_temporary_file) ) { if ( m_temporary_file ) { m_temporary_file -> close(); m_temporary_file -> unlink(); delete m_temporary_file; m_temporary_file = 0; } TQString ext (properties() -> extension()); if ( re_ext.search (ext) >= 0 ) ext.prepend ('.'); else ext = ""; m_fifo_name = TQFile::encodeName (TQDir::homeDirPath() + "/.mplayer/kpstream" + ext); removeDataFifo(); #ifdef HAVE_MKFIFO #ifdef DEBUG_KPLAYER_PROCESS int rv = #endif ::mkfifo (m_fifo_name, S_IRUSR | S_IWUSR); #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: mkfifo " << m_fifo_name << " returned " << rv << "\n"; #endif #else #ifdef DEBUG_KPLAYER_PROCESS int rv = #endif ::mknod (m_fifo_name, S_IFIFO | S_IRUSR | S_IWUSR, 0); #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: mknod " << m_fifo_name << " returned " << rv << "\n"; #endif #endif } else m_fifo_name = TQCString(); connect (m_player, TQ_SIGNAL (receivedStdoutLine (KPlayerLineOutputProcess*, char*, int)), TQ_SLOT (receivedOutputLine (KPlayerLineOutputProcess*, char*, int))); connect (m_player, TQ_SIGNAL (receivedStderrLine (KPlayerLineOutputProcess*, char*, int)), TQ_SLOT (receivedOutputLine (KPlayerLineOutputProcess*, char*, int))); if ( ! run (m_player) ) { delete m_player; m_player = 0; emit messageReceived (i18n("Could not start MPlayer")); #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Could not start MPlayer\n"; #endif setState (Idle); return; } if ( properties() -> useKioslave() && (! properties() -> useTemporaryFile() || ! m_temporary_file) ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Will send get_time_length for '" << properties() -> url().url() << "'\n"; kdDebugTime() << "Process: Creating slave job\n"; #endif m_slave_job = TDEIO::get (properties() -> url(), false, false); m_slave_job -> setWindow (kPlayerWorkspace()); m_slave_job -> addMetaData ("PropagateHttpHeader", "true"); connect (m_slave_job, TQ_SIGNAL (data (TDEIO::Job*, const TQByteArray&)), TQ_SLOT (transferData (TDEIO::Job*, const TQByteArray&))); connect (m_slave_job, TQ_SIGNAL (result (TDEIO::Job*)), TQ_SLOT (transferDone (TDEIO::Job*))); connect (m_slave_job, TQ_SIGNAL (infoMessage (TDEIO::Job*, const TQString&)), TQ_SLOT (transferInfoMessage (TDEIO::Job*, const TQString&))); m_cache_size = properties() -> cache() == 2 ? properties() -> cacheSize() * 1024 : 1048576; m_first_chunk = true; #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Cache size: " << m_cache_size << "\n"; #endif m_seekable = properties() -> playlist(); } properties() -> resetVobsubIDs(); } void KPlayerProcess::restart (void) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Restart\n"; #endif if ( m_temp_job || ! m_player || properties() -> url().isEmpty() || state() == Idle ) return; m_quit = true; m_cache.clear(); if ( m_slave_job ) m_slave_job -> kill (false); m_absolute_seek = int (m_position); sendPlayerCommand (command_quit); stop (&m_player, &m_quit, m_state != Paused); start(); m_send_seek = true; } bool KPlayerProcess::run (KPlayerLineOutputProcess* player) { static TQRegExp re_space (" +"); #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Run\n"; #endif TQString codec (properties() -> videoCodecString()); if ( ! codec.isEmpty() ) *player << "-vc" << codec; codec = properties() -> audioCodecString(); if ( ! codec.isEmpty() ) *player << "-ac" << codec; codec = properties() -> demuxerString(); if ( ! codec.isEmpty() ) *player << "-demuxer" << codec; if ( properties() -> buildNewIndex() == 0 ) *player << "-idx"; else if ( properties() -> buildNewIndex() == 2 ) *player << "-forceidx"; *player << "-noquiet" << "-msglevel" << "identify=4"; TQString commandline = properties() -> commandLine(); if ( ! commandline.isEmpty() ) *player << TQStringList::split (re_space, commandline); codec = properties() -> deviceSetting(); if ( ! codec.isEmpty() ) *player << properties() -> deviceOption() << codec; if ( properties() -> playlist() ) *player << "-playlist"; else *player << "--"; if ( properties() -> useKioslave() ) *player << (properties() -> useTemporaryFile() && m_temporary_file ? TQFile::encodeName (m_temporary_file -> name()) : m_fifo_name); else *player << properties() -> urlString(); connect (player, TQ_SIGNAL (processExited (TDEProcess*)), TQ_SLOT (playerProcessExited (TDEProcess*))); #if 0 player -> setMerge (true); #endif return player -> start (TDEProcess::NotifyOnExit, TDEProcess::All); } void KPlayerProcess::pause (void) { if ( ! m_player || m_quit ) return; #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process::Pause: state " << m_state << " sent " << m_sent << " count " << m_sent_count << " pausing " << m_pausing << " paused " << m_paused << "\n"; #endif if ( m_sent || m_pausing || state() == Running ) { m_pausing = ! m_pausing; return; } sendPlayerCommand (command_pause); setState (m_state == Paused ? Playing : Paused); m_pausing = m_paused = false; } void KPlayerProcess::stop (KPlayerLineOutputProcess** player, bool* quit, bool send_quit) { if ( *player ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Stopping MPlayer process\n"; #endif *quit = true; if ( send_quit ) { if ( (*player) -> isRunning() ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: MPlayer is running. Waiting...\n"; #endif TDEProcessController::theTDEProcessController -> waitForProcessExit (1); } //if ( *player && (*player) -> isRunning() ) // TDEProcessController::theTDEProcessController -> waitForProcessExit (1); //if ( *player && (*player) -> isRunning() ) // TDEProcessController::theTDEProcessController -> waitForProcessExit (1); } if ( *quit && *player && (*player) -> isRunning() ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Closing MPlayer...\n"; #endif (*player) -> kill(); TDEProcessController::theTDEProcessController -> waitForProcessExit (1); if ( *quit && *player && (*player) -> isRunning() ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Killing MPlayer...\n"; #endif (*player) -> kill (SIGKILL); TDEProcessController::theTDEProcessController -> waitForProcessExit (1); if ( *quit && *player && (*player) -> isRunning() ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Could not shut down MPlayer\n"; #endif (*player) -> detach(); } } } if ( *quit && *player ) { delete *player; *player = 0; } } } void KPlayerProcess::stop (void) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Stop\n"; #endif m_delayed_helper = m_delayed_player = false; m_quit = true; if ( m_temp_job ) { m_temp_job -> kill (false); if ( m_temporary_file ) { m_temporary_file -> close(); m_temporary_file -> unlink(); delete m_temporary_file; m_temporary_file = 0; } } m_cache.clear(); if ( m_slave_job ) m_slave_job -> kill (false); if ( m_player ) sendPlayerCommand (command_quit); stop (&m_player, &m_quit, m_state != Paused); setState (Idle); } void KPlayerProcess::kill (void) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Kill\n"; #endif m_delayed_helper = m_delayed_player = false; m_quit = m_kill = true; if ( m_temp_job ) { m_temp_job -> kill (false); if ( m_temporary_file ) { m_temporary_file -> close(); m_temporary_file -> unlink(); delete m_temporary_file; m_temporary_file = 0; } } m_cache.clear(); if ( m_slave_job ) m_slave_job -> kill (false); if ( m_player ) sendPlayerCommand (command_quit); if ( m_helper ) sendHelperCommand (command_quit); stop (&m_player, &m_quit, m_state != Paused); stop (&m_helper, &m_kill); //setState (Idle); } void KPlayerProcess::progressSliderReleased (void) { m_seek_count = 1; #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Slider released. Position " << position() << " origin " << m_seek_origin << " sent " << m_sent << " count " << m_seek_count << "\n"; #endif } void KPlayerProcess::absoluteSeek (int seconds) { if ( ! m_player || m_quit ) return; if ( seconds < 0 ) seconds = 0; if ( m_sent || m_position - m_seek_origin < 0.65 && m_seek_origin - m_position < 0.25 ) { m_send_seek = true; m_absolute_seek = seconds; return; } if ( m_position - float (seconds) < 0.95 && float (seconds) - m_position < 0.45 ) { if ( float (seconds) > m_position ) seconds ++; else seconds --; } TQCString s ("seek "); // broken codec workaround if ( properties() -> length() >= MIN_VIDEO_LENGTH && re_mpeg12.search (properties() -> videoCodecString()) >= 0 && properties() -> deviceOption().isEmpty() ) { seconds = limit (int (float (seconds) / properties() -> length() * 100 + 0.5), 0, 100); s += TQCString().setNum (seconds) + " 1\n"; } else s += TQCString().setNum (seconds) + " 2\n"; sendPlayerCommand (s); m_seek = true; m_seek_origin = position(); m_send_seek = false; #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sent seek. Position " << position() << " origin " << m_seek_origin << " sent " << m_sent << " count " << m_seek_count << "\n"; #endif } void KPlayerProcess::relativeSeek (int seconds) { if ( ! m_player || m_quit || seconds == 0 ) return; TQCString s ("seek "); // broken codec workaround if ( (seconds > 4 || seconds < -4) && properties() -> length() >= MIN_VIDEO_LENGTH && re_mpeg12.search (properties() -> videoCodecString()) >= 0 && properties() -> deviceOption().isEmpty() ) { //seconds = limit (int ((m_position + seconds) / properties() -> length() * 100 + 0.5), 0, 100); //s += TQCString().setNum (seconds) + " 1\n"; //if ( m_send_seek ) // m_absolute_seek += seconds; //else absoluteSeek (int (m_position + seconds + 0.5)); return; } else s += TQCString().setNum (seconds) + "\n"; sendPlayerCommand (s); m_seek = true; } void KPlayerProcess::volume (int volume) { if ( ! m_player || m_quit || state() != Playing ) return; if ( m_sent ) { m_send_volume = true; return; } volume = limit (volume, 0, 100); TQCString s ("volume "); s += TQCString().setNum (volume) + " 1\n"; sendPlayerCommand (s); m_send_volume = false; } void KPlayerProcess::frameDrop (int frame_drop) { if ( ! m_player || m_quit || state() != Playing && state() != Running ) return; if ( m_sent || state() == Running ) { m_send_frame_drop = true; return; } TQCString s ("frame_drop "); s += TQCString().setNum (frame_drop) + "\n"; sendPlayerCommand (s); m_send_frame_drop = false; } void KPlayerProcess::contrast (int contrast) { if ( ! m_player || m_quit || state() != Playing ) return; if ( m_sent ) { m_send_contrast = true; return; } contrast = limit (contrast, -100, 100); TQCString s ("contrast "); s += TQCString().setNum (contrast) + " 1\n"; sendPlayerCommand (s); m_send_contrast = false; } void KPlayerProcess::brightness (int brightness) { if ( ! m_player || m_quit || state() != Playing ) return; if ( m_sent ) { m_send_brightness = true; return; } brightness = limit (brightness, -100, 100); TQCString s ("brightness "); s += TQCString().setNum (brightness) + " 1\n"; sendPlayerCommand (s); m_send_brightness = false; } void KPlayerProcess::hue (int hue) { if ( ! m_player || m_quit || state() != Playing ) return; if ( m_sent ) { m_send_hue = true; return; } hue = limit (hue, -100, 100); TQCString s ("hue "); s += TQCString().setNum (hue) + " 1\n"; sendPlayerCommand (s); m_send_hue = false; } void KPlayerProcess::saturation (int saturation) { if ( ! m_player || m_quit || state() != Playing ) return; if ( m_sent ) { m_send_saturation = true; return; } saturation = limit (saturation, -100, 100); TQCString s ("saturation "); s += TQCString().setNum (saturation) + " 1\n"; sendPlayerCommand (s); m_send_saturation = false; } void KPlayerProcess::subtitleMove (int position, bool absolute) { if ( ! m_player || m_quit || state() != Playing && state() != Running ) return; if ( absolute ) position -= m_subtitle_position; if ( position == 0 ) return; m_subtitle_position += position; if ( m_sent || state() == Running ) { m_send_subtitle_position += position; return; } position += m_send_subtitle_position; if ( position == 0 ) return; TQCString s ("sub_pos "); s += TQCString().setNum (position) + "\n"; sendPlayerCommand (s); m_send_subtitle_position = 0; } void KPlayerProcess::subtitleDelay (float delay, bool absolute) { if ( ! m_player || m_quit || state() != Playing && state() != Running ) return; if ( absolute ) delay -= m_subtitle_delay; if ( delay < 0.001 && delay > - 0.001 ) return; m_subtitle_delay += delay; if ( m_sent || state() == Running ) { m_send_subtitle_delay += delay; return; } delay += m_send_subtitle_delay; if ( delay < 0.001 && delay > - 0.001 ) return; TQCString s ("sub_delay "); s += TQCString().setNum (- delay) + "\n"; sendPlayerCommand (s); m_send_subtitle_delay = 0; } void KPlayerProcess::subtitleIndex (int index) { if ( ! m_player || m_quit || state() != Playing && state() != Running ) return; if ( m_sent || state() == Running ) { m_send_subtitle_index = index; return; } TQCString s ("sub_select "); s += TQCString().setNum (index) + "\n"; sendPlayerCommand (s); m_subtitle_index = index; m_send_subtitle_index = -2; if ( index == -1 == m_subtitle_visibility ) subtitleVisibility(); else m_send_subtitle_visibility = false; } void KPlayerProcess::subtitleVisibility (void) { if ( ! m_player || m_quit || state() != Playing && state() != Running ) return; if ( m_sent || state() == Running ) { m_send_subtitle_visibility = true; return; } sendPlayerCommand (command_visibility); m_subtitle_visibility = ! m_subtitle_visibility; m_send_subtitle_visibility = false; } void KPlayerProcess::subtitles (void) { if ( ! m_player || m_quit || state() == Idle ) return; if ( m_vobsub != settings() -> vobsubSubtitles() && settings() -> showVobsubSubtitles() ) { restart(); return; } int index = properties() -> subtitleIndex(); int count = properties() -> subtitleIDs().count() + properties() -> vobsubIDs().count(); if ( index < count ) { subtitleIndex (index); m_send_subtitle_load = false; return; } TQString subtitle (settings() -> currentSubtitles()); index = m_subtitles.findIndex (subtitle); if ( index >= 0 ) { subtitleIndex (index + count); m_send_subtitle_load = false; return; } if ( m_sent || state() == Running ) { m_send_subtitle_load = true; return; } TQCString s ("sub_load "); s += '"' + subtitle.utf8() + "\"\n"; sendPlayerCommand (s); m_send_subtitle_load = false; } void KPlayerProcess::audioDelay (float delay, bool absolute) { if ( ! m_player || m_quit || state() != Playing && state() != Running ) return; if ( absolute ) delay -= m_audio_delay; if ( delay < 0.001 && delay > - 0.001 ) return; m_audio_delay += delay; if ( m_sent || state() == Running ) { m_send_audio_delay += delay; return; } delay += m_send_audio_delay; if ( delay < 0.001 && delay > - 0.001 ) return; TQCString s ("audio_delay "); s += TQCString().setNum (- delay) + "\n"; sendPlayerCommand (s); m_send_audio_delay = 0; } void KPlayerProcess::audioID (int id) { if ( ! m_player || m_quit || state() != Playing && state() != Running ) return; if ( m_sent || state() == Running ) { m_send_audio_id = true; return; } if ( id != m_audio_id ) { TQRegExp demuxers (configuration() -> switchAudioDemuxers()); if ( demuxers.search (properties() -> demuxerString()) >= 0 ) { TQCString s ("switch_audio "); s += TQCString().setNum (id) + "\n"; sendPlayerCommand (s); m_audio_id = id; } else restart(); } m_send_audio_id = false; } void KPlayerProcess::transferData (TDEIO::Job* job, const TQByteArray& data) { if ( job && job == m_slave_job && m_player ) { if ( data.size() == 0 ) return; if ( m_cache.count() == 0 || m_cache.count() == 1 && ! m_first_chunk ) { #ifdef DEBUG_KPLAYER_KIOSLAVE kdDebugTime() << "Process: Cache: Creating new chunk, size " << data.size() << "\n"; #endif m_cache.append (new TQByteArray (data.copy())); } else { TQByteArray* array = m_cache.last(); int size = array -> size(); array -> resize (size + data.size(), TQGArray::SpeedOptim); #ifdef DEBUG_KPLAYER_KIOSLAVE if ( array -> size() != size + data.size() ) kdDebugTime() << "Process: Cache: Size mismatch: " << size << " + " << data.size() << " = " << array -> size() << "\n"; else kdDebugTime() << "Process: Cache: Appended to chunk " << m_cache.count() << " size " << size << " + " << data.size() << " = " << array -> size() << "\n"; #endif memcpy (array -> data() + size, data.data(), data.size()); } if ( m_cache.count() > 1 && ! m_slave_job -> isSuspended() && m_cache.last() -> size() >= m_cache_size ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Suspending transfer job\n"; #endif m_slave_job -> suspend(); } if ( m_cache.count() == 1 && (! m_first_chunk || m_cache.first() -> size() >= m_cache_size) ) { if ( m_first_chunk && ! m_quit ) emit progressChanged (100, CacheFill); sendFifoData(); } else if ( m_first_chunk && ! m_quit ) emit progressChanged (limit (int ((m_cache.first() -> size() * 100 + m_cache_size / 2) / m_cache_size), 0, 100), CacheFill); } else { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Stray transfer job\n"; #endif m_cache.clear(); if ( job ) job -> kill (true); } } void KPlayerProcess::transferTempData (TDEIO::Job* job, const TQByteArray& data) { if ( job && job == m_temp_job && m_temporary_file ) { #ifdef DEBUG_KPLAYER_KIOSLAVE int rv = #endif m_temporary_file -> file() -> writeBlock (data); #ifdef DEBUG_KPLAYER_KIOSLAVE kdDebugTime() << "Process: Write call returned " << rv << "\n"; #endif } else { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Stray temporary file TransferJob\n"; #endif if ( job ) job -> kill (true); } } void KPlayerProcess::transferProgress (TDEIO::Job* job, unsigned long progress) { if ( job && job == m_temp_job ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Temporary file transfer progress received: " << progress << "\n"; #endif emit progressChanged (progress, FileTransfer); } #ifdef DEBUG_KPLAYER_PROCESS else kdDebugTime() << "Process: Stray temporary file progress received: " << progress << "\n"; #endif } void KPlayerProcess::transferInfoMessage (TDEIO::Job* job, const TQString& message) { if ( job && (job == m_slave_job || job == m_temp_job) ) emit messageReceived (message); } void KPlayerProcess::transferDone (TDEIO::Job* job) { if ( job && job == m_slave_job ) { bool error_page = m_slave_job -> isErrorPage(); #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Transfer job ended, result code: " << job -> error() << " error page " << error_page << "\n"; #endif if ( job -> error() != 0 && (job -> error() != 20 || ! m_quit) || error_page ) { TQString errorString; if ( job -> error() != 0 ) { errorString = job -> errorString(); if ( errorString.isEmpty() ) { KURL url (properties() -> url()); errorString = job -> detailedErrorStrings (&url).first(); } } else if ( error_page ) { m_cache.clear(); /*#ifdef DEBUG_KPLAYER_PROCESS TDEIO::MetaData metadata (job -> metaData()); for ( TDEIO::MetaData::Iterator it = metadata.begin(); it != metadata.end(); ++ it ) kdDebugTime() << "Process: Error page metadata: key '" << it.key() << "' data '" << it.data() << "'\n"; #endif*/ errorString = job -> queryMetaData ("HTTP-Headers"); } #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Error string: '" << errorString << "'\n"; #endif if ( ! errorString.isEmpty() ) emit messageReceived (errorString); emit errorDetected(); error_page = (error_page || m_first_chunk) && ! m_quit; } else if ( m_cache.count() == 1 && m_first_chunk && m_cache.first() -> size() < m_cache_size && ! m_quit ) sendFifoData(); m_cache_size = 0; m_first_chunk = false; m_slave_job = 0; if ( m_player && m_cache.isEmpty() ) { removeDataFifo(); if ( error_page && m_player ) { stop (&m_player, &m_quit); setState (Idle); } } } #ifdef DEBUG_KPLAYER_PROCESS else kdDebugTime() << "Process: Stray transfer job ended\n"; #endif } void KPlayerProcess::transferTempDone (TDEIO::Job* job) { if ( job && job == m_temp_job ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Temporary file transfer job ended, result code: " << job -> error() << " error page " << m_temp_job -> isErrorPage() << "\n"; #endif if ( job -> error() != 0 && (job -> error() != 20 || ! m_quit) || m_temp_job -> isErrorPage() ) { TQString errorString; if ( job -> error() != 0 ) errorString = job -> errorString(); else if ( m_temp_job -> isErrorPage() ) errorString = job -> queryMetaData ("HTTP-Headers"); /* { #ifdef DEBUG_KPLAYER_PROCESS TDEIO::MetaData metadata (job -> metaData()); for ( TDEIO::MetaData::Iterator it = metadata.begin(); it != metadata.end(); ++ it ) kdDebugTime() << "Process: Error page metadata: key '" << it.key() << "' data '" << it.data() << "'\n"; #endif }*/ if ( ! errorString.isEmpty() ) { emit messageReceived (errorString); #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Error string: " << errorString << "\n"; #endif } /*if ( m_temp_job -> isErrorPage() ) emit messageReceived ("HTTP request returned an error"); TQString errorString (job -> errorString()); if ( ! errorString.isEmpty() ) emit messageReceived (errorString); KURL url (settings() -> url()); TQStringList errors (job -> detailedErrorStrings (&url)); for ( TQStringList::Iterator it = errors.begin(); it != errors.end(); ++ it ) if ( ! (*it).isEmpty() ) emit messageReceived (*it);*/ emit errorDetected(); if ( m_temporary_file ) { m_temporary_file -> close(); m_temporary_file -> unlink(); delete m_temporary_file; m_temporary_file = 0; } m_temp_job = 0; m_delayed_player = m_delayed_helper = false; setState (Idle); } else if ( m_quit ) { if ( m_temporary_file ) { m_temporary_file -> close(); m_temporary_file -> unlink(); delete m_temporary_file; m_temporary_file = 0; } m_temp_job = 0; m_delayed_player = m_delayed_helper = false; } else { emit progressChanged (100, FileTransfer); m_temp_job = 0; if ( m_temporary_file ) m_temporary_file -> close(); if ( m_delayed_helper ) get_info(); if ( m_delayed_player ) play(); } } #ifdef DEBUG_KPLAYER_PROCESS else kdDebugTime() << "Process: Stray temporary file TransferJob ended\n"; #endif } void KPlayerProcess::removeDataFifo (void) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process::removeDataFifo\n"; #endif if ( m_fifo_notifier ) { delete m_fifo_notifier; m_fifo_notifier = 0; } if ( m_fifo_handle >= 0 ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: closing fifo " << m_fifo_handle << "...\n"; #endif m_fifo_handle = ::close (m_fifo_handle); #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: fifo close returned " << m_fifo_handle << "\n"; #endif m_fifo_handle = -1; m_fifo_offset = 0; } if ( ! m_fifo_name.isEmpty() ) ::unlink (m_fifo_name); #ifdef DEBUG_KPLAYER_DUMP if ( s_dump.isOpen() ) s_dump.close(); #endif } void KPlayerProcess::sendFifoData (void) { #ifdef DEBUG_KPLAYER_KIOSLAVE kdDebugTime() << "Process::sendFifoData\n"; #endif if ( m_fifo_handle < 0 ) { m_fifo_handle = ::open (m_fifo_name, O_WRONLY | O_NONBLOCK, S_IRUSR | S_IWUSR); #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: fifo open returned " << m_fifo_handle << "\n"; #endif if ( m_fifo_handle >= 0 ) { if ( m_fifo_timer ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: fifo open successful, deleting timer\n"; #endif delete m_fifo_timer; m_fifo_timer = 0; } m_fifo_notifier = new TQSocketNotifier (m_fifo_handle, TQSocketNotifier::Write); m_fifo_notifier -> setEnabled (false); connect (m_fifo_notifier, TQ_SIGNAL (activated (int)), TQ_SLOT (playerDataWritten (int))); } else if ( ! m_fifo_timer ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: fifo open failed, creating timer\n"; #endif m_fifo_timer = new TQTimer (this); connect (m_fifo_timer, TQ_SIGNAL (timeout()), TQ_SLOT (sendFifoData())); m_fifo_timer -> start (100); } } if ( m_fifo_handle >= 0 ) { TQByteArray* array = m_cache.first(); if ( array && array -> size() > m_fifo_offset ) { #ifdef DEBUG_KPLAYER_KIOSLAVE kdDebugTime() << "Process: Cache: Writing " << array -> size() << " - " << m_fifo_offset << " bytes to fifo\n"; #endif int rv = ::write (m_fifo_handle, array -> data() + m_fifo_offset, array -> size() - m_fifo_offset); if ( rv > 0 ) { #ifdef DEBUG_KPLAYER_DUMP if ( ! s_dump.isOpen() ) s_dump.open (IO_WriteOnly); s_dump.writeBlock (array -> data() + m_fifo_offset, rv); #endif m_fifo_offset += rv; } #ifdef DEBUG_KPLAYER_KIOSLAVE kdDebugTime() << "Process: Cache: Write call returned " << rv << "\n"; #endif m_fifo_notifier -> setEnabled (true); m_first_chunk = false; } } } void KPlayerProcess::playerDataWritten (int fd) { if ( fd == m_fifo_handle ) { #ifdef DEBUG_KPLAYER_KIOSLAVE kdDebugTime() << "Process: Cache: Data written\n"; #endif TQByteArray* array = m_cache.first(); if ( array && array -> size() <= m_fifo_offset ) { #ifdef DEBUG_KPLAYER_KIOSLAVE kdDebugTime() << "Process: Cache: Wrote " << array -> size() << " byte chunk, offset " << m_fifo_offset << "\n"; #endif m_cache.remove(); m_fifo_offset = 0; m_fifo_notifier -> setEnabled (false); if ( m_slave_job && m_slave_job -> isSuspended() ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Resuming transfer job\n"; #endif m_slave_job -> resume(); } } if ( ! m_cache.isEmpty() ) sendFifoData(); else if ( ! m_slave_job ) removeDataFifo(); } #ifdef DEBUG_KPLAYER_PROCESS else kdDebugTime() << "Process: Stray socket notifier signal\n"; #endif } void KPlayerProcess::playerProcessExited (TDEProcess *proc) { if ( proc == m_player ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: MPlayer process exited\n"; #endif delete m_player; m_player = 0; if ( m_success && ! m_seek && m_position > 0 && m_position > properties() -> length() / 40 ) { properties() -> setLength (m_max_position); m_info_available = true; emit infoAvailable(); properties() -> commit(); } m_cache.clear(); if ( m_slave_job ) m_slave_job -> kill (false); removeDataFifo(); m_fifo_name = TQCString(); if ( ! m_quit ) setState (Idle); } else if ( proc == m_helper ) { #ifdef DEBUG_KPLAYER_HELPER kdDebugTime() << "MPlayer helper process exited\n"; #endif delete m_helper; m_helper = 0; if ( m_helper_seek < 500 && m_helper_position >= MIN_VIDEO_LENGTH && m_helper_position > properties() -> length() / 40 ) properties() -> setLength (m_helper_position); m_info_available = true; if ( ! m_kill ) emit infoAvailable(); if ( ! m_size_sent && ! m_kill && m_helper_seek > 0 ) { emit sizeAvailable(); m_size_sent = true; } if ( ! m_kill && properties() -> url().isValid() ) properties() -> commit(); /*if ( m_delayed_play && ! m_player ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Delayed play...\n"; #endif play(); }*/ } else { delete proc; #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Stray MPlayer process exited\n"; #endif } } void KPlayerProcess::receivedOutputLine (KPlayerLineOutputProcess* proc, char* str, int len) { if ( proc != m_player ) { char buf [1025]; if ( len > 1024 ) len = 1024; memcpy (buf, str, len); buf [len] = 0; if ( re_exiting.search (buf) < 0 ) proc -> writeStdin (command_quit, command_quit.length()); return; } static float prev_position = -1; float ftime; if ( state() == Running ) kPlayerWidget() -> sendConfigureEvent(); if ( re_version.search (str) >= 0 ) { m_09_version = true; #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: MPlayer 0.9x detected\n"; #endif } if ( re_paused.search (str) >= 0 ) { m_paused = true; m_pausing = false; m_sent = false; setState (Paused); } if ( strncmp (str, "ID_FILE_SUB_FILENAME=", 21) == 0 && str[21] ) { m_subtitles.append (str + 21); #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Subtitle file " << m_subtitles.last() << "\n"; #endif if ( settings() -> currentSubtitles() == m_subtitles.last() ) subtitleIndex (properties() -> subtitleIDs().count() + properties() -> vobsubIDs().count() + m_subtitles.count() - 1); } else if ( m_state < Playing || strncmp (str, "ID_", 3) == 0 || strncmp (str, "Name", 4) == 0 || strncmp (str, "ICY Info:", 9) == 0 ) { TQSize size (properties() -> originalSize()); bool hadVideo = properties() -> hasVideo(); bool hadLength = properties() -> hasLength(); properties() -> extractMeta (str, true); if ( ! hadLength && properties() -> hasLength() ) { m_info_available = true; if ( ! m_quit ) emit infoAvailable(); } if ( properties() -> hasVideo() && (! hadVideo || size != properties() -> originalSize()) ) m_size_sent = false; if ( ! m_quit && ! m_size_sent && properties() -> heightAdjusted() ) { emit sizeAvailable(); m_size_sent = true; } } if ( m_state == Running && (m_pausing || m_send_seek) && ! m_sent && ! m_quit && re_start.search (str) >= 0 ) { if ( m_send_seek ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Initial seek to " << m_absolute_seek << ". Position " << position() << " origin " << m_seek_origin << " sent " << m_sent << " count " << m_seek_count << "\n"; #endif absoluteSeek (m_absolute_seek); } else { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Pausing: '" << str << "'\n"; #endif sendPlayerCommand (command_pause); setState (m_state == Paused ? Playing : Paused); m_pausing = m_paused = false; } } if ( re_success.search (str) >= 0 && ! m_quit ) m_success = true; if ( re_exiting.search (str) >= 0 && re_quit.search (str) < 0 && re_success.search (str) < 0 && ! m_quit ) emit errorDetected(); if ( re_crash.search (str) >= 0 ) { int sig = re_crash.cap(1).toInt(); if ( sig <= 15 && ! m_quit || sig < 9 || sig > 9 && sig < 15 ) emit errorDetected(); } //kdDebugTime() << "matching a_or_v regex\n"; if ( re_a_or_v.search (str) >= 0 ) { #ifdef DEBUG_KPLAYER_LINEOUT kdDebugTime() << "Received AV Buffer: '" << str << "'\n"; #endif if ( m_state < Playing ) { if ( ! m_size_sent && ! m_quit ) { emit sizeAvailable(); m_size_sent = true; } if ( ! m_quit ) properties() -> commit(); setState (Playing); m_send_volume = m_send_contrast = m_send_brightness = m_send_hue = m_send_saturation = true; } if ( m_sent && ++ m_sent_count >= 5 ) m_sent = false; if ( m_quit && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Resending quit command\n"; #endif sendPlayerCommand (command_quit); } if ( m_send_subtitle_load && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending subtitles\n"; #endif subtitles(); } if ( m_send_subtitle_index > -2 && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending subtitle index\n"; #endif subtitleIndex (m_send_subtitle_index); } if ( m_send_subtitle_visibility && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending subtitle visibility\n"; #endif subtitleVisibility(); } if ( m_send_audio_id && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending audio ID\n"; #endif audioID (properties() -> audioID()); } if ( (m_send_audio_delay >= 0.001 || m_send_audio_delay <= - 0.001) && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending audio delay\n"; #endif TQCString s ("audio_delay "); s += TQCString().setNum (- m_send_audio_delay) + "\n"; sendPlayerCommand (s); m_send_audio_delay = 0; } if ( (m_send_subtitle_delay >= 0.001 || m_send_subtitle_delay <= - 0.001) && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending subtitle delay\n"; #endif TQCString s ("sub_delay "); s += TQCString().setNum (- m_send_subtitle_delay) + "\n"; sendPlayerCommand (s); m_send_subtitle_delay = 0; } if ( m_send_subtitle_position && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending subtitle position\n"; #endif TQCString s ("sub_pos "); s += TQCString().setNum (m_send_subtitle_position) + "\n"; sendPlayerCommand (s); m_send_subtitle_position = 0; } if ( m_send_volume && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending volume\n"; #endif volume (settings() -> actualVolume()); } if ( m_send_frame_drop && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending frame drop\n"; #endif frameDrop (settings() -> frameDrop()); } if ( m_send_contrast && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending contrast\n"; #endif contrast (settings() -> contrast()); } if ( m_send_brightness && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending brightness\n"; #endif brightness (settings() -> brightness()); } if ( m_send_hue && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending hue\n"; #endif hue (settings() -> hue()); } if ( m_send_saturation && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending saturation\n"; #endif saturation (settings() -> saturation()); } // kdDebugTime() << "regex matched\n"; if ( re_a_and_v.search (str) >= 0 ) { ftime = stringToFloat (re_a_and_v.cap (1)); float ftime2 = stringToFloat (re_a_and_v.cap (2)); if ( ftime2 > ftime ) ftime = ftime2; } else { ftime = stringToFloat (re_a_or_v.cap (1)); // kdDebugTime() << "match: " << re_a_or_v.cap (1) << "ftime: " << ftime << "\n"; } if ( ftime > properties() -> length() && properties() -> length() >= MIN_VIDEO_LENGTH ) properties() -> setLength (ftime); if ( ftime != m_position ) { m_position = ftime; if ( m_position > m_max_position ) m_max_position = m_position; float diff = m_position - prev_position; prev_position = m_position; if ( ! m_quit && (diff > 0 || diff < -0.15 || m_position == 0) && (m_position - m_seek_origin > 0.65 || m_seek_origin - m_position > 0.25) && ! m_send_seek && (m_seek_count == 0 || ++ m_seek_count > 5) ) { #ifdef DEBUG_KPLAYER_PROCESS if ( m_seek_origin >= 0 ) kdDebugTime() << "Process: Reset seek origin. Position " << position() << " origin " << m_seek_origin << " sent " << m_sent << " count " << m_seek_count << "\n"; #endif m_seek_origin = NO_SEEK_ORIGIN; emit progressChanged (m_position, Position); m_seek_count = 0; } // kdDebugTime() << "position: " << m_position << " length: " << properties() -> length() << "\n"; } if ( m_pausing && ! m_quit && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Pausing: '" << str << "'\n"; #endif m_pausing = m_paused = false; pause(); } if ( m_paused && ! m_quit && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Paused: '" << str << "'\n"; #endif m_pausing = m_paused = false; sendPlayerCommand (command_pause); } if ( m_send_seek && ! m_sent ) { #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "Process: Sending seek to " << m_absolute_seek << ". Position " << position() << " origin " << m_seek_origin << " sent " << m_sent << " count " << m_seek_count << "\n"; #endif absoluteSeek (m_absolute_seek); } } else if ( re_cache_fill.search (str) >= 0 ) { ftime = stringToFloat (re_cache_fill.cap (1)); #ifdef DEBUG_KPLAYER_PROGRESS kdDebugTime() << "Received cache progress: '" << str << "' -> " << ftime << "\n"; #endif if ( ! m_quit && ! m_first_chunk ) emit progressChanged (ftime, CacheFill); } else if ( re_generating_index.search (str) >= 0 ) { ftime = stringToFloat (re_generating_index.cap (1)); #ifdef DEBUG_KPLAYER_PROGRESS kdDebugTime() << "Received indexing progress: '" << str << "' -> " << ftime << "\n"; #endif if ( ! m_quit ) emit progressChanged (ftime, IndexGeneration); } else if ( ! m_quit ) { emit messageReceived (TQString::fromLocal8Bit (str)); #ifdef DEBUG_KPLAYER_PROCESS kdDebugTime() << "process >> " << str << "\n"; #endif } } void KPlayerProcess::receivedHelperLine (KPlayerLineOutputProcess* proc, char* str, int len) { if ( proc != m_helper ) { char buf [1025]; if ( len > 1024 ) len = 1024; memcpy (buf, str, len); buf [len] = 0; if ( re_exiting.search (buf) < 0 ) proc -> writeStdin (command_quit, command_quit.length()); return; } bool sent = false; float ftime; #ifdef DEBUG_KPLAYER_HELPER kdDebugTime() << "helper >> " << str << "\n"; #endif bool hadVideo = properties() -> hasVideo(); bool hadLength = properties() -> hasLength(); properties() -> extractMeta (str, false); if ( ! hadLength && properties() -> hasLength() ) { m_info_available = true; if ( ! m_kill ) emit infoAvailable(); } if ( m_helper_seek == 1 && properties() -> hasLength() ) m_helper_seek_count = 9; if ( ! hadVideo && properties() -> hasVideo() ) m_size_sent = false; if ( ! m_kill && ! m_size_sent && properties() -> heightAdjusted() ) { emit sizeAvailable(); m_size_sent = true; } //kdDebugTime() << "matching a_or_v regex\n"; if ( re_a_or_v.search (str) >= 0 ) { // kdDebugTime() << "regex matched\n"; if ( re_a_and_v.search (str) >= 0 ) { ftime = stringToFloat (re_a_and_v.cap (1)); float ftime2 = stringToFloat (re_a_and_v.cap (2)); if ( ftime2 > ftime ) ftime = ftime2; } else { ftime = stringToFloat (re_a_or_v.cap (1)); // kdDebugTime() << "match: " << re_a_or_v.cap (1) << "ftime: " << ftime << "\n"; } if ( m_helper_seek > 0 && ! sent ) { if ( ++ m_helper_seek_count < 10 ) sent = true; else m_helper_seek_count = 0; #ifdef DEBUG_KPLAYER_HELPER kdDebugTime() << "Helper: Seek count: " << m_helper_seek_count << "\n"; #endif } if ( m_helper_seek == 0 && ftime >= MIN_VIDEO_LENGTH ) m_helper_seek = 100; else { if ( m_helper_seek > 0 && m_helper_seek < 500 && ftime >= MIN_VIDEO_LENGTH && properties() -> hasLength() && ftime > properties() -> length() ) properties() -> setLength (ftime); if ( ftime != m_helper_position ) { m_helper_position = ftime; #ifdef DEBUG_KPLAYER_HELPER kdDebugTime() << "helper position: " << m_helper_position << " length: " << properties() -> length() << "\n"; #endif } if ( m_helper_seek > 0 && m_helper_seek < 500 && ftime >= MIN_VIDEO_LENGTH ) { float estlength = ftime * 100 / m_helper_seek; if ( properties() -> length() < estlength ) { properties() -> setLength (estlength); m_info_available = true; if ( ! m_kill ) emit infoAvailable(); } #ifdef DEBUG_KPLAYER_HELPER kdDebugTime() << "estimated length: " << properties() -> length() << "\n"; #endif } } if ( m_helper_seek == 0 && ! sent ) { sendHelperCommand (command_seek_99); m_helper_seek = 99; m_helper_seek_count = 0; sent = true; } if ( m_helper_seek == 99 && ! sent && properties() -> length() < MIN_VIDEO_LENGTH ) { sendHelperCommand (command_seek_95); m_helper_seek = 95; m_helper_seek_count = 0; sent = true; } if ( m_helper_seek == 95 && ! sent && properties() -> length() < MIN_VIDEO_LENGTH ) { sendHelperCommand (command_seek_90); m_helper_seek = 90; m_helper_seek_count = 0; sent = true; } if ( m_helper_seek == 90 && ! sent && properties() -> length() < MIN_VIDEO_LENGTH ) { sendHelperCommand (command_seek_50); m_helper_seek = 50; m_helper_seek_count = 0; sent = true; } if ( m_helper_seek < 100 && properties() -> length() >= MIN_VIDEO_LENGTH ) { sendHelperCommand (command_seek_100); m_helper_seek = 100; m_helper_seek_count = 0; sent = true; } if ( (m_helper_seek == 50 || m_helper_seek == 100) && ! sent ) { sendHelperCommand (command_quit); m_helper_seek = 500; sent = true; } } }