~ubuntu-branches/debian/jessie/k3b/jessie

« back to all changes in this revision

Viewing changes to .pc/Prefer-growisofs-to-wodim-for-DVD-BluRay-burning.patch/libk3b/jobs/k3bdvdcopyjob.cpp

  • Committer: Package Import Robot
  • Author(s): Pino Toscano, Lisandro Damián Nicanor Pérez Meyer, Pino Toscano
  • Date: 2013-08-25 18:42:53 UTC
  • Revision ID: package-import@ubuntu.com-20130825184253-3nlk9xxp8rjbcemj
Tags: 2.0.2-7
* Team upload.

[ Lisandro Damián Nicanor Pérez Meyer ]
* Enable the lame-based MP3 encoding plugin (based on Pino's work):
  - Build-Depend on libmp3lame-dev.
  - Install the new plugin (and its configuration) in libk3b6-extracodecs.

[ Pino Toscano ]
* Update Vcs-* headers.
* Bump Standards-Version to 3.9.4, no changes required.
* Add Fix-K3B-to-build-with-recent-FFMPEG-versions.patch (backported from
  upstream branch 2.0) and ffmpeg-more.diff to fix compatibility with newer
  ffmpeg/libav versions. (Closes: #720799)
* Add Prefer-growisofs-to-wodim-for-DVD-BluRay-burning.patch (backported from
  upstream branch 2.0) to prefer growisofs to wodim for DVD/BluRay; add the
  growisofs recommend. (Closes: #714944)
* Suggest kde-config-cddb for the CDDB configuration page. (Closes: #696828)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *
 
3
 * Copyright (C) 2003-2010 Sebastian Trueg <trueg@k3b.org>
 
4
 *
 
5
 * This file is part of the K3b project.
 
6
 * Copyright (C) 1998-2010 Sebastian Trueg <trueg@k3b.org>
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation; either version 2 of the License, or
 
11
 * (at your option) any later version.
 
12
 * See the file "COPYING" for the exact licensing terms.
 
13
 */
 
14
 
 
15
#include "k3bdvdcopyjob.h"
 
16
#include "k3blibdvdcss.h"
 
17
 
 
18
#include "k3breadcdreader.h"
 
19
#include "k3bdatatrackreader.h"
 
20
#include "k3bexternalbinmanager.h"
 
21
#include "k3bdevice.h"
 
22
#include "k3bdeviceglobals.h"
 
23
#include "k3bdevicehandler.h"
 
24
#include "k3bdiskinfo.h"
 
25
#include "k3bglobals.h"
 
26
#include "k3bcore.h"
 
27
#include "k3bgrowisofswriter.h"
 
28
#include "k3bcdrecordwriter.h"
 
29
#include "k3bversion.h"
 
30
#include "k3biso9660.h"
 
31
#include "k3bfilesplitter.h"
 
32
#include "k3bchecksumpipe.h"
 
33
#include "k3bverificationjob.h"
 
34
#include "k3bglobalsettings.h"
 
35
 
 
36
#include <kdebug.h>
 
37
#include <klocale.h>
 
38
#include <kio/global.h>
 
39
 
 
40
#include <qfile.h>
 
41
#include <qfileinfo.h>
 
42
#include <qapplication.h>
 
43
 
 
44
 
 
45
class K3b::DvdCopyJob::Private
 
46
{
 
47
public:
 
48
    Private()
 
49
        : doneCopies(0),
 
50
          running(false),
 
51
          canceled(false),
 
52
          writerJob(0),
 
53
          readcdReader(0),
 
54
          dataTrackReader(0),
 
55
          verificationJob(0),
 
56
          usedWritingMode(K3b::WritingModeAuto),
 
57
          verifyData(false) {
 
58
        outPipe.readFrom( &imageFile, true );
 
59
    }
 
60
 
 
61
    K3b::WritingApp usedWritingApp;
 
62
 
 
63
    int doneCopies;
 
64
 
 
65
    bool running;
 
66
    bool readerRunning;
 
67
    bool writerRunning;
 
68
    bool canceled;
 
69
 
 
70
    K3b::AbstractWriter* writerJob;
 
71
    K3b::ReadcdReader* readcdReader;
 
72
    K3b::DataTrackReader* dataTrackReader;
 
73
    K3b::VerificationJob* verificationJob;
 
74
 
 
75
    K3b::Device::DiskInfo sourceDiskInfo;
 
76
 
 
77
    K3b::Msf lastSector;
 
78
 
 
79
    K3b::WritingMode usedWritingMode;
 
80
 
 
81
    K3b::FileSplitter imageFile;
 
82
    K3b::ChecksumPipe inPipe;
 
83
    K3b::ActivePipe outPipe;
 
84
 
 
85
    bool verifyData;
 
86
};
 
87
 
 
88
 
 
89
K3b::DvdCopyJob::DvdCopyJob( K3b::JobHandler* hdl, QObject* parent )
 
90
    : K3b::BurnJob( hdl, parent ),
 
91
      m_writerDevice(0),
 
92
      m_readerDevice(0),
 
93
      m_onTheFly(false),
 
94
      m_removeImageFiles(false),
 
95
      m_simulate(false),
 
96
      m_speed(1),
 
97
      m_copies(1),
 
98
      m_onlyCreateImage(false),
 
99
      m_ignoreReadErrors(false),
 
100
      m_readRetries(128),
 
101
      m_writingMode( K3b::WritingModeAuto )
 
102
{
 
103
    d = new Private();
 
104
}
 
105
 
 
106
 
 
107
K3b::DvdCopyJob::~DvdCopyJob()
 
108
{
 
109
    delete d;
 
110
}
 
111
 
 
112
 
 
113
void K3b::DvdCopyJob::start()
 
114
{
 
115
    jobStarted();
 
116
    emit burning(false);
 
117
 
 
118
    d->canceled = false;
 
119
    d->running = true;
 
120
    d->readerRunning = d->writerRunning = false;
 
121
 
 
122
    emit newTask( i18n("Checking Source Medium") );
 
123
 
 
124
    if( m_onTheFly &&
 
125
        k3bcore->externalBinManager()->binObject( "growisofs" )->version < K3b::Version( 5, 12 ) ) {
 
126
        m_onTheFly = false;
 
127
        emit infoMessage( i18n("K3b does not support writing on-the-fly with growisofs %1.",
 
128
                          k3bcore->externalBinManager()->binObject( "growisofs" )->version), MessageError );
 
129
        emit infoMessage( i18n("Disabling on-the-fly writing."), MessageInfo );
 
130
    }
 
131
 
 
132
    emit newSubTask( i18n("Waiting for source medium") );
 
133
 
 
134
    // wait for a source disk
 
135
    if( waitForMedium( m_readerDevice,
 
136
                       K3b::Device::STATE_COMPLETE|K3b::Device::STATE_INCOMPLETE,
 
137
                       K3b::Device::MEDIA_WRITABLE_DVD|K3b::Device::MEDIA_DVD_ROM|K3b::Device::MEDIA_BD_ALL ) == Device::MEDIA_UNKNOWN ) {
 
138
        emit canceled();
 
139
        d->running = false;
 
140
        jobFinished( false );
 
141
        return;
 
142
    }
 
143
 
 
144
    emit newSubTask( i18n("Checking source medium") );
 
145
 
 
146
    connect( K3b::Device::sendCommand( K3b::Device::DeviceHandler::CommandMediaInfo, m_readerDevice ),
 
147
             SIGNAL(finished(K3b::Device::DeviceHandler*)),
 
148
             this,
 
149
             SLOT(slotDiskInfoReady(K3b::Device::DeviceHandler*)) );
 
150
}
 
151
 
 
152
 
 
153
void K3b::DvdCopyJob::slotDiskInfoReady( K3b::Device::DeviceHandler* dh )
 
154
{
 
155
    if( d->canceled ) {
 
156
        emit canceled();
 
157
        jobFinished(false);
 
158
        d->running = false;
 
159
    }
 
160
 
 
161
    d->sourceDiskInfo = dh->diskInfo();
 
162
 
 
163
    if( dh->diskInfo().empty() || dh->diskInfo().diskState() == K3b::Device::STATE_NO_MEDIA ) {
 
164
        emit infoMessage( i18n("No source medium found."), MessageError );
 
165
        jobFinished(false);
 
166
        d->running = false;
 
167
    }
 
168
    else {
 
169
        // first let's determine which application to use
 
170
        d->usedWritingApp = writingApp();
 
171
        if ( d->usedWritingApp == K3b::WritingAppAuto ) {
 
172
            // let's default to cdrecord for the time being
 
173
            // FIXME: use growisofs for non-dao and non-auto mode
 
174
            if ( K3b::Device::isBdMedia( d->sourceDiskInfo.mediaType() ) ) {
 
175
                if ( k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "blu-ray" ) )
 
176
                    d->usedWritingApp = K3b::WritingAppCdrecord;
 
177
                else
 
178
                    d->usedWritingApp = K3b::WritingAppGrowisofs;
 
179
            }
 
180
        }
 
181
 
 
182
        if( m_readerDevice->copyrightProtectionSystemType() == K3b::Device::COPYRIGHT_PROTECTION_CSS ) { // CSS is the the only one we support ATM
 
183
            emit infoMessage( i18n("Found encrypted DVD."), MessageWarning );
 
184
            // check for libdvdcss
 
185
            bool haveLibdvdcss = false;
 
186
            kDebug() << "(K3b::DvdCopyJob) trying to open libdvdcss.";
 
187
            if( K3b::LibDvdCss* libcss = K3b::LibDvdCss::create() ) {
 
188
                kDebug() << "(K3b::DvdCopyJob) succeeded.";
 
189
                kDebug() << "(K3b::DvdCopyJob) dvdcss_open(" << m_readerDevice->blockDeviceName() << ") = "
 
190
                          << libcss->open(m_readerDevice) << endl;
 
191
                haveLibdvdcss = true;
 
192
 
 
193
                delete libcss;
 
194
            }
 
195
            else
 
196
                kDebug() << "(K3b::DvdCopyJob) failed.";
 
197
 
 
198
            if( !haveLibdvdcss ) {
 
199
                emit infoMessage( i18n("Cannot copy encrypted DVDs."), MessageError );
 
200
                d->running = false;
 
201
                jobFinished( false );
 
202
                return;
 
203
            }
 
204
        }
 
205
 
 
206
 
 
207
        //
 
208
        // We cannot rely on the kernel to determine the size of the DVD for some reason
 
209
        // On the other hand it is not always a good idea to rely on the size from the ISO9660
 
210
        // header since that may be wrong due to some buggy encoder or some boot code appended
 
211
        // after creating the image.
 
212
        // That is why we try our best to determine the size of the DVD. For DVD-ROM this is very
 
213
        // easy since it has only one track. The same goes for single session DVD-R(W) and DVD+R.
 
214
        // Multisession DVDs we will simply not copy. ;)
 
215
        // For DVD+RW and DVD-RW in restricted overwrite mode we are left with no other choice but
 
216
        // to use the ISO9660 header.
 
217
        //
 
218
        // On the other hand: in on-the-fly mode growisofs determines the size of the data to be written
 
219
        //                    by looking at the ISO9660 header when writing in DAO mode. So in this case
 
220
        //                    it would be best for us to do the same....
 
221
        //
 
222
        // With growisofs 5.15 we have the option to specify the size of the image to be written in DAO mode.
 
223
        //
 
224
 
 
225
        switch( dh->diskInfo().mediaType() ) {
 
226
        case K3b::Device::MEDIA_DVD_ROM:
 
227
        case K3b::Device::MEDIA_DVD_PLUS_R_DL:
 
228
        case K3b::Device::MEDIA_DVD_R_DL:
 
229
        case K3b::Device::MEDIA_DVD_R_DL_SEQ:
 
230
        case K3b::Device::MEDIA_DVD_R_DL_JUMP:
 
231
            if( !m_onlyCreateImage ) {
 
232
                if( dh->diskInfo().numLayers() > 1 &&
 
233
                    dh->diskInfo().size() > MediaSizeDvd4Gb ) {
 
234
                    if( !(m_writerDevice->type() & (K3b::Device::DEVICE_DVD_R_DL|K3b::Device::DEVICE_DVD_PLUS_R_DL)) ) {
 
235
                        emit infoMessage( i18n("The writer does not support writing Double Layer DVDs."), MessageError );
 
236
                        d->running = false;
 
237
                        jobFinished(false);
 
238
                        return;
 
239
                    }
 
240
                    else if( k3bcore->externalBinManager()->binObject( "growisofs" ) &&
 
241
                             !k3bcore->externalBinManager()->binObject( "growisofs" )->hasFeature( "dual-layer" ) ) {
 
242
                        emit infoMessage( i18n("This growisofs version does not support writing Double Layer DVDs."), MessageError );
 
243
                        d->running = false;
 
244
                        jobFinished(false);
 
245
                        return;
 
246
                    }
 
247
                }
 
248
            }
 
249
        case K3b::Device::MEDIA_DVD_R:
 
250
        case K3b::Device::MEDIA_DVD_R_SEQ:
 
251
        case K3b::Device::MEDIA_DVD_RW:
 
252
        case K3b::Device::MEDIA_DVD_RW_SEQ:
 
253
        case K3b::Device::MEDIA_DVD_PLUS_R:
 
254
        case K3b::Device::MEDIA_BD_ROM:
 
255
        case K3b::Device::MEDIA_BD_R:
 
256
        case K3b::Device::MEDIA_BD_R_SRM:
 
257
 
 
258
            if( dh->diskInfo().numSessions() > 1 ) {
 
259
                emit infoMessage( i18n("K3b does not support copying multi-session DVD or Blu-ray disks."), MessageError );
 
260
                d->running = false;
 
261
                jobFinished(false);
 
262
                return;
 
263
            }
 
264
 
 
265
            // growisofs only uses the size from the PVD for reserving
 
266
            // writable space in DAO mode
 
267
            // with version >= 5.15 growisofs supports specifying the size of the track
 
268
            if( m_writingMode != K3b::WritingModeSao || !m_onTheFly || m_onlyCreateImage ||
 
269
                ( k3bcore->externalBinManager()->binObject( "growisofs" ) &&
 
270
                  k3bcore->externalBinManager()->binObject( "growisofs" )->hasFeature( "daosize" ) ) ||
 
271
                d->usedWritingApp == K3b::WritingAppCdrecord ) {
 
272
                d->lastSector = dh->toc().lastSector();
 
273
                break;
 
274
            }
 
275
 
 
276
            // fallthrough
 
277
 
 
278
        case K3b::Device::MEDIA_DVD_PLUS_RW:
 
279
        case K3b::Device::MEDIA_DVD_RW_OVWR:
 
280
        case K3b::Device::MEDIA_BD_RE:
 
281
        {
 
282
            emit infoMessage( i18n("K3b relies on the size saved in the ISO9660 header."), MessageWarning );
 
283
            emit infoMessage( i18n("This might result in a corrupt copy if the source was mastered with buggy software."), MessageWarning );
 
284
 
 
285
            K3b::Iso9660 isoF( m_readerDevice, 0 );
 
286
            if( isoF.open() ) {
 
287
                d->lastSector = ((long long)isoF.primaryDescriptor().logicalBlockSize*isoF.primaryDescriptor().volumeSpaceSize)/2048LL - 1;
 
288
            }
 
289
            else {
 
290
                emit infoMessage( i18n("Unable to determine the ISO9660 filesystem size."), MessageError );
 
291
                jobFinished(false);
 
292
                d->running = false;
 
293
                return;
 
294
            }
 
295
        }
 
296
        break;
 
297
 
 
298
        case K3b::Device::MEDIA_DVD_RAM:
 
299
            emit infoMessage( i18n("K3b does not support copying DVD-RAM."), MessageError );
 
300
            jobFinished(false);
 
301
            d->running = false;
 
302
            return;
 
303
 
 
304
        default:
 
305
            emit infoMessage( i18n("Unsupported media type."), MessageError );
 
306
            jobFinished(false);
 
307
            d->running = false;
 
308
            return;
 
309
        }
 
310
 
 
311
 
 
312
        if( !m_onTheFly ) {
 
313
            //
 
314
            // Check the image path
 
315
            //
 
316
            QFileInfo fi( m_imagePath );
 
317
            if( !fi.isFile() ||
 
318
                questionYesNo( i18n("Do you want to overwrite %1?",m_imagePath),
 
319
                               i18n("File Exists") ) ) {
 
320
                if( fi.isDir() )
 
321
                    m_imagePath = K3b::findTempFile( "iso", m_imagePath );
 
322
                else if( !QFileInfo( m_imagePath.section( '/', 0, -2 ) ).isDir() ) {
 
323
                    emit infoMessage( i18n("Specified an unusable temporary path. Using default."), MessageWarning );
 
324
                    m_imagePath = K3b::findTempFile( "iso" );
 
325
                }
 
326
                // else the user specified a file in an existing dir
 
327
 
 
328
                emit infoMessage( i18n("Writing image file to %1.",m_imagePath), MessageInfo );
 
329
                emit newSubTask( i18n("Reading source medium.") );
 
330
            }
 
331
            else {
 
332
                jobFinished(false);
 
333
                d->running = false;
 
334
                return;
 
335
            }
 
336
 
 
337
            //
 
338
            // check free temp space
 
339
            //
 
340
            KIO::filesize_t imageSpaceNeeded = (KIO::filesize_t)(d->lastSector.lba()+1)*2048;
 
341
            unsigned long avail, size;
 
342
            QString pathToTest = m_imagePath.left( m_imagePath.lastIndexOf( '/' ) );
 
343
            if( !K3b::kbFreeOnFs( pathToTest, size, avail ) ) {
 
344
                emit infoMessage( i18n("Unable to determine free space in temporary folder '%1'.",pathToTest), MessageError );
 
345
                jobFinished(false);
 
346
                d->running = false;
 
347
                return;
 
348
            }
 
349
            else {
 
350
                if( avail < imageSpaceNeeded/1024 ) {
 
351
                    emit infoMessage( i18n("Not enough space left in temporary folder."), MessageError );
 
352
                    jobFinished(false);
 
353
                    d->running = false;
 
354
                    return;
 
355
                }
 
356
            }
 
357
 
 
358
            d->imageFile.setName( m_imagePath );
 
359
            if( !d->imageFile.open( QIODevice::WriteOnly ) ) {
 
360
                emit infoMessage( i18n("Unable to open '%1' for writing.",m_imagePath), MessageError );
 
361
                jobFinished( false );
 
362
                d->running = false;
 
363
                return;
 
364
            }
 
365
        }
 
366
 
 
367
        if( K3b::isMounted( m_readerDevice ) ) {
 
368
            emit infoMessage( i18n("Unmounting source medium"), MessageInfo );
 
369
            K3b::unmount( m_readerDevice );
 
370
        }
 
371
 
 
372
        if( m_onlyCreateImage || !m_onTheFly ) {
 
373
            emit newTask( i18n("Creating image") );
 
374
        }
 
375
        else if( m_onTheFly && !m_onlyCreateImage ) {
 
376
            if( waitForDvd() ) {
 
377
                prepareWriter();
 
378
                if( m_simulate )
 
379
                    emit newTask( i18n("Simulating copy") );
 
380
                else if( m_copies > 1 )
 
381
                    emit newTask( i18n("Writing copy %1",d->doneCopies+1) );
 
382
                else
 
383
                    emit newTask( i18n("Writing copy") );
 
384
 
 
385
                emit burning(true);
 
386
                d->writerRunning = true;
 
387
                d->writerJob->start();
 
388
            }
 
389
            else {
 
390
                if( d->canceled )
 
391
                    emit canceled();
 
392
                jobFinished(false);
 
393
                d->running = false;
 
394
                return;
 
395
            }
 
396
        }
 
397
 
 
398
        prepareReader();
 
399
        d->readerRunning = true;
 
400
        d->dataTrackReader->start();
 
401
    }
 
402
}
 
403
 
 
404
 
 
405
void K3b::DvdCopyJob::cancel()
 
406
{
 
407
    if( d->running ) {
 
408
        d->canceled = true;
 
409
        if( d->readerRunning  )
 
410
            d->dataTrackReader->cancel();
 
411
        if( d->writerRunning )
 
412
            d->writerJob->cancel();
 
413
        if ( d->verificationJob && d->verificationJob->active() )
 
414
            d->verificationJob->cancel();
 
415
        d->inPipe.close();
 
416
        d->outPipe.close();
 
417
        d->imageFile.close();
 
418
    }
 
419
    else {
 
420
        kDebug() << "(K3b::DvdCopyJob) not running.";
 
421
    }
 
422
}
 
423
 
 
424
 
 
425
void K3b::DvdCopyJob::prepareReader()
 
426
{
 
427
    if( !d->dataTrackReader ) {
 
428
        d->dataTrackReader = new K3b::DataTrackReader( this );
 
429
        connect( d->dataTrackReader, SIGNAL(percent(int)), this, SLOT(slotReaderProgress(int)) );
 
430
        connect( d->dataTrackReader, SIGNAL(processedSize(int, int)), this, SLOT(slotReaderProcessedSize(int, int)) );
 
431
        connect( d->dataTrackReader, SIGNAL(finished(bool)), this, SLOT(slotReaderFinished(bool)) );
 
432
        connect( d->dataTrackReader, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) );
 
433
        connect( d->dataTrackReader, SIGNAL(newTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) );
 
434
        connect( d->dataTrackReader, SIGNAL(debuggingOutput(const QString&, const QString&)),
 
435
                 this, SIGNAL(debuggingOutput(const QString&, const QString&)) );
 
436
    }
 
437
 
 
438
    d->dataTrackReader->setDevice( m_readerDevice );
 
439
    d->dataTrackReader->setIgnoreErrors( m_ignoreReadErrors );
 
440
    d->dataTrackReader->setRetries( m_readRetries );
 
441
    d->dataTrackReader->setSectorRange( 0, d->lastSector );
 
442
 
 
443
    if( m_onTheFly && !m_onlyCreateImage )
 
444
        // there are several uses of pipe->writeTo( d->writerJob->ioDevice(), ... ) in this file!
 
445
#ifdef __GNUC__
 
446
#warning Growisofs needs stdin to be closed in order to exit gracefully. Cdrecord does not. However,  if closed with cdrecord we loose parts of stderr. Why?
 
447
#endif
 
448
        d->inPipe.writeTo( d->writerJob->ioDevice(), d->usedWritingApp == K3b::WritingAppGrowisofs );
 
449
    else
 
450
        d->inPipe.writeTo( &d->imageFile, true );
 
451
 
 
452
    d->inPipe.open( true );
 
453
    d->dataTrackReader->writeTo( &d->inPipe );
 
454
}
 
455
 
 
456
 
 
457
// ALWAYS CALL WAITFORDVD BEFORE PREPAREWRITER!
 
458
void K3b::DvdCopyJob::prepareWriter()
 
459
{
 
460
    delete d->writerJob;
 
461
 
 
462
    if ( d->usedWritingApp == K3b::WritingAppGrowisofs ) {
 
463
        K3b::GrowisofsWriter* job = new K3b::GrowisofsWriter( m_writerDevice, this, this );
 
464
 
 
465
        // these do only make sense with DVD-R(W)
 
466
        job->setSimulate( m_simulate );
 
467
        job->setBurnSpeed( m_speed );
 
468
        job->setWritingMode( d->usedWritingMode );
 
469
        job->setCloseDvd( true );
 
470
 
 
471
        //
 
472
        // In case the first layer size is not known let the
 
473
        // split be determined by growisofs
 
474
        //
 
475
        if( d->sourceDiskInfo.numLayers() > 1 &&
 
476
            d->sourceDiskInfo.firstLayerSize() > 0 ) {
 
477
            job->setLayerBreak( d->sourceDiskInfo.firstLayerSize().lba() );
 
478
        }
 
479
        else {
 
480
            // this is only used in DAO mode with growisofs >= 5.15
 
481
            job->setTrackSize( d->lastSector.lba()+1 );
 
482
        }
 
483
 
 
484
        job->setImageToWrite( QString() ); // write to stdin
 
485
 
 
486
        d->writerJob = job;
 
487
    }
 
488
 
 
489
    else {
 
490
        K3b::CdrecordWriter* writer = new K3b::CdrecordWriter( m_writerDevice, this, this );
 
491
 
 
492
        writer->setWritingMode( d->usedWritingMode );
 
493
        writer->setSimulate( m_simulate );
 
494
        writer->setBurnSpeed( m_speed );
 
495
 
 
496
        writer->addArgument( "-data" );
 
497
        writer->addArgument( QString("-tsize=%1s").arg( d->lastSector.lba()+1 ) )->addArgument("-");
 
498
 
 
499
        d->writerJob = writer;
 
500
    }
 
501
 
 
502
 
 
503
    connect( d->writerJob, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) );
 
504
    connect( d->writerJob, SIGNAL(percent(int)), this, SLOT(slotWriterProgress(int)) );
 
505
    connect( d->writerJob, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSize(int, int)) );
 
506
    connect( d->writerJob, SIGNAL(processedSubSize(int, int)), this, SIGNAL(processedSubSize(int, int)) );
 
507
    connect( d->writerJob, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) );
 
