File indexing completed on 2024-05-05 04:50:58
0001 /* 0002 SPDX-FileCopyrightText: 2006-2009 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "k3bvideodvdtitledetectclippingjob.h" 0009 0010 #include "k3bexternalbinmanager.h" 0011 #include "k3bprocess.h" 0012 #include "k3bcore.h" 0013 #include "k3bglobals.h" 0014 #include "k3b_i18n.h" 0015 0016 #include <QDebug> 0017 0018 0019 static const int s_unrealisticHighClippingValue = 100000; 0020 0021 0022 class K3b::VideoDVDTitleDetectClippingJob::Private 0023 { 0024 public: 0025 const K3b::ExternalBin* usedTranscodeBin; 0026 0027 K3b::Process* process; 0028 0029 bool canceled; 0030 0031 unsigned int currentChapter; 0032 unsigned int currentFrames; 0033 unsigned int totalChapters; 0034 0035 int lastProgress; 0036 int lastSubProgress; 0037 }; 0038 0039 0040 0041 K3b::VideoDVDTitleDetectClippingJob::VideoDVDTitleDetectClippingJob( K3b::JobHandler* hdl, QObject* parent ) 0042 : K3b::Job( hdl, parent ), 0043 m_clippingTop( 0 ), 0044 m_clippingBottom( 0 ), 0045 m_clippingLeft( 0 ), 0046 m_clippingRight( 0 ), 0047 m_lowPriority( true ) 0048 { 0049 d = new Private; 0050 d->process = 0; 0051 } 0052 0053 0054 K3b::VideoDVDTitleDetectClippingJob::~VideoDVDTitleDetectClippingJob() 0055 { 0056 delete d->process; 0057 delete d; 0058 } 0059 0060 0061 void K3b::VideoDVDTitleDetectClippingJob::start() 0062 { 0063 jobStarted(); 0064 0065 d->canceled = false; 0066 d->lastProgress = 0; 0067 0068 // 0069 // It seems as if the last chapter is often way too short 0070 // 0071 d->totalChapters = m_dvd[m_titleNumber-1].numPTTs(); 0072 if( d->totalChapters > 1 && m_dvd[m_titleNumber-1][d->totalChapters-1].playbackTime().totalFrames() < 200 ) 0073 d->totalChapters--; 0074 0075 // initial values (some way to big value) 0076 m_clippingTop = s_unrealisticHighClippingValue; 0077 m_clippingBottom = s_unrealisticHighClippingValue; 0078 m_clippingLeft = s_unrealisticHighClippingValue; 0079 m_clippingRight = s_unrealisticHighClippingValue; 0080 0081 d->usedTranscodeBin = k3bcore->externalBinManager()->binObject("transcode"); 0082 if( !d->usedTranscodeBin ) { 0083 emit infoMessage( i18n("%1 executable could not be found.",QString("transcode")), MessageError ); 0084 jobFinished( false ); 0085 return; 0086 } 0087 0088 if( d->usedTranscodeBin->version() < K3b::Version( 1, 0, 0 ) ){ 0089 emit infoMessage( i18n("%1 version %2 is too old.", 0090 QString("transcode") 0091 ,d->usedTranscodeBin->version()), MessageError ); 0092 jobFinished( false ); 0093 return; 0094 } 0095 0096 emit debuggingOutput( QLatin1String( "Used versions" ), QString::fromLatin1( "transcode: %1" ).arg(d->usedTranscodeBin->version()) ); 0097 0098 if( !d->usedTranscodeBin->copyright().isEmpty() ) 0099 emit infoMessage( i18n("Using %1 %2 – Copyright © %3" 0100 ,d->usedTranscodeBin->name() 0101 ,d->usedTranscodeBin->version() 0102 ,d->usedTranscodeBin->copyright()), MessageInfo ); 0103 0104 emit newTask( i18n("Analysing Title %1 of Video DVD %2",m_titleNumber,m_dvd.volumeIdentifier()) ); 0105 0106 startTranscode( 1 ); 0107 } 0108 0109 0110 void K3b::VideoDVDTitleDetectClippingJob::startTranscode( int chapter ) 0111 { 0112 d->currentChapter = chapter; 0113 d->lastSubProgress = 0; 0114 0115 // 0116 // If we have only one chapter and it is not longer than 2 minutes (value guessed based on some test DVD) 0117 // use the whole chapter 0118 // 0119 if( d->totalChapters == 1 ) 0120 d->currentFrames = qMin( 3000, qMax( 1, ( int )m_dvd[m_titleNumber-1][d->currentChapter-1].playbackTime().totalFrames() ) ); 0121 else 0122 d->currentFrames = qMin( 200, qMax( 1, ( int )m_dvd[m_titleNumber-1][d->currentChapter-1].playbackTime().totalFrames() ) ); 0123 0124 // 0125 // prepare the process 0126 // 0127 delete d->process; 0128 d->process = new K3b::Process(); 0129 d->process->setSuppressEmptyLines(true); 0130 d->process->setSplitStdout(true); 0131 connect( d->process, SIGNAL(stdoutLine(QString)), this, SLOT(slotTranscodeStderr(QString)) ); 0132 connect( d->process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotTranscodeExited(int,QProcess::ExitStatus)) ); 0133 0134 // the executable 0135 *d->process << d->usedTranscodeBin; 0136 0137 // low priority 0138 if( m_lowPriority ) 0139 *d->process << "--nice" << "19"; 0140 0141 if ( d->usedTranscodeBin->version() >= Version( 1, 1, 0 ) ) 0142 *d->process << "--log_no_color"; 0143 0144 // the input 0145 *d->process << "-i" << m_dvd.device()->blockDeviceName(); 0146 0147 // select the title number and chapter 0148 *d->process << "-T" << QString("%1,%2").arg(m_titleNumber).arg(chapter); 0149 0150 // null output 0151 *d->process << "-y" << "null,null" << "-o" << "/dev/null"; 0152 0153 // analyze the first 200 frames 0154 *d->process << "-J" << QString("detectclipping=range=0-%1/5").arg(d->currentFrames); 0155 0156 // also only decode the first 200 frames 0157 *d->process << "-c" << QString("0-%1").arg(d->currentFrames+1); 0158 0159 // additional user parameters from config 0160 const QStringList& params = d->usedTranscodeBin->userParameters(); 0161 for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) 0162 *d->process << *it; 0163 0164 // produce some debugging output 0165 qDebug() << "***** transcode parameters:\n"; 0166 QString s = d->process->joinedArgs(); 0167 qDebug() << s << Qt::flush; 0168 emit debuggingOutput( d->usedTranscodeBin->name() + " command:", s); 0169 0170 // start the process 0171 if( !d->process->start( KProcess::MergedChannels ) ) { 0172 // something went wrong when starting the program 0173 // it "should" be the executable 0174 emit infoMessage( i18n("Could not start %1.",d->usedTranscodeBin->name()), K3b::Job::MessageError ); 0175 jobFinished(false); 0176 } 0177 else { 0178 emit newSubTask( i18n("Analysing Chapter %1 of %2",chapter,m_dvd[m_titleNumber-1].numPTTs()) ); 0179 emit subPercent( 0 ); 0180 } 0181 } 0182 0183 0184 void K3b::VideoDVDTitleDetectClippingJob::cancel() 0185 { 0186 d->canceled = true; 0187 if( d->process && d->process->isRunning() ) 0188 d->process->kill(); 0189 } 0190 0191 0192 void K3b::VideoDVDTitleDetectClippingJob::slotTranscodeStderr( const QString& line ) 0193 { 0194 emit debuggingOutput( "transcode", line ); 0195 0196 // parse progress 0197 // encoding frame [185], 24.02 fps, 93.0%, ETA: 0:00:00, ( 0| 0| 0) 0198 if( line.startsWith( "encoding frame" ) ) { 0199 int pos1 = line.indexOf( '[', 15 ); 0200 int pos2 = line.indexOf( ']', pos1+1 ); 0201 if( pos1 > 0 && pos2 > 0 ) { 0202 bool ok; 0203 int encodedFrames = line.mid( pos1+1, pos2-pos1-1 ).toInt( &ok ); 0204 if( ok ) { 0205 int progress = 100 * encodedFrames / d->currentFrames; 0206 0207 if( progress > d->lastSubProgress ) { 0208 d->lastSubProgress = progress; 0209 emit subPercent( progress ); 0210 } 0211 0212 double part = 100.0 / (double)d->totalChapters; 0213 0214 progress = (int)( ( (double)(d->currentChapter-1) * part ) 0215 + ( (double)progress / (double)d->totalChapters ) 0216 + 0.5 ); 0217 0218 if( progress > d->lastProgress ) { 0219 d->lastProgress = progress; 0220 emit percent( progress ); 0221 } 0222 } 0223 } 0224 } 0225 0226 // [detectclipping#0] valid area: X: 5..719 Y: 72..507 -> -j 72,6,68,0 0227 else if( line.startsWith( "[detectclipping" ) ) { 0228 int pos = line.indexOf( "-j" ); 0229 if( pos > 0 ) { 0230 QStringList values = line.mid( pos+3 ).split( ',' ); 0231 m_clippingTop = qMin( m_clippingTop, values[0].toInt() ); 0232 m_clippingLeft = qMin( m_clippingLeft, values[1].toInt() ); 0233 m_clippingBottom = qMin( m_clippingBottom, values[2].toInt() ); 0234 m_clippingRight = qMin( m_clippingRight, values[3].toInt() ); 0235 } 0236 else 0237 qDebug() << "(K3b::VideoDVDTitleDetectClippingJob) failed to parse line: " << line; 0238 } 0239 } 0240 0241 0242 void K3b::VideoDVDTitleDetectClippingJob::slotTranscodeExited( int exitCode, QProcess::ExitStatus ) 0243 { 0244 switch( exitCode ) { 0245 case 0: 0246 d->currentChapter++; 0247 if( d->currentChapter > d->totalChapters ) { 0248 // 0249 // check if we did set any values at all 0250 // 0251 if( m_clippingTop == s_unrealisticHighClippingValue ) 0252 m_clippingTop = m_clippingLeft = m_clippingBottom = m_clippingRight = 0; 0253 0254 if( d->totalChapters < m_dvd[m_titleNumber-1].numPTTs() ) 0255 emit infoMessage( i18n("Ignoring clipping values of last chapter due to its short playback time."), MessageInfo ); 0256 0257 jobFinished( true ); 0258 } 0259 else { 0260 startTranscode( d->currentChapter ); 0261 } 0262 break; 0263 0264 default: 0265 // FIXME: error handling 0266 0267 if( d->canceled ) { 0268 emit canceled(); 0269 } 0270 else { 0271 emit infoMessage( i18n("%1 returned an unknown error (code %2).", 0272 d->usedTranscodeBin->name(), exitCode ), 0273 K3b::Job::MessageError ); 0274 emit infoMessage( i18n("Please send me an email with the last output."), K3b::Job::MessageError ); 0275 } 0276 0277 jobFinished( false ); 0278 } 0279 } 0280 0281 #include "moc_k3bvideodvdtitledetectclippingjob.cpp"