File indexing completed on 2024-05-12 04:51:52

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 "k3bvideodvdrippingjob.h"
0009 
0010 #include "k3bvideodvdtitletranscodingjob.h"
0011 #include "k3bvideodvdtitledetectclippingjob.h"
0012 
0013 #include <QDebug>
0014 #include <KLocalizedString>
0015 
0016 
0017 K3b::VideoDVDRippingJob::TitleRipInfo::TitleRipInfo()
0018     : title(1),
0019       audioStream(0),
0020       width(0),
0021       height(0),
0022       videoBitrate(0),
0023       clipTop(0),
0024       clipLeft(0),
0025       clipBottom(0),
0026       clipRight(0)
0027 {
0028 }
0029 
0030 
0031 K3b::VideoDVDRippingJob::TitleRipInfo::TitleRipInfo( int _title,
0032                                                      int _audioStream,
0033                                                      const QString& fn,
0034                                                      int _width,
0035                                                      int _height,
0036                                                      int _videoBitrate,
0037                                                      int _clipTop,
0038                                                      int _clipLeft,
0039                                                      int _clipBottom,
0040                                                      int _clipRight )
0041     : title(_title),
0042       audioStream(_audioStream),
0043       filename(fn),
0044       width(_width),
0045       height(_height),
0046       videoBitrate(_videoBitrate),
0047       clipTop(_clipTop),
0048       clipLeft(_clipLeft),
0049       clipBottom(_clipBottom),
0050       clipRight(_clipRight)
0051 {
0052 }
0053 
0054 
0055 
0056 class K3b::VideoDVDRippingJob::Private {
0057 public:
0058     Private()
0059         : autoClipping( true ) {
0060     }
0061 
0062     int currentTitleInfoIndex;
0063     bool autoClipping;
0064 
0065     bool canceled;
0066 
0067     int videoBitrate;
0068 
0069     int failedTitles;
0070 
0071     QVector<double> titleProgressParts;
0072     QVector<double> titleClippingProgressParts;
0073 };
0074 
0075 
0076 
0077 K3b::VideoDVDRippingJob::VideoDVDRippingJob( K3b::JobHandler* hdl, QObject* parent )
0078     : K3b::Job( hdl, parent )
0079 {
0080     d = new Private();
0081 
0082     m_transcodingJob = new K3b::VideoDVDTitleTranscodingJob( this, this );
0083     connectSubJob( m_transcodingJob,
0084                    SLOT(slotTranscodingJobFinished(bool)),
0085                    SIGNAL(newTask(QString)),
0086                    SIGNAL(newSubTask(QString)),
0087                    SLOT(slotTranscodingProgress(int)),
0088                    SIGNAL(subPercent(int)),
0089                    0,
0090                    0 );
0091     m_detectClippingJob = 0;
0092 }
0093 
0094 
0095 K3b::VideoDVDRippingJob::~VideoDVDRippingJob()
0096 {
0097     delete d;
0098 }
0099 
0100 
0101 QString K3b::VideoDVDRippingJob::jobDescription() const
0102 {
0103     return i18n("Ripping Video DVD Titles");
0104 }
0105 
0106 
0107 QString K3b::VideoDVDRippingJob::jobDetails() const
0108 {
0109     return i18np("Transcoding 1 title to %2/%3", "Transcoding %1 titles to %2/%3", m_titleRipInfos.count(),
0110                  K3b::VideoDVDTitleTranscodingJob::videoCodecString( m_transcodingJob->videoCodec() ) ,
0111                  K3b::VideoDVDTitleTranscodingJob::audioCodecString( m_transcodingJob->audioCodec() ) );
0112 }
0113 
0114 
0115 void K3b::VideoDVDRippingJob::start()
0116 {
0117     jobStarted();
0118     d->canceled = false;
0119     d->failedTitles = 0;
0120 
0121     initProgressInfo();
0122 
0123     if( d->autoClipping )
0124         startDetectClipping( 0 );
0125     else
0126         startTranscoding( 0 );
0127 }
0128 
0129 
0130 void K3b::VideoDVDRippingJob::slotTranscodingJobFinished( bool success )
0131 {
0132     if( d->canceled ) {
0133         emit canceled();
0134         jobFinished( false );
0135     }
0136     else {
0137         if( success )
0138             emit infoMessage( i18n("Successfully ripped title %1 to '%2'",
0139                                    m_titleRipInfos[d->currentTitleInfoIndex].title,
0140                                    m_titleRipInfos[d->currentTitleInfoIndex].filename ), MessageSuccess );
0141         else {
0142             d->failedTitles++;
0143             emit infoMessage( i18n("Failed to rip title %1", m_titleRipInfos[d->currentTitleInfoIndex].title), MessageError );
0144         }
0145 
0146         ++d->currentTitleInfoIndex ;
0147         if( d->currentTitleInfoIndex < m_titleRipInfos.count() ) {
0148             if( d->autoClipping )
0149                 startDetectClipping( d->currentTitleInfoIndex );
0150             else
0151                 startTranscoding( d->currentTitleInfoIndex );
0152         }
0153         else {
0154             jobFinished( d->failedTitles == 0 );
0155         }
0156     }
0157 }
0158 
0159 
0160 void K3b::VideoDVDRippingJob::slotDetectClippingJobFinished( bool success )
0161 {
0162     if( d->canceled ) {
0163         emit canceled();
0164         jobFinished( false );
0165     }
0166     else {
0167         m_titleRipInfos[d->currentTitleInfoIndex].clipTop = 0;
0168         m_titleRipInfos[d->currentTitleInfoIndex].clipLeft = 0;
0169         m_titleRipInfos[d->currentTitleInfoIndex].clipBottom = 0;
0170         m_titleRipInfos[d->currentTitleInfoIndex].clipRight = 0;
0171 
0172         if( success ) {
0173             emit infoMessage( i18n("Determined clipping values for title %1",m_titleRipInfos[d->currentTitleInfoIndex].title), MessageSuccess );
0174             emit infoMessage( i18n("Top: %1, Bottom: %2", m_detectClippingJob->clippingTop(), m_detectClippingJob->clippingBottom()), MessageInfo );
0175             emit infoMessage( i18n("Left: %1, Right: %2", m_detectClippingJob->clippingLeft(), m_detectClippingJob->clippingRight()), MessageInfo );
0176 
0177             // let's see if the clipping values make sense
0178             if( m_detectClippingJob->clippingTop() + m_detectClippingJob->clippingBottom()
0179                 >= (int)m_dvd[d->currentTitleInfoIndex].videoStream().pictureHeight() ||
0180                 m_detectClippingJob->clippingLeft() + m_detectClippingJob->clippingRight()
0181                 >= (int)m_dvd[d->currentTitleInfoIndex].videoStream().pictureWidth() ) {
0182                 emit infoMessage( i18n("Insane clipping values. No clipping will be done at all."), MessageWarning );
0183             }
0184             else {
0185                 m_titleRipInfos[d->currentTitleInfoIndex].clipTop = m_detectClippingJob->clippingTop();
0186                 m_titleRipInfos[d->currentTitleInfoIndex].clipLeft = m_detectClippingJob->clippingLeft();
0187                 m_titleRipInfos[d->currentTitleInfoIndex].clipBottom = m_detectClippingJob->clippingBottom();
0188                 m_titleRipInfos[d->currentTitleInfoIndex].clipRight = m_detectClippingJob->clippingRight();
0189             }
0190         }
0191         else
0192             emit infoMessage( i18n("Failed to determine clipping values for title %1",m_titleRipInfos[d->currentTitleInfoIndex].title), MessageError );
0193 
0194         startTranscoding( d->currentTitleInfoIndex );
0195     }
0196 }
0197 
0198 
0199 void K3b::VideoDVDRippingJob::startTranscoding( int ripInfoIndex )
0200 {
0201     d->currentTitleInfoIndex = ripInfoIndex;
0202 
0203     m_transcodingJob->setVideoDVD( m_dvd );
0204     m_transcodingJob->setTitle( m_titleRipInfos[ripInfoIndex].title );
0205     m_transcodingJob->setAudioStream( m_titleRipInfos[ripInfoIndex].audioStream );
0206     m_transcodingJob->setClipping( m_titleRipInfos[ripInfoIndex].clipTop,
0207                                    m_titleRipInfos[ripInfoIndex].clipLeft,
0208                                    m_titleRipInfos[ripInfoIndex].clipBottom,
0209                                    m_titleRipInfos[ripInfoIndex].clipRight );
0210     m_transcodingJob->setSize( m_titleRipInfos[ripInfoIndex].width, m_titleRipInfos[ripInfoIndex].height );
0211     m_transcodingJob->setFilename( m_titleRipInfos[ripInfoIndex].filename );
0212 
0213     if( m_titleRipInfos[ripInfoIndex].videoBitrate > 0 )
0214         m_transcodingJob->setVideoBitrate( m_titleRipInfos[ripInfoIndex].videoBitrate );
0215     else
0216         m_transcodingJob->setVideoBitrate( d->videoBitrate );
0217 
0218     m_transcodingJob->start();
0219 }
0220 
0221 
0222 void K3b::VideoDVDRippingJob::startDetectClipping( int ripInfoIndex )
0223 {
0224     d->currentTitleInfoIndex = ripInfoIndex;
0225 
0226     if( !m_detectClippingJob ) {
0227         m_detectClippingJob = new K3b::VideoDVDTitleDetectClippingJob( this, this );
0228         connectSubJob( m_detectClippingJob,
0229                        SLOT(slotDetectClippingJobFinished(bool)),
0230                        SIGNAL(newTask(QString)),
0231                        SIGNAL(newSubTask(QString)),
0232                        SLOT(slotDetectClippingProgress(int)),
0233                        SIGNAL(subPercent(int)),
0234                        0,
0235                        0 );
0236     }
0237 
0238     m_detectClippingJob->setVideoDVD( m_dvd );
0239     m_detectClippingJob->setTitle( m_titleRipInfos[ripInfoIndex].title );
0240     m_detectClippingJob->setLowPriority( m_transcodingJob->lowPriority() );
0241 
0242     m_detectClippingJob->start();
0243 }
0244 
0245 
0246 void K3b::VideoDVDRippingJob::slotTranscodingProgress( int p )
0247 {
0248     // calculate the part already done
0249     double doneParts = 0.0;
0250     for( int i = 0; i < d->currentTitleInfoIndex; ++i ) {
0251         doneParts += d->titleProgressParts[i];
0252         if( d->autoClipping )
0253             doneParts += d->titleClippingProgressParts[i];
0254     }
0255     if( d->autoClipping )
0256         doneParts += d->titleClippingProgressParts[d->currentTitleInfoIndex];
0257 
0258     // and the current thing
0259     doneParts += (double)p/100.0*d->titleProgressParts[d->currentTitleInfoIndex];
0260 
0261     emit percent( (int)( 100.0*doneParts ) );
0262 }
0263 
0264 
0265 void K3b::VideoDVDRippingJob::slotDetectClippingProgress( int p )
0266 {
0267     // calculate the part already done
0268     double doneParts = 0.0;
0269     for( int i = 0; i < d->currentTitleInfoIndex; ++i ) {
0270         doneParts += d->titleProgressParts[i];
0271         doneParts += d->titleClippingProgressParts[i];
0272     }
0273 
0274     // and the current thing
0275     doneParts += (double)p/100.0*d->titleClippingProgressParts[d->currentTitleInfoIndex];
0276 
0277     emit percent( (int)( 100.0*doneParts ) );
0278 }
0279 
0280 
0281 void K3b::VideoDVDRippingJob::cancel()
0282 {
0283     d->canceled = true;
0284     if( m_transcodingJob->active() )
0285         m_transcodingJob->cancel();
0286     else if( m_detectClippingJob && m_detectClippingJob->active() )
0287         m_detectClippingJob->cancel();
0288 }
0289 
0290 
0291 void K3b::VideoDVDRippingJob::setVideoCodec( K3b::VideoDVDTitleTranscodingJob::VideoCodec codec )
0292 {
0293     m_transcodingJob->setVideoCodec( codec );
0294 }
0295 
0296 
0297 void K3b::VideoDVDRippingJob::setVideoBitrate( int bitrate )
0298 {
0299     d->videoBitrate = bitrate;
0300 }
0301 
0302 
0303 void K3b::VideoDVDRippingJob::setTwoPassEncoding( bool b )
0304 {
0305     m_transcodingJob->setTwoPassEncoding( b );
0306 }
0307 
0308 
0309 void K3b::VideoDVDRippingJob::setAudioCodec( K3b::VideoDVDTitleTranscodingJob::AudioCodec codec )
0310 {
0311     m_transcodingJob->setAudioCodec( codec );
0312 }
0313 
0314 
0315 void K3b::VideoDVDRippingJob::setAudioBitrate( int bitrate )
0316 {
0317     m_transcodingJob->setAudioBitrate( bitrate );
0318 }
0319 
0320 
0321 void K3b::VideoDVDRippingJob::setAudioVBR( bool vbr )
0322 {
0323     m_transcodingJob->setAudioVBR( vbr );
0324 }
0325 
0326 
0327 void K3b::VideoDVDRippingJob::setResampleAudioTo44100( bool b )
0328 {
0329     m_transcodingJob->setResampleAudioTo44100( b );
0330 }
0331 
0332 
0333 void K3b::VideoDVDRippingJob::setLowPriority( bool b )
0334 {
0335     m_transcodingJob->setLowPriority( b );
0336 }
0337 
0338 
0339 void K3b::VideoDVDRippingJob::setAutoClipping( bool b )
0340 {
0341     d->autoClipping = b;
0342 }
0343 
0344 
0345 void K3b::VideoDVDRippingJob::initProgressInfo()
0346 {
0347     d->titleProgressParts.resize( m_titleRipInfos.count() );
0348     d->titleClippingProgressParts.resize( m_titleRipInfos.count() );
0349 
0350     unsigned long long totalFrames = 0ULL;
0351     for( int i = 0; i < m_titleRipInfos.count(); ++i ) {
0352         if( m_transcodingJob->twoPassEncoding() )
0353             totalFrames += m_dvd[m_titleRipInfos[i].title-1].playbackTime().totalFrames() * 2;
0354         else
0355             totalFrames += m_dvd[m_titleRipInfos[i].title-1].playbackTime().totalFrames();
0356 
0357         // using my knowledge of the internals of the clipping detection job: it decodes 200 frames
0358         // of every chapter
0359         if( d->autoClipping )
0360             totalFrames += m_dvd[m_titleRipInfos[i].title-1].numChapters() * 200;
0361     }
0362 
0363     for( int i = 0; i < m_titleRipInfos.count(); ++i ) {
0364         unsigned long long titleFrames = m_dvd[m_titleRipInfos[i].title-1].playbackTime().totalFrames();
0365         if( m_transcodingJob->twoPassEncoding() )
0366             titleFrames *= 2;
0367 
0368         // using my knowledge of the internals of the clipping detection job: it decodes 200 frames
0369         // of every chapter
0370         unsigned long long titleClippingFrames = m_dvd[m_titleRipInfos[i].title-1].numChapters() * 200;
0371 
0372         if (totalFrames) {
0373             d->titleProgressParts[i] = (double)titleFrames/(double)totalFrames;
0374             d->titleClippingProgressParts[i] = (double)titleClippingFrames/(double)totalFrames;
0375         }
0376     }
0377 }
0378 
0379 #include "moc_k3bvideodvdrippingjob.cpp"