508
    connect( d->writerJob, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) );
 
509
    connect( d->writerJob, SIGNAL(writeSpeed(int, K3b::Device::SpeedMultiplicator)), this, SIGNAL(writeSpeed(int, K3b::Device::SpeedMultiplicator)) );
 
510
    connect( d->writerJob, SIGNAL(finished(bool)), this, SLOT(slotWriterFinished(bool)) );
 
511
    //  connect( d->writerJob, SIGNAL(newTask(const QString&)), this, SIGNAL(newTask(const QString&)) );
 
512
    connect( d->writerJob, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) );
 
513
    connect( d->writerJob, SIGNAL(debuggingOutput(const QString&, const QString&)),
 
514
             this, SIGNAL(debuggingOutput(const QString&, const QString&)) );
 
515
}
 
516
 
 
517
 
 
518
void K3b::DvdCopyJob::slotReaderProgress( int p )
 
519
{
 
520
    if( !m_onTheFly || m_onlyCreateImage ) {
 
521
        emit subPercent( p );
 
522
 
 
523
        int bigParts = ( m_onlyCreateImage ? 1 : (m_simulate ? 2 : ( d->verifyData ? m_copies*2 : m_copies ) + 1 ) );
 
524
        emit percent( p/bigParts );
 
525
    }
 
526
}
 
