/* * * $Id: k3bvideocdrip.cpp 619556 2007-01-03 17:38:12Z trueg $ * Copyright (C) 2003 Christian Kvasny * * This file is part of the K3b project. * Copyright (C) 1998-2007 Sebastian Trueg * * 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 2 of the License, or * (at your option) any later version. * See the file "COPYING" for the exact licensing terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include // K3b Includes #include "k3bvideocdrip.h" #include #include #include #include K3bVideoCdRip::K3bVideoCdRip( K3bJobHandler* hdl, K3bVideoCdRippingOptions* options, TQObject* parent, const char* name ) : K3bJob( hdl, parent, name ), m_ripsourceType( 0 ), m_subPosition ( 0 ), m_videooptions( options ), m_canceled( false ), m_process( 0 ) {} K3bVideoCdRip::~K3bVideoCdRip() { if ( m_process ) delete m_process; } void K3bVideoCdRip::cancel() { cancelAll(); emit infoMessage( i18n( "Job canceled by user." ), K3bJob::ERROR ); emit canceled(); jobFinished( false ); } void K3bVideoCdRip::cancelAll() { m_canceled = true; if ( m_process->isRunning() ) { m_process->disconnect( this ); m_process->kill(); } } void K3bVideoCdRip::start() { kdDebug() << "(K3bVideoCdRip) starting job" << endl; jobStarted(); m_canceled = false; vcdxRip(); } void K3bVideoCdRip::vcdxRip() { emit newTask( i18n( "Check files" ) ); m_stage = stageUnknown; delete m_process; m_process = new K3bProcess(); const K3bExternalBin* bin = k3bcore ->externalBinManager() ->binObject( "vcdxrip" ); if ( !bin ) { kdDebug() << "(K3bVideoCdRip) could not find vcdxrip executable" << endl; emit infoMessage( i18n( "Could not find %1 executable." ).tqarg( "vcdxrip" ), K3bJob::ERROR ); emit infoMessage( i18n( "To rip VideoCD's you must install VcdImager Version %1." ).tqarg( ">= 0.7.12" ), K3bJob::INFO ); emit infoMessage( i18n( "You can find this on your distribution disks or download it from http://www.vcdimager.org" ), K3bJob::INFO ); cancelAll(); jobFinished( false ); return ; } if( bin->version < K3bVersion("0.7.12") ) { kdDebug() << "(K3bVideoCdRip) vcdxrip executable too old!" << endl; emit infoMessage( i18n( "%1 executable too old! Need version %2 or greater" ).tqarg( "Vcdxrip" ).tqarg( "0.7.12" ), K3bJob::ERROR ); emit infoMessage( i18n( "You can find this on your distribution disks or download it from http://www.vcdimager.org" ), K3bJob::INFO ); cancelAll(); jobFinished( false ); return ; } if ( !bin->copyright.isEmpty() ) emit infoMessage( i18n( "Using %1 %2 - Copyright (C) %3" ).tqarg( bin->name() ).tqarg( bin->version ).tqarg( bin->copyright ), INFO ); *m_process << k3bcore ->externalBinManager() ->binPath( "vcdxrip" ); // additional user parameters from config const TQStringList& params = k3bcore->externalBinManager() ->program( "vcdxrip" ) ->userParameters(); for ( TQStringList::const_iterator it = params.begin(); it != params.end(); ++it ) *m_process << *it; *m_process << "--gui" << "--progress"; if ( !m_videooptions ->getVideoCdRipFiles() ) *m_process << "--nofiles"; if ( !m_videooptions ->getVideoCdRipSegments() ) *m_process << "--nosegments"; if ( !m_videooptions ->getVideoCdRipSequences() ) *m_process << "--nosequences"; if ( m_videooptions ->getVideoCdIgnoreExt() ) *m_process << "--no-ext-psd"; if ( m_videooptions ->getVideoCdSector2336() ) *m_process << "--sector-2336"; *m_process << "-i" << TQString( "%1" ).tqarg( TQFile::encodeName( m_videooptions ->getVideoCdSource() ).data() ); if ( m_videooptions ->getVideoCdExtractXml() ) *m_process << "-o" << TQString( "%1" ).tqarg( TQFile::encodeName( m_videooptions ->getVideoCdDescription() + ".xml" ).data() ); else *m_process << "-o" << "/dev/null"; connect( m_process, TQT_SIGNAL( receivedStderr( KProcess*, char*, int ) ), this, TQT_SLOT( slotParseVcdXRipOutput( KProcess*, char*, int ) ) ); connect( m_process, TQT_SIGNAL( receivedStdout( KProcess*, char*, int ) ), this, TQT_SLOT( slotParseVcdXRipOutput( KProcess*, char*, int ) ) ); connect( m_process, TQT_SIGNAL( processExited( KProcess* ) ), this, TQT_SLOT( slotVcdXRipFinished() ) ); m_process->setWorkingDirectory( TQUrl( m_videooptions ->getVideoCdDestination() ).dirPath() ); // vcdxrip commandline parameters kdDebug() << "***** vcdxrip parameters:" << endl; ; const TQValueList& args = m_process->args(); TQString s; for ( TQValueList::const_iterator it = args.begin(); it != args.end(); ++it ) { s += *it + " "; } kdDebug() << s << flush << endl; emit debuggingOutput( "vcdxrip command:", s ); emit newTask( i18n( "Extracting" ) ); emit infoMessage( i18n( "Start extracting." ), K3bJob::INFO ); emit infoMessage( i18n( "Extract files from %1 to %2." ).tqarg( m_videooptions ->getVideoCdSource() ).tqarg( m_videooptions ->getVideoCdDestination() ), K3bJob::INFO ); if ( !m_process->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) { kdDebug() << "(K3bVideoCdRip) could not start vcdxrip" << endl; emit infoMessage( i18n( "Could not start %1." ).tqarg( "vcdxrip" ), K3bJob::ERROR ); cancelAll(); jobFinished( false ); } } void K3bVideoCdRip::slotParseVcdXRipOutput( KProcess*, char* output, int len ) { TQString buffer = TQString::fromLocal8Bit( output, len ); // split to lines TQStringList lines = TQStringList::split( "\n", buffer ); TQDomDocument xml_doc; TQDomElement xml_root; // do every line TQStringList::Iterator end( lines.end()); for ( TQStringList::Iterator str = lines.begin(); str != end; ++str ) { *str = ( *str ).stripWhiteSpace(); emit debuggingOutput( "vcdxrip", *str ); xml_doc.setContent( TQString( "" ) + *str + "" ); xml_root = xml_doc.documentElement(); for ( TQDomNode node = xml_root.firstChild(); !node.isNull(); node = node.nextSibling() ) { TQDomElement el = node.toElement(); if ( el.isNull() ) continue; const TQString tagName = el.tagName().lower(); if ( tagName == "progress" ) { const TQString oper = el.attribute( "operation" ).lower(); const unsigned long long overallPos = el.attribute( "position" ).toLong(); const unsigned long long pos = overallPos - m_subPosition; const unsigned long long size = el.attribute( "size" ).toLong() - m_subPosition; if ( oper == "extract" ) { emit subPercent( ( int ) ( 100.0 * ( double ) pos / ( double ) size ) ); emit processedSubSize( ( pos * 2352 ) / 1024 / 1024 , ( size * 2352 ) / 1024 / 1024 ); m_bytesFinished = pos; kdDebug() << "(slotParseVcdXRipOutput) overall: " << ((long)overallPos * 2352) << ", videocdsize: " << m_videooptions->getVideoCdSize() << endl; double relOverallWritten = ( ( double ) overallPos * 2352 ) / ( double ) m_videooptions ->getVideoCdSize() ; int newpercent = ( int ) ( 100 * relOverallWritten ); if ( newpercent > m_oldpercent ) { emit percent( newpercent ); m_oldpercent = newpercent; } } else { return ; } } else if ( tagName == "log" ) { TQDomText tel = el.firstChild().toText(); const TQString level = el.attribute( "level" ).lower(); if ( tel.isText() ) { const TQString text = tel.data(); if ( level == "information" ) { kdDebug() << TQString( "(K3bVideoCdRip) vcdxrip information, %1" ).tqarg( text ) << endl; parseInformation( text ); } else { if ( level != "error" ) { kdDebug() << TQString( "(K3bVideoCdRip) vcdxrip warning, %1" ).tqarg( text ) << endl; emit debuggingOutput( "vcdxrip", text ); parseInformation( text ); } else { kdDebug() << TQString( "(K3bVideoCdRip) vcdxrip error, %1" ).tqarg( text ) << endl; emit infoMessage( text, K3bJob::ERROR ); } } } } } } } void K3bVideoCdRip::slotVcdXRipFinished() { if ( m_process->normalExit() ) { // TODO: check the process' exitStatus() switch ( m_process->exitStatus() ) { case 0: emit infoMessage( i18n( "Files successfully extracted." ), K3bJob::SUCCESS ); break; default: emit infoMessage( i18n( "%1 returned an unknown error (code %2)." ).tqarg( "vcdxrip" ).tqarg( m_process->exitStatus() ), K3bJob::ERROR ); emit infoMessage( i18n( "Please send me an email with the last output..." ), K3bJob::ERROR ); cancelAll(); jobFinished( false ); return ; } } else { emit infoMessage( i18n( "%1 did not exit cleanly." ).tqarg( "Vcdxrip" ), K3bJob::ERROR ); cancelAll(); jobFinished( false ); return ; } jobFinished( true ); } void K3bVideoCdRip::parseInformation( TQString text ) { // parse warning if ( text.contains( "encountered non-form2 sector" ) ) { // I think this is an error not a warning. Finish ripping with invalid mpegs. emit infoMessage( i18n( "%1 encountered non-form2 sector" ).tqarg("Vcdxrip"), K3bJob::ERROR ); emit infoMessage( i18n( "leaving loop" ), K3bJob::ERROR ); cancelAll(); jobFinished( false ); return; } // parse extra info else if ( text.contains( "detected extended VCD2.0 PBC files" ) ) emit infoMessage( i18n( "detected extended VCD2.0 PBC files" ), K3bJob::INFO ); // parse startposition and extracting sequence info // extracting avseq05.mpg... (start lsn 32603 (+28514)) else if ( text.startsWith( "extracting" ) ) { if ( text.contains( "(start lsn" ) ) { int index = text.find( "(start lsn" ); int end = text.find( " (+" ); if ( end > 0) { m_subPosition = text.mid( index + 11, end - index - 11 ).stripWhiteSpace().toLong(); } else { // found segment here we can get only the start lsn :) // extracting item0001.mpg... (start lsn 225, 1 segments) int end = text.find( ",", index ); int overallPos = text.mid( index + 11, end - index - 11 ).stripWhiteSpace().toLong(); double relOverallWritten = ( ( double ) overallPos * 2352 ) / ( double ) m_videooptions ->getVideoCdSize() ; int newpercent = ( int ) ( 100 * relOverallWritten ); if ( newpercent > m_oldpercent ) { emit percent( newpercent ); m_oldpercent = newpercent; } } index = 11; end = text.find( "(start lsn" ); emit newSubTask( i18n( "Extracting %1" ).tqarg( text.mid( index, end - index ).stripWhiteSpace() ) ); } // parse extracting files info // extracting CDI/CDI_IMAG.RTF to _cdi_cdi_imag.rtf (lsn 258, size 1315168, raw 1) else if ( text.contains( "(lsn" ) && text.contains( "size" ) ) { int index = 11; int end = text.find( "to" ); TQString extractFileName = text.mid( index, end - index ).stripWhiteSpace(); index = text.find( " to " ); end = text.find( " (lsn" ); TQString toFileName = text.mid( index + 4, end - index - 4 ).stripWhiteSpace(); emit newSubTask( i18n( "Extracting %1 to %2" ).tqarg( extractFileName ).tqarg( toFileName ) ); } } } TQString K3bVideoCdRip::jobDescription() const { return i18n( "Extracting %1" ).tqarg( m_videooptions ->getVideoCdDescription() ); } TQString K3bVideoCdRip::jobDetails() const { return TQString( "(%1)" ).arg ( KIO::convertSize( m_videooptions ->getVideoCdSize() ) ); } #include "k3bvideocdrip.moc"