K3b::Msf K3b::Msf::fromString( const QString& s, bool* ok ) { QRegExp rx = regExp(); K3b::Msf msf; if( rx.exactMatch( s ) ) { // // first number - cap(1) // second number - cap(2) // third number - cap(3) // if( rx.cap(2).isEmpty() ) { msf.m_frames = rx.cap(1).toInt(); } else { msf.m_minutes = rx.cap(1).toInt(); msf.m_seconds = rx.cap(2).toInt(); msf.m_frames = rx.cap(3).toInt(); } if( ok ) *ok = true; } else if( ok ) *ok = false; msf.makeValid(); return msf; }
K3b::AudioRippingDialog::AudioRippingDialog( const K3b::Medium& medium, const KCDDB::CDInfo& entry, const QList<int>& tracks, QWidget *parent ) : K3b::InteractionDialog( parent, QString(), QString(), START_BUTTON|CANCEL_BUTTON, START_BUTTON, "Audio Ripping" ), // config group m_medium( medium ), m_cddbEntry( entry ), m_trackNumbers( tracks ) { d = new Private(); setupGui(); setupContextHelp(); K3b::Msf length; K3b::Device::Toc toc = medium.toc(); for( QList<int>::const_iterator it = m_trackNumbers.constBegin(); it != m_trackNumbers.constEnd(); ++it ) { length += toc[*it].length(); } setTitle( i18n("CD Ripping"), i18np("1 track (%2)", "%1 tracks (%2)", m_trackNumbers.count(),length.toString()) ); }
void K3b::TRM::start( const K3b::Msf& length ) { if( KProtocolManager::useProxy() ) { QUrl proxy( KProtocolManager::proxyFor("http") ); trm_SetProxy( d->trm, const_cast<char*>(proxy.host().toLatin1().constData()), short(proxy.port()) ); } trm_SetPCMDataInfo( d->trm, 44100, 2, 16 ); trm_SetSongLength( d->trm, length.totalFrames()/75 ); }
bool K3bFFMpegFile::seek( const K3b::Msf& msf ) { d->outputBufferSize = 0; d->packetSize = 0; double seconds = (double)msf.totalFrames()/75.0; quint64 timestamp = (quint64)(seconds * (double)AV_TIME_BASE); // FIXME: do we really need the start_time and why? #if LIBAVFORMAT_BUILD >= 4619 return ( ::av_seek_frame( d->formatContext, -1, timestamp + d->formatContext->start_time, 0 ) >= 0 ); #else return ( ::av_seek_frame( d->formatContext, -1, timestamp + d->formatContext->start_time ) >= 0 ); #endif }
void K3b::FillStatusDisplay::Private::setCdSize( const K3b::Msf& size ) { // Remove check mark from the currently checked action if( QAction* checked = cdSizeGroup->checkedAction() ) { checked->setChecked( false ); } switch( size.totalFrames() ) { case MediaSizeCd74Min: case 650*512: displayWidget->setCdSize( MediaSizeCd74Min ); action74Min->setChecked( true ); break; case MediaSizeCd80Min: case 700*512: displayWidget->setCdSize( MediaSizeCd80Min ); action80Min->setChecked( true ); break; case MediaSizeCd100Min: case 880*512: displayWidget->setCdSize( MediaSizeCd100Min ); action100Min->setChecked( true ); break; case MediaSizeDvd4Gb: case 2306867: // rounded 4.4*1024*512 displayWidget->setCdSize( MediaSizeDvd4Gb ); actionDvd4_7GB->setChecked( true ); break; case MediaSizeDvd8Gb: case 8*1024*512: displayWidget->setCdSize( MediaSizeDvd8Gb ); actionDvdDoubleLayer->setChecked( true ); break; case MediaSizeBluRay25Gb: //case 25*1024*512: displayWidget->setCdSize( MediaSizeBluRay25Gb ); actionBD25->setChecked( true ); break; case MediaSizeBluRay50Gb: //case 50*1024*512: displayWidget->setCdSize( MediaSizeBluRay50Gb ); actionBD50->setChecked( true ); break; default: displayWidget->setCdSize( size ); break; } }
void K3b::DataPropertiesDialog::loadListProperties( const QList<K3b::DataItem*>& items ) { m_labelIcon->setPixmap( DesktopIcon( "document-multiple", KIconLoader::SizeLarge ) ); int files = 0; int folders = 0; KIO::filesize_t size = 0; K3b::Msf blocks = 0; for ( QList<K3b::DataItem*>::iterator it = m_dataItems.begin(); it != m_dataItems.end(); ++it ) { K3b::DataItem* item = *it; if ( item->isFile() ) ++files; else if ( item->isDir() ) ++folders; blocks += item->blocks(); size += item->size(); } QString s = i18np( "One Item", "%1 Items", items.count() ); s += " - "; if ( files > 0 ) s += i18np( "One File", "%1 Files", files ); else s += i18n( "No Files" ); s += " - "; if ( folders > 0 ) s += i18np( "One Folder", "%1 Folders", folders ); else s += i18n( "No Folders" ); m_multiSelectionLabel->setText( s ); m_labelSize->setText( KIO::convertSize(size) ); m_labelBlocks->setText( QString::number(blocks.lba()) ); // the location of all items are the same since it is not possible to // select items from different folders // FIXME: maybe better use QString::section? QString location = '/' + items.first()->k3bPath(); if( location[location.length()-1] == '/' ) location.truncate( location.length()-1 ); location.truncate( location.lastIndexOf('/') ); if( location.isEmpty() ) location = '/'; m_labelLocation->setText( location ); m_checkHideOnJoliet->setChecked( items.first()->hideOnJoliet() ); for ( QList<K3b::DataItem*>::iterator it = m_dataItems.begin(); it != m_dataItems.end(); ++it ) { K3b::DataItem* item = *it; if ( m_checkHideOnJoliet->isChecked() != item->hideOnJoliet() ) { m_checkHideOnJoliet->setCheckState( Qt::PartiallyChecked ); break; } } m_checkHideOnRockRidge->setChecked( items.first()->hideOnRockRidge() ); for ( QList<K3b::DataItem*>::iterator it = m_dataItems.begin(); it != m_dataItems.end(); ++it ) { K3b::DataItem* item = *it; if ( m_checkHideOnRockRidge->isChecked() != item->hideOnRockRidge() ) { m_checkHideOnRockRidge->setCheckState( Qt::PartiallyChecked ); break; } } int weight = items.first()->sortWeight(); for ( QList<K3b::DataItem*>::iterator it = m_dataItems.begin(); it != m_dataItems.end(); ++it ) { K3b::DataItem* item = *it; if ( weight != item->sortWeight() ) { weight = 0; break; } } m_editSortWeight->setText( QString::number( weight ) ); }
bool K3b::operator>=( const K3b::Msf& m1, const K3b::Msf& m2 ) { return ( m1.lba() >= m2.lba() ); }
bool K3b::operator<( const K3b::Msf& m1, const K3b::Msf& m2 ) { return ( m1.lba() < m2.lba() ); }
bool K3b::operator==( const K3b::Msf& m1, const K3b::Msf& m2 ) { return ( m1.minutes() == m2.minutes() && m1.seconds() == m2.seconds() && m1.frames() == m2.frames() ); }
K3b::Msf::Msf( const K3b::Msf& m ) : m_minutes(m.minutes()), m_seconds(m.seconds()), m_frames(m.frames()) { }
void K3b::AudioRippingDialog::refresh() { d->viewTracks->clear(); d->filenames.clear(); QString baseDir = K3b::prepareDir( m_optionWidget->baseDir() ); d->fsInfo.setPath( baseDir ); KIO::filesize_t overallSize = 0; K3b::Device::Toc toc = m_medium.toc(); if( m_optionWidget->createSingleFile() ) { long length = 0; for( QList<int>::const_iterator it = m_trackNumbers.constBegin(); it != m_trackNumbers.constEnd(); ++it ) { length += ( m_checkUseIndex0->isChecked() ? toc[*it].realAudioLength().lba() : toc[*it].length().lba() ); } QString filename; QString extension; long long fileSize = 0; if( m_optionWidget->encoder() == 0 ) { extension = "wav"; fileSize = length * 2352 + 44; } else { extension = m_optionWidget->extension(); fileSize = m_optionWidget->encoder()->fileSize( extension, length ); } if( fileSize > 0 ) overallSize = fileSize; filename = d->fsInfo.fixupPath( K3b::PatternParser::parsePattern( m_cddbEntry, 1, extension, m_patternWidget->playlistPattern(), m_patternWidget->replaceBlanks(), m_patternWidget->blankReplaceString() ) ); d->addTrack( filename, K3b::Msf(length).toString(), fileSize < 0 ? i18n("unknown") : KIO::convertSize( fileSize ), i18n("Audio") ); d->filenames.append( baseDir + filename ); if( m_optionWidget->createCueFile() ) { QString cueFileName = d->fsInfo.fixupPath( K3b::PatternParser::parsePattern( m_cddbEntry, 1, QLatin1String( "cue" ), m_patternWidget->playlistPattern(), m_patternWidget->replaceBlanks(), m_patternWidget->blankReplaceString() ) ); d->addTrack( cueFileName, "-", "-", i18n("Cue-file") ); } } else { for( int i = 0; i < m_trackNumbers.count(); ++i ) { int trackIndex = m_trackNumbers[i]; QString extension; long long fileSize = 0; K3b::Msf trackLength = ( m_checkUseIndex0->isChecked() ? toc[trackIndex].realAudioLength() : toc[trackIndex].length() ); if( m_optionWidget->encoder() == 0 ) { extension = "wav"; fileSize = trackLength.audioBytes() + 44; } else { extension = m_optionWidget->extension(); fileSize = m_optionWidget->encoder()->fileSize( extension, trackLength ); } if( fileSize > 0 ) overallSize += fileSize; if( toc[trackIndex].type() == K3b::Device::Track::TYPE_DATA ) { extension = ".iso"; continue; // TODO: find out how to rip the iso data } QString filename; filename = K3b::PatternParser::parsePattern( m_cddbEntry, trackIndex+1, extension, m_patternWidget->filenamePattern(), m_patternWidget->replaceBlanks(), m_patternWidget->blankReplaceString() ); if ( filename.isEmpty() ){ filename = i18n("Track%1", QString::number( trackIndex+1 ).rightJustified( 2, '0' ) ) + '.' + extension; } filename = d->fsInfo.fixupPath( filename ); d->addTrack( filename, trackLength.toString(), fileSize < 0 ? i18n("unknown") : KIO::convertSize( fileSize ), toc[trackIndex].type() == K3b::Device::Track::TYPE_AUDIO ? i18n("Audio") : i18n("Data") ); d->filenames.append( baseDir + filename ); } } // create playlist item if( m_optionWidget->createPlaylist() ) { QString filename = K3b::PatternParser::parsePattern( m_cddbEntry, 1, QLatin1String( "m3u" ), m_patternWidget->playlistPattern(), m_patternWidget->replaceBlanks(), m_patternWidget->blankReplaceString() ); d->addTrack( filename, "-", "-", i18n("Playlist") ); d->playlistFilename = d->fsInfo.fixupPath( baseDir + '/' + filename ); } if( overallSize > 0 ) m_optionWidget->setNeededSize( overallSize ); else m_optionWidget->setNeededSize( 0 ); }
bool K3bMadDecoder::seekInternal( const K3b::Msf& pos ) { // // we need to reset the complete mad stuff // if( !initDecoderInternal() ) return false; // // search a position // This is all hacking, I don't really know what I am doing here... ;) // double mp3FrameSecs = static_cast<double>(d->firstHeader.duration.seconds) + static_cast<double>(d->firstHeader.duration.fraction) / static_cast<double>(MAD_TIMER_RESOLUTION); double posSecs = static_cast<double>(pos.totalFrames()) / 75.0; // seekPosition to seek after frame i unsigned int frame = static_cast<unsigned int>( posSecs / mp3FrameSecs ); // Rob said: 29 frames is the theoretically max frame reservoir limit (whatever that means...) // it seems that mad needs at most 29 frames to get ready unsigned int frameReservoirProtect = ( frame > 29 ? 29 : frame ); frame -= frameReservoirProtect; // seek in the input file behind the already decoded data d->handle->inputSeek( d->seekPositions[frame] ); qDebug() << "(K3bMadDecoder) Seeking to frame " << frame << " with " << frameReservoirProtect << " reservoir frames." << endl; // decode some frames ignoring MAD_ERROR_BADDATAPTR errors unsigned int i = 1; while( i <= frameReservoirProtect ) { d->handle->fillStreamBuffer(); if( mad_frame_decode( d->handle->madFrame, d->handle->madStream ) ) { if( MAD_RECOVERABLE( d->handle->madStream->error ) ) { if( d->handle->madStream->error == MAD_ERROR_BUFLEN ) continue; else if( d->handle->madStream->error != MAD_ERROR_BADDATAPTR ) { qDebug() << "(K3bMadDecoder) Seeking: recoverable mad error (" << mad_stream_errorstr(d->handle->madStream) << ")" << endl; continue; } else { qDebug() << "(K3bMadDecoder) Seeking: ignoring (" << mad_stream_errorstr(d->handle->madStream) << ")" << endl; } } else return false; } if( i == frameReservoirProtect ) // synth only the last frame (Rob said so ;) mad_synth_frame( d->handle->madSynth, d->handle->madFrame ); ++i; } return true; }
bool K3b::TocFileWriter::save( QTextStream& t ) { writeHeader(t); if( !m_cdText.isEmpty() ) writeGlobalCdText(t); // // see if we have multiple sessions // int sessions = 1; for( K3b::Device::Toc::iterator it = m_toc.begin(); it != m_toc.end(); ++it ) { if( (*it).session() > 1 ) sessions = (*it).session(); } if( m_sessionToWrite > sessions ) m_sessionToWrite = 1; // // We can only hide the first track if both the first and the second track are // audio tracks. // We also can only hide the first track in the first session. // bool hideFirstTrack = m_hideFirstTrack; if( m_toc.count() < 2 || m_toc[0].type() != K3b::Device::Track::TYPE_AUDIO || m_toc[1].type() != K3b::Device::Track::TYPE_AUDIO || (sessions > 1 && m_sessionToWrite != 1 ) ) hideFirstTrack = false; // the dataStart will be the offset in case we do not write the first session K3b::Msf dataStart; int trackIndex = 0; if( hideFirstTrack ) { const K3b::Device::Track& hiddenTrack = m_toc[0]; const K3b::Device::Track& track = m_toc[1]; t << "// Track number 1 (hidden) and track number 2 (as track 1)" << endl; t << "TRACK AUDIO" << endl; if( track.copyPermitted() ) t << "COPY" << endl; else t << "NO COPY" << endl; if( track.preEmphasis() ) t << "PRE_EMPHASIS" << endl; else t << "NO PRE_EMPHASIS" << endl; if( !m_cdText.isEmpty() ) writeTrackCdText( m_cdText[0], t ); // the "hidden" file will be used as pregap for the "first" track t << "AUDIOFILE "; writeDataSource( 0, t ); if( readFromStdin() ) t << hiddenTrack.firstSector().toString(); else t << " 0"; t << " " << hiddenTrack.length().toString() << endl; t << "START" << endl; // use the whole hidden file as pregap // now comes the "real" first track t << "AUDIOFILE "; writeDataSource( 1, t ); if( readFromStdin() ) t << track.firstSector().toString() << " "; else t << "0 "; // no index 0 for the last track. Or should we allow this??? if( m_toc.count() == 2 ) t << track.length().toString(); else t << track.realAudioLength().toString(); t << endl << endl; trackIndex+=2; } else { // // Seek to the first track to write. // In case we hid the first track above it was the first track anyway. // while( m_toc[trackIndex].session() < m_sessionToWrite && m_toc[trackIndex].session() > 0 ) ++trackIndex; dataStart = m_toc[trackIndex].firstSector(); } kDebug() << "(K3b::TocFileWriter) using offset of: " << dataStart.toString(); while( trackIndex < m_toc.count() ) { if( m_toc[trackIndex].session() == 0 || m_toc[trackIndex].session() == m_sessionToWrite ) writeTrack( trackIndex, dataStart, t ); trackIndex++; } return ( t.status() == QTextStream::Ok ); }