527
 
 
528
 
 
529
void K3b::DvdCopyJob::slotReaderProcessedSize( int p, int c )
 
530
{
 
531
    if( !m_onTheFly || m_onlyCreateImage )
 
532
        emit processedSubSize( p, c );
 
533
 
 
534
    if( m_onlyCreateImage )
 
535
        emit processedSize( p, c );
 
536
}
 
537
 
 
538
 
 
539
void K3b::DvdCopyJob::slotWriterProgress( int p )
 
540
{
 
541
    int bigParts = ( m_simulate ? 1 : ( d->verifyData ? m_copies*2 : m_copies ) ) + ( m_onTheFly ? 0 : 1 );
 
542
    int doneParts = ( m_simulate ? 0 : ( d->verifyData ? d->doneCopies*2 : d->doneCopies ) ) + ( m_onTheFly ? 0 : 1 );
 
543
    emit percent( 100*doneParts/bigParts + p/bigParts );
 
544
 
 
545
    emit subPercent( p );
 
546
}
 
547
 
 
548
 
 
549
void K3b::DvdCopyJob::slotVerificationProgress( int p )
 
550
{
 
551
    int bigParts = ( m_simulate ? 1 : ( d->verifyData ? m_copies*2 : m_copies ) ) + ( m_onTheFly ? 0 : 1 );
 
552
    int doneParts = ( m_simulate ? 0 : ( d->verifyData ? d->doneCopies*2 : d->doneCopies ) ) + ( m_onTheFly ? 0 : 1 ) + 1;
 
553
    emit percent( 100*doneParts/bigParts + p/bigParts );
 
554
}
 
