File indexing completed on 2025-03-16 04:29:31
0001 /* 0002 SPDX-FileCopyrightText: 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 "k3bmetawriter.h" 0009 #include "k3bcdrecordwriter.h" 0010 #include "k3bcdrskinwriter.h" 0011 #include "k3bcdrdaowriter.h" 0012 #include "k3bgrowisofswriter.h" 0013 #include "k3btocfilewriter.h" 0014 #include "k3binffilewriter.h" 0015 0016 #include "k3bexternalbinmanager.h" 0017 #include "k3bglobals.h" 0018 #include "k3btrack.h" 0019 #include "k3btoc.h" 0020 #include "k3bmedium.h" 0021 #include "k3bcore.h" 0022 #include "k3bmediacache.h" 0023 #include "k3bdevicetypes.h" 0024 #include "k3bdeviceglobals.h" 0025 #include "k3b_i18n.h" 0026 0027 #include <QFile> 0028 0029 0030 class K3b::MetaWriter::Private 0031 { 0032 public: 0033 Private() 0034 : writingApp(WritingAppAuto), 0035 writingMode(WritingModeAuto), 0036 clone(false), 0037 multiSession(false), 0038 layerBreak(0), 0039 hideFirstTrack(false), 0040 supportedWritingMedia(Device::MEDIA_WRITABLE), 0041 writingJob(0) { 0042 } 0043 0044 // member vars set via setXXX methods 0045 // ---------------------------------- 0046 WritingApp writingApp; 0047 WritingMode writingMode; 0048 QString cueFile; 0049 bool clone; 0050 bool multiSession; 0051 Device::CdText cdText; 0052 qint64 layerBreak; 0053 bool hideFirstTrack; 0054 Device::Toc toc; 0055 Device::MediaTypes supportedWritingMedia; 0056 QStringList images; 0057 // ---------------------------------- 0058 0059 0060 // status vars 0061 // ---------------------------------- 0062 WritingApp usedWritingApp; 0063 WritingMode usedWritingMode; 0064 0065 AbstractWriter* writingJob; 0066 0067 QVector<QString> infFiles; 0068 QString tocFile; 0069 // ---------------------------------- 0070 0071 0072 void prepareTempFileNames( const QString& path = QString() ) 0073 { 0074 infFiles.clear(); 0075 0076 QString prefix = K3b::findUniqueFilePrefix( "k3b_tmp_", path ) + '_'; 0077 0078 for( int i = 0; i < toc.count(); ++i ) { 0079 infFiles.append( prefix + QString::number( i+1 ).rightJustified( 2, '0' ) + ".inf" ); 0080 } 0081 0082 tocFile = prefix + ".toc"; 0083 } 0084 0085 QString tocFileName() 0086 { 0087 if( tocFile.isEmpty() ) 0088 prepareTempFileNames(); 0089 return tocFile; 0090 } 0091 0092 QString infFileName( int track ) 0093 { 0094 if( infFiles.count() < track ) 0095 prepareTempFileNames(); 0096 return infFiles.at( track - 1 ); 0097 } 0098 0099 void cleanupTempFiles() 0100 { 0101 for( int i = 0; i < infFiles.count(); ++i ) { 0102 if( QFile::exists( infFiles[i] ) ) 0103 QFile::remove( infFiles[i] ); 0104 } 0105 0106 if( QFile::exists( tocFile ) ) 0107 QFile::remove( tocFile ); 0108 0109 tocFile.truncate(0); 0110 } 0111 }; 0112 0113 0114 K3b::MetaWriter::MetaWriter( Device::Device* dev, JobHandler* hdl, QObject* parent ) 0115 : AbstractWriter( dev, hdl, parent ), 0116 d(new Private()) 0117 { 0118 } 0119 0120 0121 K3b::MetaWriter::~MetaWriter() 0122 { 0123 delete d->writingJob; 0124 delete d; 0125 } 0126 0127 0128 QIODevice* K3b::MetaWriter::ioDevice() const 0129 { 0130 if( d->writingJob ) 0131 return d->writingJob->ioDevice(); 0132 else 0133 return 0; 0134 } 0135 0136 0137 void K3b::MetaWriter::start() 0138 { 0139 jobStarted(); 0140 0141 // step 1: see if we are set up correctly 0142 if( !ensureSettingsIntegrity() ) { 0143 jobFinished( false ); 0144 return; 0145 } 0146 0147 if( !determineUsedAppAndMode() ) { 0148 jobFinished( false ); 0149 return; 0150 } 0151 0152 delete d->writingJob; 0153 d->writingJob = 0; 0154 0155 bool success = true; 0156 switch( d->usedWritingApp ) { 0157 case K3b::WritingAppCdrecord: 0158 success = setupCdrecordJob(); 0159 break; 0160 case K3b::WritingAppCdrdao: 0161 success = setupCdrdaoJob(); 0162 break; 0163 case K3b::WritingAppGrowisofs: 0164 success = setupGrowisofsob(); 0165 break; 0166 case K3b::WritingAppCdrskin: 0167 success = setupCdrskinJob(); 0168 break; 0169 default: 0170 Q_ASSERT(false); 0171 break; 0172 } 0173 0174 if( !success ) { 0175 jobFinished( false ); 0176 return; 0177 } 0178 0179 informUser(); 0180 0181 connectJob( d->writingJob, SLOT(slotWritingJobFinished(bool)) ); 0182 connect( d->writingJob, SIGNAL(buffer(int)), 0183 this, SIGNAL(buffer(int)) ); 0184 connect( d->writingJob, SIGNAL(deviceBuffer(int)), 0185 this, SIGNAL(deviceBuffer(int)) ); 0186 connect( d->writingJob, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)), 0187 this, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)) ); 0188 connect( d->writingJob, SIGNAL(nextTrack(int,int)), 0189 this, SIGNAL(nextTrack(int,int)) ); 0190 0191 d->writingJob->start(); 0192 } 0193 0194 0195 bool K3b::MetaWriter::ensureSettingsIntegrity() 0196 { 0197 if( d->toc.isEmpty() && d->cueFile.isEmpty() ) { 0198 emit infoMessage( QLatin1String("Internal error: job not setup properly: cue file and toc set! " 0199 "The application needs fixing!"), MessageError ); 0200 return false; 0201 } 0202 else if( !d->images.isEmpty() && d->images.count() != d->toc.count() ) { 0203 emit infoMessage( QLatin1String("Internal error: job not setup properly: image count != track count! " 0204 "The application needs fixing!"), MessageError ); 0205 return false; 0206 } 0207 else if( d->toc.contentType() == Device::MIXED ) { 0208 int dtc = 0; 0209 for( int i = 0; i < d->toc.count(); ++i ) { 0210 Device::Track track = d->toc[i]; 0211 if( track.type() == Device::Track::TYPE_DATA ) { 0212 if( i > 0 && i+1 == d->toc.count() ) { 0213 emit infoMessage( QLatin1String("Internal error: job not setup properly: can only handle data tracks at the beginning or end of toc! " 0214 "The application needs fixing!"), MessageError ); 0215 return false; 0216 } 0217 ++dtc; 0218 } 0219 } 0220 if( dtc > 1 ) { 0221 emit infoMessage( QLatin1String("Internal error: job not setup properly: cannot handle more than one data track in a session! " 0222 "The application needs fixing!"), MessageError ); 0223 return false; 0224 } 0225 } 0226 0227 return true; 0228 } 0229 0230 0231 bool K3b::MetaWriter::determineUsedAppAndMode() 0232 { 0233 // ============================================= 0234 // Get the burn medium 0235 // ============================================= 0236 0237 Device::MediaTypes mt = d->supportedWritingMedia; 0238 // a little bit of restricting 0239 if( d->writingMode == K3b::WritingModeRestrictedOverwrite ) // we treat DVD+R(W) as restricted overwrite media 0240 mt = K3b::Device::MEDIA_DVD_RW_OVWR|K3b::Device::MEDIA_DVD_PLUS_RW|K3b::Device::MEDIA_DVD_PLUS_R; 0241 else if( d->writingMode == K3b::WritingModeIncrementalSequential ) 0242 mt ^= Device::MEDIA_CD_ALL; 0243 else if( d->writingMode == K3b::WritingModeRaw ) 0244 mt ^= (Device::MEDIA_DVD_ALL|Device::MEDIA_BD_ALL); 0245 0246 Device::MediaType mediaType = waitForMedium( burnDevice(), Device::STATE_EMPTY, mt ); 0247 if( mediaType == Device::MEDIA_UNKNOWN ) 0248 return false; 0249 0250 Medium medium = k3bcore->mediaCache()->medium( burnDevice() ); 0251 0252 0253 // ============================================= 0254 // Some values we need later on 0255 // ============================================= 0256 0257 bool onTheFly = d->cueFile.isEmpty() && d->images.isEmpty(); 0258 bool cdrecordOnTheFly = false; 0259 bool cdrecordCdText = false; 0260 bool cdrecordBluRay = false; 0261 bool cdrecordWodim = false; 0262 bool growisofsBluRay = false; 0263 const K3b::ExternalBin* cdrecordBin = k3bcore->externalBinManager()->binObject("cdrecord"); 0264 if( cdrecordBin ) { 0265 cdrecordOnTheFly = cdrecordBin->hasFeature( "audio-stdin" ); 0266 cdrecordCdText = cdrecordBin->hasFeature( "cdtext" ); 0267 cdrecordBluRay = cdrecordBin->hasFeature( "blu-ray" ); 0268 cdrecordWodim = cdrecordBin->hasFeature( "wodim" ); 0269 } 0270 if( k3bcore->externalBinManager()->binObject("growisofs") ) { 0271 growisofsBluRay = k3bcore->externalBinManager()->binObject("growisofs")->hasFeature( "blu-ray" ); 0272 } 0273 0274 0275 // ============================================= 0276 // Determine writing app 0277 // ============================================= 0278 0279 d->usedWritingApp = d->writingApp; 0280 if( d->writingApp == K3b::WritingAppAuto ) { 0281 if( mediaType & Device::MEDIA_CD_ALL ) { 0282 if( d->usedWritingMode == K3b::WritingModeSao ) { 0283 // there are none-DAO writers that are supported by cdrdao 0284 if( !burnDevice()->dao() || 0285 ( !cdrecordOnTheFly && onTheFly ) || 0286 ( !d->cdText.isEmpty() && !cdrecordCdText ) || 0287 d->hideFirstTrack ) { 0288 d->usedWritingApp = K3b::WritingAppCdrdao; 0289 } 0290 // cdrecord seems to have problems writing xa 1 disks in dao mode? At least on my system! 0291 else if( d->cueFile.isEmpty() && 0292 d->toc.first().mode() != Device::Track::MODE1 ) { 0293 d->usedWritingApp = K3b::WritingAppCdrdao; 0294 } 0295 else { 0296 d->usedWritingApp = K3b::WritingAppCdrecord; 0297 } 0298 } 0299 else 0300 d->usedWritingApp = K3b::WritingAppCdrecord; 0301 } 0302 else { 0303 if ( d->writingApp == K3b::WritingAppCdrdao ) { 0304 emit infoMessage( i18n( "Cannot write %1 media using %2. Falling back to default application.", 0305 K3b::Device::mediaTypeString( mediaType, true ), QLatin1String("cdrdao") ), MessageWarning ); 0306 d->writingApp = K3b::WritingAppAuto; 0307 } 0308 0309 if( d->toc.count() != 1 || d->toc.first().mode() != Device::Track::MODE1 ) { 0310 emit infoMessage( i18n("DVD and Blu-ray tracks can only be written in MODE1."), MessageWarning ); 0311 } 0312 0313 if( mediaType & (K3b::Device::MEDIA_DVD_PLUS_RW|K3b::Device::MEDIA_DVD_RW_OVWR) && 0314 d->multiSession ) { 0315 // we can only do this with growisofs 0316 d->usedWritingApp = WritingAppGrowisofs; 0317 } 0318 else if( mediaType & Device::MEDIA_DVD_ALL ) { 0319 // wodim (at least on fedora) doesn't do DVDs all that well, use growisofs instead 0320 if ( cdrecordWodim ) { 0321 d->usedWritingApp = WritingAppGrowisofs; 0322 } 0323 else { 0324 d->usedWritingApp = WritingAppCdrecord; 0325 } 0326 } 0327 else if( mediaType & Device::MEDIA_BD_ALL ) { 0328 if( cdrecordBluRay && ! cdrecordWodim ) { 0329 d->usedWritingApp = WritingAppCdrecord; 0330 } 0331 else if( growisofsBluRay ) { 0332 d->usedWritingApp = WritingAppGrowisofs; 0333 } 0334 else { 0335 emit infoMessage( i18n("Missing Blu-ray support in cdrecord and growisofs. Please update the system."), MessageError ); 0336 return false; 0337 } 0338 } 0339 } 0340 } 0341 else 0342 d->usedWritingApp = d->writingApp; 0343 0344 0345 // ============================================= 0346 // Determine writing mode 0347 // ============================================= 0348 0349 if( d->writingMode == K3b::WritingModeAuto ) { 0350 if( mediaType & (Device::MEDIA_DVD_PLUS_RW|K3b::Device::MEDIA_DVD_RW_OVWR) ) { 0351 d->usedWritingMode = K3b::WritingModeRestrictedOverwrite; 0352 } 0353 else if( mediaType & Device::MEDIA_DVD_PLUS_ALL ) { 0354 d->usedWritingMode = K3b::WritingModeSao; 0355 } 0356 else if( mediaType & (K3b::Device::MEDIA_DVD_RW_SEQ| 0357 K3b::Device::MEDIA_DVD_RW) ) { 0358 d->usedWritingMode = K3b::WritingModeIncrementalSequential; 0359 } 0360 else if( mediaType & K3b::Device::MEDIA_DVD_MINUS_ALL ) { 0361 if( d->multiSession ) 0362 d->usedWritingMode = K3b::WritingModeIncrementalSequential; 0363 else 0364 d->usedWritingMode = K3b::WritingModeSao; 0365 } 0366 else if( mediaType & Device::MEDIA_CD_ALL ) { 0367 if( !d->cueFile.isEmpty() ) { 0368 d->usedWritingMode = WritingModeSao; 0369 } 0370 else { 0371 if( d->toc.contentType() == Device::MIXED ) { 0372 // when writing mode in one session, TAO is the only choice 0373 // otherwise we need to see what kind of session we write 0374 d->usedWritingMode = WritingModeTao; 0375 } 0376 0377 else if( d->toc.contentType() == Device::DATA ) { 0378 // 0379 // Data sessions are simple: always SAO except if there is multisession involved 0380 // However, if we add a session, even if d->multiSession is false, use TAO! 0381 // 0382 if( burnDevice()->dao() && 0383 d->toc.first().mode() == K3b::Device::Track::MODE1 && 0384 !d->multiSession && 0385 medium.diskInfo().empty() ) 0386 d->usedWritingMode = K3b::WritingModeSao; 0387 else 0388 d->usedWritingMode = K3b::WritingModeTao; 0389 } 0390 else { 0391 // 0392 // there are a lot of writers out there which produce coasters 0393 // in dao mode if the CD contains pregaps of length 0 (or maybe already != 2 secs?) 0394 // 0395 // Also most writers do not accept cuesheets with tracks smaller than 4 seconds (a violation 0396 // of the red book standard) in DAO mode. 0397 // 0398 bool zeroPregap = false; 0399 bool less4Sec = false; 0400 for( int i = 0; i < d->toc.count(); ++i ) { 0401 Device::Track track = d->toc[i]; 0402 0403 if( track.type() != Device::Track::TYPE_AUDIO ) 0404 continue; 0405 0406 if( track.index0() == 0 && i+1 < d->toc.count() ) // the last track's postgap is always 0 0407 zeroPregap = true; 0408 0409 if( track.length() < K3b::Msf( 0, 4, 0 ) ) 0410 less4Sec = true; 0411 } 0412 0413 // 0414 // DAO is always the first choice 0415 // RAW second and TAO last 0416 // there are none-DAO writers that are supported by cdrdao 0417 // 0418 // older cdrecord versions do not support the -shorttrack option in RAW writing mode 0419 // 0420 if( !burnDevice()->dao() && d->usedWritingApp == K3b::WritingAppCdrecord ) { 0421 if( !burnDevice()->supportsRawWriting() && 0422 ( !less4Sec || (cdrecordBin && cdrecordBin->hasFeature( "short-track-raw" ) ) ) ) 0423 d->usedWritingMode = K3b::WritingModeRaw; 0424 else 0425 d->usedWritingMode = K3b::WritingModeTao; 0426 } 0427 else { 0428 if( (zeroPregap || less4Sec) && burnDevice()->supportsRawWriting() ) { 0429 d->usedWritingMode = K3b::WritingModeRaw; 0430 if( less4Sec ) 0431 emit infoMessage( i18n("Track lengths below 4 seconds violate the Red Book standard."), MessageWarning ); 0432 } 0433 else 0434 d->usedWritingMode = K3b::WritingModeSao; 0435 } 0436 } 0437 } 0438 } 0439 else { 0440 // FIXME: what to use for BD? 0441 d->usedWritingMode = K3b::WritingModeSao; 0442 } 0443 } 0444 else { 0445 d->usedWritingMode = d->writingMode; 0446 0447 if( !(mediaType & (K3b::Device::MEDIA_DVD_RW|K3b::Device::MEDIA_DVD_RW_OVWR|K3b::Device::MEDIA_DVD_RW_SEQ)) && 0448 d->writingMode == K3b::WritingModeRestrictedOverwrite ) { 0449 emit infoMessage( i18n("Restricted Overwrite is not possible with DVD-R media."), MessageInfo ); 0450 return false; 0451 } 0452 } 0453 0454 0455 // ============================================= 0456 // Some final checks and safety nets 0457 // ============================================= 0458 0459 // on-the-fly writing with cdrecord >= 2.01a13 0460 if( d->usedWritingApp == K3b::WritingAppCdrecord && 0461 onTheFly && 0462 !cdrecordOnTheFly ) { 0463 emit infoMessage( i18n("On-the-fly writing with cdrecord < 2.01a13 not supported."), MessageError ); 0464 return false; 0465 } 0466 0467 if( d->usedWritingApp == K3b::WritingAppCdrecord && 0468 !d->cdText.isEmpty() ) { 0469 if( !cdrecordCdText ) { 0470 emit infoMessage( i18n("Cdrecord %1 does not support CD-Text writing.", 0471 k3bcore->externalBinManager()->binObject("cdrecord")->version()), MessageError ); 0472 return false; 0473 } 0474 else if( d->usedWritingMode == K3b::WritingModeTao ) { 0475 emit infoMessage( i18n("It is not possible to write CD-Text in TAO mode."), MessageWarning ); 0476 return false; 0477 } 0478 } 0479 0480 if( d->usedWritingMode == K3b::WritingModeIncrementalSequential ) { 0481 if( burnDevice()->featureCurrent( K3b::Device::FEATURE_INCREMENTAL_STREAMING_WRITABLE ) == 0 ) { 0482 if( !questionYesNo( i18n("Your writer (%1 %2) does not support Incremental Streaming with %3 " 0483 "media. Multisession will not be possible. Continue anyway?", 0484 burnDevice()->vendor(), 0485 burnDevice()->description(), 0486 K3b::Device::mediaTypeString(mediaType, true) ), 0487 i18n("No Incremental Streaming") ) ) { 0488 return false; 0489 } 0490 else { 0491 d->usedWritingMode = K3b::WritingModeSao; 0492 } 0493 } 0494 } 0495 0496 if( !(mediaType & (K3b::Device::MEDIA_DVD_RW|K3b::Device::MEDIA_DVD_RW_OVWR|K3b::Device::MEDIA_DVD_RW_SEQ)) && 0497 d->usedWritingMode == K3b::WritingModeRestrictedOverwrite ) { 0498 emit infoMessage( i18n("Restricted Overwrite is not possible with DVD-R media."), MessageInfo ); 0499 } 0500 0501 if( simulate() ) { 0502 if( mediaType & K3b::Device::MEDIA_DVD_PLUS_ALL ) { 0503 if( !questionYesNo( i18n("DVD+R(W) media do not support write simulation. " 0504 "Do you really want to continue? The media will actually be " 0505 "written to."), 0506 i18n("No Simulation with DVD+R(W)") ) ) { 0507 return false; 0508 } 0509 } 0510 else if( mediaType & Device::MEDIA_DVD_MINUS_ALL && 0511 !burnDevice()->dvdMinusTestwrite() ) { 0512 if( !questionYesNo( i18n("Your writer (%1 %2) does not support simulation with DVD-R(W) media. " 0513 "Do you really want to continue? The media will actually be " 0514 "written to.", 0515 burnDevice()->vendor(), 0516 burnDevice()->description()), 0517 i18n("No Simulation with DVD-R(W)") ) ) { 0518 return false; 0519 } 0520 } 0521 } 0522 0523 // cdrecord manpage says that "not all" writers are able to write 0524 // multisession disks in dao mode. That means there are writers that can. 0525 0526 // Does it really make sence to write Data ms cds in DAO mode since writing the 0527 // first session of a cd-extra in DAO mode is no problem with my writer while 0528 // writing the second data session is only possible in TAO mode. 0529 if( mediaType & Device::MEDIA_CD_ALL && 0530 d->usedWritingMode == K3b::WritingModeSao && 0531 d->multiSession ) 0532 emit infoMessage( i18n("Most writers do not support writing " 0533 "multisession CDs in DAO mode."), MessageWarning ); 0534 0535 qDebug() << "Writing mode: " << d->writingMode; 0536 qDebug() << "Used Writing mode:" << d->usedWritingMode; 0537 qDebug() << "Writing app: " << d->writingApp; 0538 qDebug() << "Used Writing app:" << d->usedWritingApp; 0539 0540 return true; 0541 } 0542 0543 0544 bool K3b::MetaWriter::setupCdrecordJob() 0545 { 0546 K3b::CdrecordWriter* writer = new K3b::CdrecordWriter( burnDevice(), this, this ); 0547 d->writingJob = writer; 0548 0549 writer->setWritingMode( d->usedWritingMode ); 0550 writer->setSimulate( simulate() ); 0551 writer->setBurnSpeed( burnSpeed() ); 0552 writer->setMulti( d->multiSession ); 0553 0554 if( d->multiSession && 0555 !d->toc.isEmpty() && 0556 d->images.isEmpty() ) { 0557 writer->addArgument("-waiti"); 0558 } 0559 0560 if( d->cueFile.isEmpty() ) { 0561 bool firstAudioTrack = true; 0562 int audioTrackCnt = 0; 0563 0564 for( int i = 0; i < d->toc.count(); ++i ) { 0565 Device::Track track = d->toc[i]; 0566 QString image; 0567 if( d->images.count() ) 0568 image = d->images[i]; 0569 0570 // 0571 // Add a data track 0572 // 0573 if( track.type() == Device::Track::TYPE_DATA ) { 0574 if( track.mode() == Device::Track::MODE1 ) { 0575 writer->addArgument( "-data" ); 0576 } 0577 else { 0578 const K3b::ExternalBin* cdrecordBin = k3bcore->externalBinManager()->binObject("cdrecord"); 0579 if( cdrecordBin && cdrecordBin->hasFeature( "xamix" ) ) 0580 writer->addArgument( "-xa" ); 0581 else 0582 writer->addArgument( "-xa1" ); 0583 } 0584 0585 if( image.isEmpty() ) 0586 writer->addArgument( QString("-tsize=%1s").arg(track.length().lba()) )->addArgument("-"); 0587 else 0588 writer->addArgument( image ); 0589 } 0590 0591 // 0592 // Add an audio track 0593 // 0594 else { 0595 if( firstAudioTrack ) { 0596 firstAudioTrack = false; 0597 writer->addArgument( "-useinfo" ); 0598 0599 // add raw cdtext data 0600 if( !d->cdText.isEmpty() ) { 0601 writer->setRawCdText( d->cdText.rawPackData() ); 0602 } 0603 0604 writer->addArgument( "-audio" ); 0605 0606 // we always pad because although K3b makes sure all tracks' length are multiples of 2352 0607 // it seems that normalize sometimes corrupts these lengths 0608 // FIXME: see K3b::AudioJob for the whole less4secs and zeroPregap handling 0609 writer->addArgument( "-pad" ); 0610 0611 // Allow tracks shorter than 4 seconds 0612 writer->addArgument( "-shorttrack" ); 0613 } 0614 0615 K3b::InfFileWriter infFileWriter; 0616 infFileWriter.setTrack( track ); 0617 infFileWriter.setTrackNumber( ++audioTrackCnt ); 0618 if( image.isEmpty() ) 0619 infFileWriter.setBigEndian( false ); 0620 if( !infFileWriter.save( d->infFileName( audioTrackCnt ) ) ) 0621 return false; 0622 0623 if( image.isEmpty() ) { 0624 // this is only supported by cdrecord versions >= 2.01a13 0625 writer->addArgument( QFile::encodeName( d->infFileName( audioTrackCnt ) ) ); 0626 } 0627 else { 0628 writer->addArgument( QFile::encodeName( image ) ); 0629 } 0630 } 0631 } 0632 } 0633 else { 0634 writer->setCueFile( d->cueFile ); 0635 } 0636 0637 return true; 0638 } 0639 0640 0641 bool K3b::MetaWriter::setupCdrdaoJob() 0642 { 0643 QString tocFile = d->cueFile; 0644 0645 if( !d->cueFile.isEmpty() ) { 0646 K3b::TocFileWriter tocFileWriter; 0647 0648 // 0649 // TOC 0650 // 0651 tocFileWriter.setData( d->toc ); 0652 tocFileWriter.setHideFirstTrack( d->hideFirstTrack ); 0653 0654 // 0655 // CD-Text 0656 // 0657 if( !d->cdText.isEmpty() ) { 0658 Device::CdText text = d->cdText; 0659 // if data in first track we need to add a dummy cdtext 0660 if( d->toc.first().type() == Device::Track::TYPE_DATA ) 0661 text.insert( 0, K3b::Device::TrackCdText() ); 0662 0663 tocFileWriter.setCdText( text ); 0664 } 0665 0666 // 0667 // image filenames 0668 // 0669 tocFileWriter.setFilenames( d->images ); 0670 0671 if( !tocFileWriter.save( d->tocFile )) 0672 return false; 0673 0674 tocFile = d->tocFile; 0675 } 0676 0677 0678 K3b::CdrdaoWriter* writer = new K3b::CdrdaoWriter( burnDevice(), this, this ); 0679 writer->setSimulate( simulate() ); 0680 writer->setBurnSpeed( burnSpeed() ); 0681 0682 // multisession only for the first session 0683 writer->setMulti( d->multiSession ); 0684 0685 writer->setTocFile( tocFile ); 0686 0687 d->writingJob = writer; 0688 0689 return true; 0690 } 0691 0692 0693 bool K3b::MetaWriter::setupGrowisofsob() 0694 { 0695 K3b::GrowisofsWriter* job = new K3b::GrowisofsWriter( burnDevice(), this, this ); 0696 0697 // these do only make sense with DVD-R(W) 0698 job->setSimulate( simulate() ); 0699 job->setBurnSpeed( burnSpeed() ); 0700 job->setWritingMode( d->usedWritingMode ); 0701 job->setCloseDvd( !d->multiSession ); 0702 0703 // 0704 // In case the first layer size is not known let the 0705 // split be determined by growisofs 0706 // 0707 if( d->layerBreak > 0 ) { 0708 job->setLayerBreak( d->layerBreak ); 0709 } 0710 else { 0711 // this is only used in DAO mode with growisofs >= 5.15 0712 job->setTrackSize( d->toc.first().length().lba() ); 0713 } 0714 0715 if( d->images.isEmpty() ) 0716 job->setImageToWrite( QString() ); // read from stdin 0717 else 0718 job->setImageToWrite( d->images.first() ); 0719 0720 d->writingJob = job; 0721 0722 return true; 0723 } 0724 0725 0726 bool K3b::MetaWriter::setupCdrskinJob() 0727 { 0728 K3b::CdrskinWriter* writer = new K3b::CdrskinWriter( burnDevice(), this, this ); 0729 d->writingJob = writer; 0730 0731 writer->setWritingMode( d->usedWritingMode ); 0732 writer->setSimulate( simulate() ); 0733 writer->setBurnSpeed( burnSpeed() ); 0734 writer->setMulti( d->multiSession ); 0735 0736 if( d->multiSession && 0737 !d->toc.isEmpty() && 0738 d->images.isEmpty() ) { 0739 writer->addArgument("-waiti"); 0740 } 0741 0742 if( d->cueFile.isEmpty() ) { 0743 int audioTrackCnt = 0; 0744 0745 for( int i = 0; i < d->toc.count(); ++i ) { 0746 Device::Track track = d->toc[i]; 0747 QString image; 0748 if( d->images.count() ) 0749 image = d->images[i]; 0750 0751 // 0752 // Add a data track 0753 // 0754 if( track.type() == Device::Track::TYPE_DATA ) { 0755 if( track.mode() == Device::Track::MODE1 ) { 0756 writer->addArgument( "-data" ); 0757 } 0758 else { 0759 if( k3bcore->externalBinManager()->binObject("cdrskin") && 0760 k3bcore->externalBinManager()->binObject("cdrskin")->hasFeature( "xamix" ) ) 0761 writer->addArgument( "-xa" ); 0762 else 0763 writer->addArgument( "-xa1" ); 0764 } 0765 0766 if( image.isEmpty() ) 0767 writer->addArgument( QString("-tsize=%1s").arg(track.length().lba()) )->addArgument("-"); 0768 else 0769 writer->addArgument( image ); 0770 } 0771 0772 // 0773 // Add an audio track 0774 // 0775 else { 0776 K3b::InfFileWriter infFileWriter; 0777 infFileWriter.setTrack( track ); 0778 infFileWriter.setTrackNumber( ++audioTrackCnt ); 0779 if( image.isEmpty() ) 0780 infFileWriter.setBigEndian( false ); 0781 if( !infFileWriter.save( d->infFileName( audioTrackCnt ) ) ) 0782 return false; 0783 0784 if (image.isEmpty()) { 0785 emit infoMessage(i18n("No version of cdrskin can do this yet."), MessageError); 0786 } else { 0787 writer->addArgument(QFile::encodeName(image)); 0788 } 0789 } 0790 } 0791 } 0792 else { 0793 writer->setCueFile( d->cueFile ); 0794 } 0795 0796 return true; 0797 } 0798 0799 0800 void K3b::MetaWriter::cancel() 0801 { 0802 if( active() ) { 0803 if( d->writingJob && d->writingJob->active() ) { 0804 d->writingJob->cancel(); 0805 } 0806 else { 0807 // can this really happen? 0808 emit canceled(); 0809 jobFinished(false); 0810 } 0811 } 0812 } 0813 0814 0815 void K3b::MetaWriter::slotWritingJobFinished( bool success ) 0816 { 0817 d->cleanupTempFiles(); 0818 jobFinished( success ); 0819 } 0820 0821 0822 void K3b::MetaWriter::setSessionToWrite( const Device::Toc& toc, const QStringList& images ) 0823 { 0824 d->toc = toc; 0825 d->images = images; 0826 } 0827 0828 0829 void K3b::MetaWriter::setSupportedWritingMedia( Device::MediaTypes types ) 0830 { 0831 d->supportedWritingMedia = types; 0832 } 0833 0834 0835 void K3b::MetaWriter::setWritingApp( WritingApp app ) 0836 { 0837 d->writingApp = app; 0838 } 0839 0840 0841 void K3b::MetaWriter::setWritingMode( WritingMode mode ) 0842 { 0843 d->writingMode = mode; 0844 } 0845 0846 0847 void K3b::MetaWriter::setCueFile( const QString& s) 0848 { 0849 d->cueFile = s; 0850 } 0851 0852 0853 void K3b::MetaWriter::setClone( bool b ) 0854 { 0855 d->clone = b; 0856 } 0857 0858 0859 void K3b::MetaWriter::setMultiSession( bool b ) 0860 { 0861 d->multiSession = b; 0862 } 0863 0864 0865 void K3b::MetaWriter::setCdText( const Device::CdText& cdtext ) 0866 { 0867 d->cdText = cdtext; 0868 } 0869 0870 0871 void K3b::MetaWriter::setLayerBreak( qint64 lb ) 0872 { 0873 d->layerBreak = lb; 0874 } 0875 0876 0877 void K3b::MetaWriter::setHideFirstTrack( bool b ) 0878 { 0879 d->hideFirstTrack = b; 0880 } 0881 0882 0883 void K3b::MetaWriter::informUser() 0884 { 0885 Medium medium = k3bcore->mediaCache()->medium( burnDevice() ); 0886 0887 if( medium.diskInfo().mediaType() == Device::MEDIA_CD_R ) { 0888 if( medium.diskInfo().empty() ) { 0889 if( d->usedWritingMode == WritingModeSao ) 0890 emit infoMessage( i18n("Writing CD in Session At Once mode."), MessageInfo ); 0891 else if( d->usedWritingMode == WritingModeTao ) 0892 emit infoMessage( i18n("Writing CD in Track At Once mode."), MessageInfo ); 0893 else if( d->usedWritingMode == WritingModeRaw ) 0894 emit infoMessage( i18n("Writing CD in Raw mode."), MessageInfo ); 0895 } 0896 else { 0897 emit infoMessage( i18n("Appending session to CD"), MessageInfo ); 0898 } 0899 } 0900 0901 else if( medium.diskInfo().mediaType() == Device::MEDIA_CD_RW ) { 0902 if( medium.diskInfo().empty() ) { 0903 if( d->usedWritingMode == WritingModeSao ) 0904 emit infoMessage( i18n("Writing rewritable CD in Session At Once mode."), MessageInfo ); 0905 else if( d->usedWritingMode == WritingModeTao ) 0906 emit infoMessage( i18n("Writing rewritable CD in Track At Once mode."), MessageInfo ); 0907 else if( d->usedWritingMode == WritingModeRaw ) 0908 emit infoMessage( i18n("Writing rewritable CD in Raw mode."), MessageInfo ); 0909 } 0910 else { 0911 emit infoMessage( i18n("Appending session to rewritable CD."), MessageInfo ); 0912 } 0913 } 0914 0915 else if( Device::isDvdMedia( medium.diskInfo().mediaType() ) ) { 0916 if( medium.diskInfo().appendable() ) { 0917 if( medium.diskInfo().mediaType() & (Device::MEDIA_DVD_PLUS_RW|Device::MEDIA_DVD_PLUS_RW_DL) ) 0918 emit infoMessage( i18n("Growing ISO 9660 filesystem on DVD+RW."), MessageInfo ); 0919 else if( medium.diskInfo().mediaType() == Device::MEDIA_DVD_RW_OVWR ) 0920 emit infoMessage( i18n("Growing ISO 9660 filesystem on DVD-RW in restricted overwrite mode."), MessageInfo ); 0921 else if( medium.diskInfo().mediaType() == Device::MEDIA_DVD_PLUS_R ) 0922 emit infoMessage( i18n("Appending session to DVD+R."), MessageInfo ); 0923 else if( medium.diskInfo().mediaType() == Device::MEDIA_DVD_PLUS_R_DL ) 0924 emit infoMessage( i18n("Appending session to Double Layer DVD+R."), MessageInfo ); 0925 else 0926 emit infoMessage( i18n("Appending session to %1.", K3b::Device::mediaTypeString(medium.diskInfo().mediaType(), true) ), MessageInfo ); 0927 } 0928 else { 0929 if( medium.diskInfo().mediaType() == Device::MEDIA_DVD_RW_OVWR ) 0930 emit infoMessage( i18n("Writing DVD-RW in restricted overwrite mode."), MessageInfo ); 0931 else if( medium.diskInfo().mediaType() == Device::MEDIA_DVD_PLUS_R_DL ) 0932 emit infoMessage( i18n("Writing Double Layer DVD+R."), MessageInfo ); 0933 else if( medium.diskInfo().mediaType() & Device::MEDIA_DVD_PLUS_ALL ) 0934 emit infoMessage( i18n("Writing %1.", K3b::Device::mediaTypeString(medium.diskInfo().mediaType(), true)), MessageInfo ); 0935 else if( d->usedWritingMode == WritingModeSao ) 0936 emit infoMessage( i18n("Writing %1 in DAO mode.", K3b::Device::mediaTypeString(medium.diskInfo().mediaType(), true) ), MessageInfo ); 0937 else if( d->usedWritingMode == WritingModeIncrementalSequential ) 0938 emit infoMessage( i18n("Writing %1 in incremental mode.", K3b::Device::mediaTypeString(medium.diskInfo().mediaType(), true) ), MessageInfo ); 0939 } 0940 } 0941 0942 else { 0943 emit infoMessage( i18n("Writing %1.", K3b::Device::mediaTypeString(medium.diskInfo().mediaType(), true) ), MessageInfo ); 0944 } 0945 } 0946 0947 0948 K3b::WritingApp K3b::MetaWriter::usedWritingApp() const 0949 { 0950 return d->usedWritingApp; 0951 } 0952 0953 0954 K3b::WritingMode K3b::MetaWriter::usedWritingMode() const 0955 { 0956 return d->usedWritingMode; 0957 } 0958 0959 #include "moc_k3bmetawriter.cpp"