555
 
 
556
 
 
557
void K3b::DvdCopyJob::slotReaderFinished( bool success )
 
558
{
 
559
    d->readerRunning = false;
 
560
 
 
561
    // already finished?
 
562
    if( !d->running )
 
563
        return;
 
564
 
 
565
    if( d->canceled ) {
 
566
        removeImageFiles();
 
567
        emit canceled();
 
568
        jobFinished(false);
 
569
        d->running = false;
 
570
    }
 
571
 
 
572
    if( success ) {
 
573
        emit infoMessage( i18n("Successfully read source medium."), MessageSuccess );
 
574
        if( m_onlyCreateImage ) {
 
575
            jobFinished(true);
 
576
            d->running = false;
 
577
        }
 
578
        else {
 
579
            if( m_writerDevice == m_readerDevice ) {
 
580
                // eject the media (we do this blocking to know if it worked
 
581
                // because if it did not it might happen that k3b overwrites a CD-RW
 
582
                // source)
 
583
                kDebug() << "Ejecting read medium" << m_readerDevice->blockDeviceName();
 
584
                if( !K3b::eject( m_readerDevice ) ) {
 
585
                    blockingInformation( i18n("K3b was unable to eject the source medium. Please do so manually.") );
 
586
                }
 
587
            }
 
588
 
 
589
            if( !m_onTheFly ) {
 
590
 
 
591
                d->imageFile.close();
 
592
 
 
593
                if( waitForDvd() ) {
 
594
                    prepareWriter();
 
595
                    if( m_copies > 1 )
 
596
                        emit newTask( i18n("Writing copy %1",d->doneCopies+1) );
 
597
                    else
 
598
                        emit newTask( i18n("Writing copy") );
 
599
 
 
600
                    emit burning(true);
 
601
 
 
602
                    d->writerRunning = true;
 
603
                    d->writerJob->start();
 
604
#ifdef __GNUC__
 
605
#warning Growisofs needs stdin to be closed in order to exit gracefully. Cdrecord does not. However,  if closed with cdrecord we loose parts of stderr. Why?
 
606
#endif
 
607
                    d->outPipe.writeTo( d->writerJob->ioDevice(), d->usedWritingApp == K3b::WritingAppGrowisofs );
 
608
                    d->outPipe.open( true );
 
609
                }
 
610
                else {
 
611
                    if( m_removeImageFiles )
 
612
                        removeImageFiles();
 
613
                    if( d->canceled )
 
614
                        emit canceled();
 
615
                    jobFinished(false);
 
616
                    d->running = false;
 
617
                }
 
618
            }
 
619
        }
 
620
    }
 
621
    else {
 
622
        removeImageFiles();
 
623
        jobFinished(false);
 
624
        d->running = false;
 
625
    }
 
626
}
 
627
 
 
628
 
 
629
void K3b::DvdCopyJob::slotWriterFinished( bool success )
 
630
{
 
631
    d->writerRunning = false;
 
632
 
 
633
    // already finished?
 
634
    if( !d->running )
 
635
        return;
 
636
 
 
637
    if( d->canceled ) {
 
638
        if( m_removeImageFiles )
 
639
            removeImageFiles();
 
640
        emit canceled();
 
641
        jobFinished(false);
 
642
        d->running = false;
 
643
    }
 
644
 
 
645
    if( success ) {
 
646
        emit infoMessage( i18n("Successfully written copy %1.",d->doneCopies+1), MessageInfo );
 
647
 
 
648
        if( d->verifyData && !m_simulate ) {
 
649
            if( !d->verificationJob ) {
 
650
                d->verificationJob = new K3b::VerificationJob( this, this );
 
651
                connect( d->verificationJob, SIGNAL(infoMessage(const QString&, int)),
 
652
                         this, SIGNAL(infoMessage(const QString&, int)) );
 
653
                connect( d->verificationJob, SIGNAL(newTask(const QString&)),
 
654
                         this, SIGNAL(newSubTask(const QString&)) );
 
655
                connect( d->verificationJob, SIGNAL(percent(int)),
 
656
                         this, SLOT(slotVerificationProgress(int)) );
 
657
                connect( d->verificationJob, SIGNAL(percent(int)),
 
658
                         this, SIGNAL(subPercent(int)) );
 
659
                connect( d->verificationJob, SIGNAL(finished(bool)),
 
660
                         this, SLOT(slotVerificationFinished(bool)) );
 
661
                connect( d->verificationJob, SIGNAL(debuggingOutput(const QString&, const QString&)),
 
662
                         this, SIGNAL(debuggingOutput(const QString&, const QString&)) );
 
663
 
 
664
            }
 
665
            d->verificationJob->setDevice( m_writerDevice );
 
666
            d->verificationJob->addTrack( 1, d->inPipe.checksum(), d->lastSector+1 );
 
667
 
 
668
            if( m_copies > 1 )
 
669
                emit newTask( i18n("Verifying copy %1",d->doneCopies+1) );
 
670
            else
 
671
                emit newTask( i18n("Verifying copy") );
 
672
 
 
673
            emit burning( false );
 
674
 
 
675
            d->verificationJob->start();
 
676
        }
 
677
 
 
678
        else if( ++d->doneCopies < m_copies ) {
 
679
 
 
680
            if( !K3b::eject( m_writerDevice ) ) {
 
681
                blockingInformation( i18n("K3b was unable to eject the written medium. Please do so manually.") );
 
682
            }
 
683
 
 
684
            if( waitForDvd() ) {
 
685
                prepareWriter();
 
686
                emit newTask( i18n("Writing copy %1",d->doneCopies+1) );
 
687
 
 
688
                emit burning(true);
 
689
 
 
690
                d->writerRunning = true;
 
691
                d->writerJob->start();
 
692
            }
 
693
            else {
 
694
                if( d->canceled )
 
695
                    emit canceled();
 
696
                jobFinished(false);
 
697
                d->running = false;
 
698
                return;
 
699
            }
 
700
 
 
701
            if( m_onTheFly ) {
 
702
                prepareReader();
 
703
                d->readerRunning = true;
 
704
                d->dataTrackReader->start();
 
705
            }
 
706
            else {
 
707
#ifdef __GNUC__
 
708
#warning Growisofs needs stdin to be closed in order to exit gracefully. Cdrecord does not. However,  if closed with cdrecord we loose parts of stderr. Why?
 
709
#endif
 
710
                d->outPipe.writeTo( d->writerJob->ioDevice(), true/*d->usedWritingApp == K3b::WritingAppGrowisofs*/ );
 
711
                d->outPipe.open( true );
 
712
            }
 
713
        }
 
714
        else {
 
715
            if ( k3bcore->globalSettings()->ejectMedia() ) {
 
716
                K3b::Device::eject( m_writerDevice );
 
717
            }
 
718
            if( m_removeImageFiles )
 
719
                removeImageFiles();
 
720
            d->running = false;
 
721
            jobFinished(true);
 
722
        }
 
723
    }
 
724
    else {
 
725
        if( m_removeImageFiles )
 
726
            removeImageFiles();
 
727
        d->running = false;
 
728
        jobFinished(false);
 
729
    }
 
730
}
 
731
 
 
732
 
 
733
void K3b::DvdCopyJob::slotVerificationFinished( bool success )
 
734
{
 
735
    if ( d->canceled ) {
 
736
        emit canceled();
 
737
        jobFinished( false );
 
738
    }
 
739
 
 
740
    // we simply ignore the results from the verification, the verification
 
741
    // job already emits a message
 
742
    else if( ++d->doneCopies < m_copies ) {
 
743
 
 
744
        if( waitForDvd() ) {
 
745
            prepareWriter();
 
746
            emit newTask( i18n("Writing copy %1",d->doneCopies+1) );
 
747
 
 
748
            emit burning(true);
 
749
 
 
750
            d->writerRunning = true;
 
751
            d->writerJob->start();
 
752
        }
 
753
        else {
 
754
            if( d->canceled )
 
755
                emit canceled();
 
756
            jobFinished(false);
 
757
            d->running = false;
 
758
            return;
 
759
        }
 
760
 
 
761
        if( m_onTheFly ) {
 
762
            prepareReader();
 
763
            d->readerRunning = true;
 
764
            d->dataTrackReader->start();
 
765
        }
 
766
        else {
 
767
#ifdef __GNUC__
 
768
#warning Growisofs needs stdin to be closed in order to exit gracefully. Cdrecord does not. However,  if closed with cdrecord we loose parts of stderr. Why?
 
769
#endif
 
770
            d->outPipe.writeTo( d->writerJob->ioDevice(), d->usedWritingApp == K3b::WritingAppGrowisofs );
 
771
            d->outPipe.open( true );
 
772
        }
 
773
    }
 
774
    else {
 
775
        if( m_removeImageFiles )
 
776
            removeImageFiles();
 
777
        d->running = false;
 
778
        jobFinished( success );
 
779
    }
 
780
}
 
781
 
 
782
 
 
783
// this is basically the same code as in K3b::DvdJob... :(
 
784
// perhaps this should be moved to some K3b::GrowisofsHandler which also parses the growisofs output?
 
785
bool K3b::DvdCopyJob::waitForDvd()
 
786
{
 
787
    Device::MediaTypes mt = 0;
 
788
    if ( !K3b::Device::isDvdMedia( d->sourceDiskInfo.mediaType() ) &&
 
789
         !K3b::Device::isBdMedia( d->sourceDiskInfo.mediaType() ) ) {
 
790
        // this should NEVER happen
 
791
        emit infoMessage( i18n( "Unsupported media type: %1" , K3b::Device::mediaTypeString( d->sourceDiskInfo.mediaType() ) ), MessageError );
 
792
        return false;
 
793
    }
 
794
 
 
795
    Device::MediaType m = waitForMedium( m_writerDevice,
 
796
                                         K3b::Device::STATE_EMPTY,
 
797
                                         Device::MEDIA_WRITABLE_DVD|Device::MEDIA_WRITABLE_BD,
 
798
                                         d->sourceDiskInfo.size() );
 
799
 
 
800
    if( m == Device::MEDIA_UNKNOWN ) {
 
801
        cancel();
 
802
        return false;
 
803
    }
 
804
 
 
805
    else {
 
806
        // -------------------------------
 
807
        // DVD Plus
 
808
        // -------------------------------
 
809
        if( m & K3b::Device::MEDIA_DVD_PLUS_ALL ) {
 
810
 
 
811
            if ( m & ( Device::MEDIA_DVD_PLUS_R|Device::MEDIA_DVD_PLUS_R_DL ) )
 
812
                d->usedWritingMode = K3b::WritingModeSao;
 
813
            else
 
814
                d->usedWritingMode = K3b::WritingModeRestrictedOverwrite;
 
815
 
 
816
            if( m_simulate ) {
 
817
                if( !questionYesNo( i18n("%1 media do not support write simulation. "
 
818
                                         "Do you really want to continue? The disc will actually be "
 
819
                                         "written to.", Device::mediaTypeString(m, true)),
 
820
                                    i18n("No Simulation with %1", Device::mediaTypeString(m, true)) ) ) {
 
821
                    cancel();
 
822
                    return false;
 
823
                }
 
824
 
 
825
//      m_simulate = false;
 
826
                emit newTask( i18n("Writing DVD copy") );
 
827
            }
 
828
 
 
829
            if( m_writingMode != K3b::WritingModeAuto && m_writingMode != K3b::WritingModeRestrictedOverwrite )
 
830
                emit infoMessage( i18n("Writing mode ignored when writing DVD+R(W) media."), MessageInfo );
 
831
 
 
832
            emit infoMessage( i18n("Writing %1.", Device::mediaTypeString( m, true ) ), MessageInfo );
 
833
        }
 
834
 
 
835
        // -------------------------------
 
836
        // DVD Minus
 
837
        // -------------------------------
 
838
        else if ( m & K3b::Device::MEDIA_DVD_MINUS_ALL ) {
 
839
            if( m_simulate && !m_writerDevice->dvdMinusTestwrite() ) {
 
840
                if( !questionYesNo( i18n("Your writer (%1 %2) does not support simulation with DVD-R(W) media. "
 
841
                                         "Do you really want to continue? The media will actually be "
 
842
                                         "written to.",
 
843
                                         m_writerDevice->vendor(),
 
844
                                         m_writerDevice->description()),
 
845
                                    i18n("No Simulation with DVD-R(W)") ) ) {
 
846
                    cancel();
 
847
                    return false;
 
848
                }
 
849
 
 
850
//      m_simulate = false;
 
851
            }
 
852
 
 
853
            //
 
854
            // We do not default to DAO in onthefly mode since otherwise growisofs would
 
855
            // use the size from the PVD to reserve space on the DVD and that can be bad
 
856
            // if this size is wrong
 
857
            // With growisofs 5.15 we have the option to specify the size of the image to be written in DAO mode.
 
858
            //
 
859
//       bool sizeWithDao = ( k3bcore->externalBinManager()->binObject( "growisofs" ) &&
 
860
//                         k3bcore->externalBinManager()->binObject( "growisofs" )->version >= K3b::Version( 5, 15, -1 ) );
 
861
 
 
862
 
 
863
            // TODO: check for feature 0x21
 
864
 
 
865
            if( m & K3b::Device::MEDIA_DVD_RW_OVWR ) {
 
866
                emit infoMessage( i18n("Writing DVD-RW in restricted overwrite mode."), MessageInfo );
 
867
                d->usedWritingMode = K3b::WritingModeRestrictedOverwrite;
 
868
            }
 
869
            else if( m & (K3b::Device::MEDIA_DVD_RW_SEQ|
 
870
                          K3b::Device::MEDIA_DVD_RW) ) {
 
871
                if( m_writingMode == K3b::WritingModeSao ) {
 
872
//          ( m_writingMode ==  K3b::WritingModeAuto &&
 
873
//            ( sizeWithDao || !m_onTheFly ) ) ) {
 
874
                    emit infoMessage( i18n("Writing DVD-RW in DAO mode."), MessageInfo );
 
875
                    d->usedWritingMode = K3b::WritingModeSao;
 
876
                }
 
877
                else {
 
878
                    emit infoMessage( i18n("Writing DVD-RW in incremental mode."), MessageInfo );
 
879
                    d->usedWritingMode = K3b::WritingModeIncrementalSequential;
 
880
                }
 
881
            }
 
882
            else {
 
883
 
 
884
                // FIXME: DVD-R DL jump and stuff
 
885
 
 
886
                if( m_writingMode == K3b::WritingModeRestrictedOverwrite )
 
887
                    emit infoMessage( i18n("Restricted Overwrite is not possible with DVD-R media."), MessageInfo );
 
888
 
 
889
                if( m_writingMode == K3b::WritingModeSao ) {
 
890
//          ( m_writingMode ==  K3b::WritingModeAuto &&
 
891
//            ( sizeWithDao || !m_onTheFly ) ) ) {
 
892
                    emit infoMessage( i18n("Writing %1 in DAO mode.",K3b::Device::mediaTypeString(m, true) ), MessageInfo );
 
893
                    d->usedWritingMode = K3b::WritingModeSao;
 
894
                }
 
895
                else {
 
896
                    emit infoMessage( i18n("Writing %1 in incremental mode.",K3b::Device::mediaTypeString(m, true) ), MessageInfo );
 
897
                    d->usedWritingMode = K3b::WritingModeIncrementalSequential;
 
898
                }
 
899
            }
 
900
        }
 
901
 
 
902
 
 
903
        // -------------------------------
 
904
        // Blu-ray
 
905
        // -------------------------------
 
906
        else {
 
907
            d->usedWritingMode = K3b::WritingModeSao;
 
908
 
 
909
            if( m_simulate ) {
 
910
                if( !questionYesNo( i18n("%1 media do not support write simulation. "
 
911
                                         "Do you really want to continue? The disc will actually be "
 
912
                                         "written to.", Device::mediaTypeString(m, true)),
 
913
                                    i18n("No Simulation with %1", Device::mediaTypeString(m, true)) ) ) {
 
914
                    cancel();
 
915
                    return false;
 
916
                }
 
917
 
 
918
                m_simulate = false;
 
919
                emit newTask( i18n("Writing BD copy") );
 
920
            }
 
921
 
 
922
            emit infoMessage( i18n("Writing %1.", Device::mediaTypeString(m, true) ), MessageInfo );
 
923
        }
 
924
    }
 
925
 
 
926
    return true;
 
927
}
 
928
 
 
929
 
 
930
 
 
931
void K3b::DvdCopyJob::removeImageFiles()
 
932
{
 
933
    if( QFile::exists( m_imagePath ) ) {
 
934
        d->imageFile.remove();
 
935
        emit infoMessage( i18n("Removed image file %1",m_imagePath), K3b::Job::MessageSuccess );
 
936
    }
 
937
}
 
938
 
 
939
 
 
940
QString K3b::DvdCopyJob::jobDescription() const
 
941
{
 
942
    if( m_onlyCreateImage ) {
 
943
        return i18n("Creating Image");
 
944
    }
 
945
    else {
 
946
        if( m_onTheFly )
 
947
            return i18n("Copying DVD or BD On-The-Fly");
 
948
        else
 
949
            return i18n("Copying DVD or BD");
 
950
    }
 
951
}
 
952
 
 
953
 
 
954
QString K3b::DvdCopyJob::jobDetails() const
 
955
{
 
956
    return i18np("Creating 1 copy",
 
957
                 "Creating %1 copies",
 
958
                 (m_simulate||m_onlyCreateImage) ? 1 : m_copies );
 
959
}
 
960
 
 
961
 
 
962
void K3b::DvdCopyJob::setVerifyData( bool b )
 
963
{
 
964
    d->verifyData = b;
 
965
}
 
966
 
 
967
#include "k3bdvdcopyjob.moc"