summaryrefslogtreecommitdiffstats
path: root/libk3b/projects/videocd
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-03 02:15:56 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-03 02:15:56 +0000
commit50b48aec6ddd451a6d1709c0942477b503457663 (patch)
treea9ece53ec06fd0a2819de7a2a6de997193566626 /libk3b/projects/videocd
downloadk3b-50b48aec6ddd451a6d1709c0942477b503457663.tar.gz
k3b-50b48aec6ddd451a6d1709c0942477b503457663.zip
Added abandoned KDE3 version of K3B
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/k3b@1084400 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'libk3b/projects/videocd')
-rw-r--r--libk3b/projects/videocd/Makefile.am20
-rw-r--r--libk3b/projects/videocd/cdi/Makefile.am5
-rw-r--r--libk3b/projects/videocd/cdi/cdi_imag.rtfbin0 -> 1314877 bytes
-rw-r--r--libk3b/projects/videocd/cdi/cdi_text.fntbin0 -> 13616 bytes
-rw-r--r--libk3b/projects/videocd/cdi/cdi_vcd.appbin0 -> 102400 bytes
-rw-r--r--libk3b/projects/videocd/cdi/cdi_vcd.cfg12
-rw-r--r--libk3b/projects/videocd/cdi/icdia.htm12
-rw-r--r--libk3b/projects/videocd/cdi/vcd_on_cdi_41.pdfbin0 -> 126675 bytes
-rw-r--r--libk3b/projects/videocd/extra/Makefile.am5
-rw-r--r--libk3b/projects/videocd/extra/k3bphotosvcd.mpgbin0 -> 824970 bytes
-rw-r--r--libk3b/projects/videocd/extra/k3bphotovcd.mpgbin0 -> 1731138 bytes
-rw-r--r--libk3b/projects/videocd/k3bvcddoc.cpp894
-rw-r--r--libk3b/projects/videocd/k3bvcddoc.h192
-rw-r--r--libk3b/projects/videocd/k3bvcdjob.cpp567
-rw-r--r--libk3b/projects/videocd/k3bvcdjob.h115
-rw-r--r--libk3b/projects/videocd/k3bvcdoptions.cpp146
-rw-r--r--libk3b/projects/videocd/k3bvcdoptions.h377
-rw-r--r--libk3b/projects/videocd/k3bvcdtrack.cpp456
-rw-r--r--libk3b/projects/videocd/k3bvcdtrack.h198
-rw-r--r--libk3b/projects/videocd/k3bvcdxmlview.cpp440
-rw-r--r--libk3b/projects/videocd/k3bvcdxmlview.h59
-rw-r--r--libk3b/projects/videocd/mpeginfo/Makefile.am5
-rw-r--r--libk3b/projects/videocd/mpeginfo/k3bmpeginfo.cpp844
-rw-r--r--libk3b/projects/videocd/mpeginfo/k3bmpeginfo.h178
24 files changed, 4525 insertions, 0 deletions
diff --git a/libk3b/projects/videocd/Makefile.am b/libk3b/projects/videocd/Makefile.am
new file mode 100644
index 0000000..1e18d02
--- /dev/null
+++ b/libk3b/projects/videocd/Makefile.am
@@ -0,0 +1,20 @@
+AM_CPPFLAGS= -I$(srcdir)/../../core \
+ -I$(srcdir)/../../../src \
+ -I$(srcdir)/../../../libk3bdevice \
+ -I$(srcdir)/../../tools \
+ -I$(srcdir)/.. \
+ $(all_includes)
+
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libvcd.la
+
+libvcd_la_SOURCES = k3bvcddoc.cpp k3bvcdtrack.cpp k3bvcdjob.cpp k3bvcdoptions.cpp k3bvcdxmlview.cpp
+
+libvcd_la_LIBADD = mpeginfo/libmpeginfo.la
+
+SUBDIRS = cdi extra mpeginfo
+
+include_HEADERS = k3bvcdjob.h \
+ k3bvcddoc.h \
+ k3bvcdoptions.h
diff --git a/libk3b/projects/videocd/cdi/Makefile.am b/libk3b/projects/videocd/cdi/Makefile.am
new file mode 100644
index 0000000..e487acc
--- /dev/null
+++ b/libk3b/projects/videocd/cdi/Makefile.am
@@ -0,0 +1,5 @@
+
+cdidir = $(kde_datadir)/k3b/cdi
+cdi_DATA = cdi_imag.rtf cdi_text.fnt cdi_vcd.app cdi_vcd.cfg vcd_on_cdi_41.pdf icdia.htm
+
+EXTRA_DIST = $(cdi_DATA)
diff --git a/libk3b/projects/videocd/cdi/cdi_imag.rtf b/libk3b/projects/videocd/cdi/cdi_imag.rtf
new file mode 100644
index 0000000..809145f
--- /dev/null
+++ b/libk3b/projects/videocd/cdi/cdi_imag.rtf
Binary files differ
diff --git a/libk3b/projects/videocd/cdi/cdi_text.fnt b/libk3b/projects/videocd/cdi/cdi_text.fnt
new file mode 100644
index 0000000..0dd0e15
--- /dev/null
+++ b/libk3b/projects/videocd/cdi/cdi_text.fnt
Binary files differ
diff --git a/libk3b/projects/videocd/cdi/cdi_vcd.app b/libk3b/projects/videocd/cdi/cdi_vcd.app
new file mode 100644
index 0000000..ceb31fc
--- /dev/null
+++ b/libk3b/projects/videocd/cdi/cdi_vcd.app
Binary files differ
diff --git a/libk3b/projects/videocd/cdi/cdi_vcd.cfg b/libk3b/projects/videocd/cdi/cdi_vcd.cfg
new file mode 100644
index 0000000..4aed0eb
--- /dev/null
+++ b/libk3b/projects/videocd/cdi/cdi_vcd.cfg
@@ -0,0 +1,12 @@
+CONTROLS=ALL
+CURCOL=YELLOW
+PSDCURCOL=RED
+PSDCURSHAPE=ARROW
+CENTRTRACK=2
+AUTOPLAY=AUTO_ON
+DUALCHAN=DUAL_ON
+TIMECODE_X=64
+TIMECODE_Y=100
+LOTID_X=64
+LOTID_Y=64
+ALBUM=STANDARD \ No newline at end of file
diff --git a/libk3b/projects/videocd/cdi/icdia.htm b/libk3b/projects/videocd/cdi/icdia.htm
new file mode 100644
index 0000000..cd6c47b
--- /dev/null
+++ b/libk3b/projects/videocd/cdi/icdia.htm
@@ -0,0 +1,12 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<META HTTP-EQUIV="Refresh" CONTENT="0; URL=http://www.icdia.org/">
+<TITLE>The New International CD-i Association</TITLE>
+</HEAD>
+<BODY>
+
+<A HREF="http://www.icdia.org">The New International CD-i Association - http://www.icdia.org</A>
+
+</BODY>
+</HTML>
diff --git a/libk3b/projects/videocd/cdi/vcd_on_cdi_41.pdf b/libk3b/projects/videocd/cdi/vcd_on_cdi_41.pdf
new file mode 100644
index 0000000..cdf4fed
--- /dev/null
+++ b/libk3b/projects/videocd/cdi/vcd_on_cdi_41.pdf
Binary files differ
diff --git a/libk3b/projects/videocd/extra/Makefile.am b/libk3b/projects/videocd/extra/Makefile.am
new file mode 100644
index 0000000..717fa99
--- /dev/null
+++ b/libk3b/projects/videocd/extra/Makefile.am
@@ -0,0 +1,5 @@
+
+extradir = $(kde_datadir)/k3b/extra
+extra_DATA = k3bphotovcd.mpg k3bphotosvcd.mpg
+
+EXTRA_DIST = $(extra_DATA)
diff --git a/libk3b/projects/videocd/extra/k3bphotosvcd.mpg b/libk3b/projects/videocd/extra/k3bphotosvcd.mpg
new file mode 100644
index 0000000..50156d7
--- /dev/null
+++ b/libk3b/projects/videocd/extra/k3bphotosvcd.mpg
Binary files differ
diff --git a/libk3b/projects/videocd/extra/k3bphotovcd.mpg b/libk3b/projects/videocd/extra/k3bphotovcd.mpg
new file mode 100644
index 0000000..2ddb69e
--- /dev/null
+++ b/libk3b/projects/videocd/extra/k3bphotovcd.mpg
Binary files differ
diff --git a/libk3b/projects/videocd/k3bvcddoc.cpp b/libk3b/projects/videocd/k3bvcddoc.cpp
new file mode 100644
index 0000000..462aea3
--- /dev/null
+++ b/libk3b/projects/videocd/k3bvcddoc.cpp
@@ -0,0 +1,894 @@
+/*
+*
+* $Id: k3bvcddoc.cpp 619556 2007-01-03 17:38:12Z trueg $
+* Copyright (C) 2003-2005 Christian Kvasny <chris@k3b.org>
+*
+* This file is part of the K3b project.
+* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* See the file "COPYING" for the exact licensing terms.
+*/
+
+// QT-includes
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qfile.h>
+#include <qdatastream.h>
+#include <qdom.h>
+#include <qdatetime.h>
+#include <qtimer.h>
+#include <qtextstream.h>
+
+// KDE-includes
+#include <kprocess.h>
+#include <kurl.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kio/global.h>
+#include <kdebug.h>
+#include <kstdguiitem.h>
+
+// K3b-includes
+#include "k3bvcddoc.h"
+#include "k3bvcdtrack.h"
+#include "k3bvcdjob.h"
+#include <k3bglobals.h>
+#include <k3bmsf.h>
+
+
+bool desperate_mode = false;
+bool preserve_header = false;
+bool print_progress = true;
+bool aspect_correction = false;
+byte forced_sequence_header = 0;
+
+K3bVcdDoc::K3bVcdDoc( QObject* parent )
+ : K3bDoc( parent )
+{
+ m_tracks = 0L;
+ m_vcdOptions = new K3bVcdOptions();
+
+ m_docType = VCD;
+ m_vcdType = NONE;
+
+ m_urlAddingTimer = new QTimer( this );
+ connect( m_urlAddingTimer, SIGNAL( timeout() ), this, SLOT( slotWorkUrlQueue() ) );
+
+ // FIXME: remove the newTracks() signal and replace it with the changed signal
+ connect( this, SIGNAL( newTracks() ), this, SIGNAL( changed() ) );
+ connect( this, SIGNAL( trackRemoved( K3bVcdTrack* ) ), this, SIGNAL( changed() ) );
+}
+
+K3bVcdDoc::~K3bVcdDoc()
+{
+ if ( m_tracks ) {
+ m_tracks->setAutoDelete( true );
+ delete m_tracks;
+ }
+
+ delete m_vcdOptions;
+}
+
+bool K3bVcdDoc::newDocument()
+{
+ if ( m_tracks )
+ while ( m_tracks->first() )
+ removeTrack( m_tracks->first() );
+ else
+ m_tracks = new QPtrList<K3bVcdTrack>;
+ m_tracks->setAutoDelete( false );
+
+ return K3bDoc::newDocument();
+}
+
+
+QString K3bVcdDoc::name() const
+{
+ return m_vcdOptions->volumeId();
+}
+
+
+KIO::filesize_t K3bVcdDoc::calcTotalSize() const
+{
+ unsigned long long sum = 0;
+ if ( m_tracks ) {
+ for ( K3bVcdTrack * track = m_tracks->first(); track; track = m_tracks->next() ) {
+ sum += track->size();
+ }
+ }
+ return sum;
+}
+
+KIO::filesize_t K3bVcdDoc::size() const
+{
+ // mode2 -> mode1 int(( n+2047 ) / 2048) * 2352
+ // mode1 -> mode2 int(( n+2351 ) / 2352) * 2048
+ long tracksize = long( ( calcTotalSize() + 2351 ) / 2352 ) * 2048;
+ return tracksize + ISOsize();
+}
+
+KIO::filesize_t K3bVcdDoc::ISOsize() const
+{
+ // 136000b for vcd iso reseved
+ long long iso_size = 136000;
+ if ( vcdOptions() ->CdiSupport() ) {
+ iso_size += vcdOptions() ->CDIsize();
+ }
+
+ return iso_size;
+}
+
+K3b::Msf K3bVcdDoc::length() const
+{
+ return K3b::Msf( size() / 2048 );
+}
+
+
+bool K3bVcdDoc::isImage( const KURL& url )
+{
+ QImage p;
+ return p.load( QFile::encodeName( url.path() ) );
+}
+
+void K3bVcdDoc::addUrls( const KURL::List& urls )
+{
+ // make sure we add them at the end even if urls are in the queue
+ addTracks( urls, 99 );
+}
+
+void K3bVcdDoc::addTracks( const KURL::List& urls, uint position )
+{
+ KURL::List::ConstIterator end( urls.end() );
+ for ( KURL::List::ConstIterator it = urls.begin(); it != end; ++it ) {
+ urlsToAdd.enqueue( new PrivateUrlToAdd( K3b::convertToLocalUrl(*it), position++ ) );
+ }
+
+ m_urlAddingTimer->start( 0 );
+}
+
+void K3bVcdDoc::slotWorkUrlQueue()
+{
+ if ( !urlsToAdd.isEmpty() ) {
+ PrivateUrlToAdd * item = urlsToAdd.dequeue();
+ lastAddedPosition = item->position;
+
+ // append at the end by default
+ if ( lastAddedPosition > m_tracks->count() )
+ lastAddedPosition = m_tracks->count();
+
+ if ( !item->url.isLocalFile() ) {
+ kdDebug() << item->url.path() << " no local file" << endl;
+ return ;
+ }
+
+ if ( !QFile::exists( item->url.path() ) ) {
+ kdDebug() << "(K3bVcdDoc) file not found: " << item->url.path() << endl;
+ m_notFoundFiles.append( item->url.path() );
+ return ;
+ }
+
+ if ( K3bVcdTrack * newTrack = createTrack( item->url ) )
+ addTrack( newTrack, lastAddedPosition );
+
+ delete item;
+
+ emit newTracks();
+ } else {
+ m_urlAddingTimer->stop();
+
+ emit newTracks();
+
+ // reorder pbc tracks
+ setPbcTracks();
+
+ informAboutNotFoundFiles();
+ }
+}
+
+K3bVcdTrack* K3bVcdDoc::createTrack( const KURL& url )
+{
+ char filename[ 255 ];
+ QString error_string = "";
+ strcpy( filename, QFile::encodeName( url.path() ) );
+ K3bMpegInfo* Mpeg = new K3bMpegInfo( filename );
+
+ if ( Mpeg ) {
+ int mpegVersion = Mpeg->version();
+ if ( mpegVersion > 0 ) {
+
+ if ( vcdType() == NONE && mpegVersion < 2 ) {
+ m_urlAddingTimer->stop();
+ setVcdType( vcdTypes( mpegVersion ) );
+ vcdOptions() ->setMpegVersion( mpegVersion );
+ KMessageBox::information( kapp->mainWidget(),
+ i18n( "K3b will create a %1 image from the given MPEG "
+ "files, but these files must already be in %2 "
+ "format. K3b does not yet resample MPEG files." )
+ .arg( i18n( "VCD" ) )
+ .arg( i18n( "VCD" ) ),
+ i18n( "Information" ) );
+ m_urlAddingTimer->start( 0 );
+ } else if ( vcdType() == NONE ) {
+ m_urlAddingTimer->stop();
+ vcdOptions() ->setMpegVersion( mpegVersion );
+ bool force = false;
+ force = ( KMessageBox::questionYesNo( kapp->mainWidget(),
+ i18n( "K3b will create a %1 image from the given MPEG "
+ "files, but these files must already be in %2 "
+ "format. K3b does not yet resample MPEG files." )
+ .arg( i18n( "SVCD" ) )
+ .arg( i18n( "SVCD" ) )
+ + "\n\n"
+ + i18n( "Note: Forcing MPEG2 as VCD is not supported by "
+ "some standalone DVD players." ),
+ i18n( "Information" ),
+ KStdGuiItem::ok().text(),
+ i18n( "Forcing VCD" ) ) == KMessageBox::No );
+ if ( force ) {
+ setVcdType( vcdTypes( 1 ) );
+ vcdOptions() ->setAutoDetect( false );
+ } else
+ setVcdType( vcdTypes( mpegVersion ) );
+
+ m_urlAddingTimer->start( 0 );
+ }
+
+
+ if ( numOfTracks() > 0 && vcdOptions() ->mpegVersion() != mpegVersion ) {
+ KMessageBox::error( kapp->mainWidget(), "(" + url.path() + ")\n" +
+ i18n( "You cannot mix MPEG1 and MPEG2 video files.\nPlease start a new Project for this filetype.\nResample not implemented in K3b yet." ),
+ i18n( "Wrong File Type for This Project" ) );
+
+ delete Mpeg;
+ return 0;
+ }
+
+ K3bVcdTrack* newTrack = new K3bVcdTrack( m_tracks, url.path() );
+ *( newTrack->mpeg_info ) = *( Mpeg->mpeg_info );
+
+ if ( newTrack->isSegment() && !vcdOptions()->PbcEnabled() ) {
+ KMessageBox::information( kapp->mainWidget(),
+ i18n( "PBC (Playback control) enabled.\n"
+ "Videoplayers can not reach Segments (Mpeg Still Pictures) without Playback control ." ) ,
+ i18n( "Information" ) );
+
+ vcdOptions()->setPbcEnabled( true );
+ }
+
+ // set defaults;
+ newTrack->setPlayTime( vcdOptions() ->PbcPlayTime() );
+ newTrack->setWaitTime( vcdOptions() ->PbcWaitTime() );
+ newTrack->setPbcNumKeys( vcdOptions() ->PbcNumkeysEnabled() );
+ delete Mpeg;
+
+ // debugging output
+ newTrack->PrintInfo();
+
+ return newTrack;
+ }
+ } else if ( isImage( url ) ) { // image track
+ // woking on ...
+ // for future use
+ // photoalbum starts here
+ // return here the new photoalbum track
+ }
+
+ if ( Mpeg ) {
+ error_string = Mpeg->error_string();
+ delete Mpeg;
+ }
+
+ // error (unsupported files)
+ KMessageBox::error( kapp->mainWidget(), "(" + url.path() + ")\n" +
+ i18n( "Only MPEG1 and MPEG2 video files are supported.\n" ) + error_string ,
+ i18n( "Wrong File Format" ) );
+
+
+ return 0;
+}
+
+void K3bVcdDoc::addTrack( const KURL& url, uint position )
+{
+ urlsToAdd.enqueue( new PrivateUrlToAdd( url, position ) );
+
+ m_urlAddingTimer->start( 0 );
+}
+
+
+void K3bVcdDoc::addTrack( K3bVcdTrack* track, uint position )
+{
+ if ( m_tracks->count() >= 98 ) {
+ kdDebug() << "(K3bVcdDoc) VCD Green Book only allows 98 tracks." << endl;
+ // TODO: show some messagebox
+ delete track;
+ return ;
+ }
+
+ lastAddedPosition = position;
+
+ if ( !m_tracks->insert( position, track ) ) {
+ lastAddedPosition = m_tracks->count();
+ m_tracks->insert( m_tracks->count(), track );
+ }
+
+ if ( track->isSegment() )
+ vcdOptions() ->increaseSegments( );
+ else
+ vcdOptions() ->increaseSequence( );
+
+ emit newTracks();
+
+ setModified( true );
+}
+
+
+void K3bVcdDoc::removeTrack( K3bVcdTrack* track )
+{
+ if ( !track ) {
+ return ;
+ }
+
+ // set the current item to track
+ if ( m_tracks->findRef( track ) >= 0 ) {
+ // take the current item
+ track = m_tracks->take();
+
+ // remove all pbc references to us?
+ if ( track->hasRevRef() )
+ track->delRefToUs();
+
+ // remove all pbc references from us?
+ track->delRefFromUs();
+
+ // emit signal before deleting the track to avoid crashes
+ // when the view tries to call some of the tracks' methods
+ emit trackRemoved( track );
+
+ if ( track->isSegment() )
+ vcdOptions() ->decreaseSegments( );
+ else
+ vcdOptions() ->decreaseSequence( );
+
+ delete track;
+
+ if ( numOfTracks() == 0 ) {
+ setVcdType( NONE );
+ vcdOptions() ->setAutoDetect( true );
+ }
+
+ // reorder pbc tracks
+ setPbcTracks();
+ }
+}
+
+void K3bVcdDoc::moveTrack( const K3bVcdTrack* track, const K3bVcdTrack* after )
+{
+ if ( track == after )
+ return ;
+
+ // set the current item to track
+ m_tracks->findRef( track );
+ // take the current item
+ track = m_tracks->take();
+
+ // if after == 0 findRef returnes -1
+ int pos = m_tracks->findRef( after );
+ m_tracks->insert( pos + 1, track );
+
+ // reorder pbc tracks
+ setPbcTracks();
+
+ emit changed();
+}
+
+
+QString K3bVcdDoc::typeString() const
+{
+ return "vcd";
+}
+
+
+K3bBurnJob* K3bVcdDoc::newBurnJob( K3bJobHandler* hdl, QObject* parent )
+{
+ return new K3bVcdJob( this, hdl, parent );
+}
+
+void K3bVcdDoc::informAboutNotFoundFiles()
+{
+ if ( !m_notFoundFiles.isEmpty() ) {
+ KMessageBox::informationList( view(), i18n( "Could not find the following files:" ),
+ m_notFoundFiles, i18n( "Not Found" ) );
+
+ m_notFoundFiles.clear();
+ }
+}
+
+void K3bVcdDoc::setVcdType( int type )
+{
+ m_vcdType = type;
+ switch ( type ) {
+ case 0:
+ //vcd 1.1
+ vcdOptions() ->setVcdClass( "vcd" );
+ vcdOptions() ->setVcdVersion( "1.1" );
+ break;
+ case 1:
+ //vcd 2.0
+ vcdOptions() ->setVcdClass( "vcd" );
+ vcdOptions() ->setVcdVersion( "2.0" );
+ break;
+ case 2:
+ //svcd 1.0
+ vcdOptions() ->setVcdClass( "svcd" );
+ vcdOptions() ->setVcdVersion( "1.0" );
+ break;
+ case 3:
+ //hqvcd 1.0
+ vcdOptions() ->setVcdClass( "hqvcd" );
+ vcdOptions() ->setVcdVersion( "1.0" );
+ break;
+
+ }
+}
+
+void K3bVcdDoc::setPbcTracks()
+{
+ // reorder pbc tracks
+ /*
+ if ( !vcdOptions()->PbcEnabled() )
+ return;
+ */
+
+ if ( m_tracks ) {
+ int count = m_tracks->count();
+ kdDebug() << QString( "K3bVcdDoc::setPbcTracks() - we have %1 tracks in list." ).arg( count ) << endl;
+
+ QPtrListIterator<K3bVcdTrack> iterTrack( *m_tracks );
+ K3bVcdTrack* track;
+ while ( ( track = iterTrack.current() ) != 0 ) {
+ ++iterTrack;
+ for ( int i = 0; i < K3bVcdTrack::_maxPbcTracks; i++ ) {
+ // do not change userdefined tracks
+ if ( !track->isPbcUserDefined( i ) ) {
+ if ( track->getPbcTrack( i ) )
+ track->getPbcTrack( i ) ->delFromRevRefList( track );
+
+ K3bVcdTrack* t = 0L;
+ int index = track->index();
+
+ // we are the last track
+ if ( index == count - 1 ) {
+ switch ( i ) {
+ case K3bVcdTrack::PREVIOUS:
+ // we are not alone :)
+ if ( count > 1 ) {
+ t = at( index - 1 );
+ t->addToRevRefList( track );
+ track->setPbcTrack( i, t );
+ } else {
+ track->setPbcTrack( i );
+ track->setPbcNonTrack( i, K3bVcdTrack::VIDEOEND );
+ }
+ break;
+ case K3bVcdTrack::AFTERTIMEOUT:
+ case K3bVcdTrack::NEXT:
+ track->setPbcTrack( i );
+ track->setPbcNonTrack( i, K3bVcdTrack::VIDEOEND );
+ break;
+ case K3bVcdTrack::RETURN:
+ track->setPbcTrack( i );
+ track->setPbcNonTrack( i, K3bVcdTrack::VIDEOEND );
+ break;
+ case K3bVcdTrack::DEFAULT:
+ track->setPbcTrack( i );
+ track->setPbcNonTrack( i, K3bVcdTrack::DISABLED );
+ break;
+ }
+ }
+ // we are the first track
+ else if ( index == 0 ) {
+ switch ( i ) {
+ case K3bVcdTrack::PREVIOUS:
+ track->setPbcTrack( i );
+ track->setPbcNonTrack( i, K3bVcdTrack::VIDEOEND );
+ break;
+ case K3bVcdTrack::AFTERTIMEOUT:
+ case K3bVcdTrack::NEXT:
+ t = at( index + 1 );
+ t->addToRevRefList( track );
+ track->setPbcTrack( i, t );
+ break;
+ case K3bVcdTrack::RETURN:
+ track->setPbcTrack( i );
+ track->setPbcNonTrack( i, K3bVcdTrack::VIDEOEND );
+ break;
+ case K3bVcdTrack::DEFAULT:
+ track->setPbcTrack( i );
+ track->setPbcNonTrack( i, K3bVcdTrack::DISABLED );
+ break;
+ }
+ }
+ // we are one of the other tracks and have PREVIOUS and NEXT Track
+ else {
+ switch ( i ) {
+ case K3bVcdTrack::PREVIOUS:
+ t = at( index - 1 );
+ t->addToRevRefList( track );
+ track->setPbcTrack( i, t );
+ break;
+ case K3bVcdTrack::AFTERTIMEOUT:
+ case K3bVcdTrack::NEXT:
+ t = at( index + 1 );
+ t->addToRevRefList( track );
+ track->setPbcTrack( i, t );
+ break;
+ case K3bVcdTrack::RETURN:
+ track->setPbcTrack( i );
+ track->setPbcNonTrack( i, K3bVcdTrack::VIDEOEND );
+ break;
+ case K3bVcdTrack::DEFAULT:
+ track->setPbcTrack( i );
+ track->setPbcNonTrack( i, K3bVcdTrack::DISABLED );
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+bool K3bVcdDoc::loadDocumentData( QDomElement* root )
+{
+ newDocument();
+
+ QDomNodeList nodes = root->childNodes();
+
+ if ( nodes.length() < 3 )
+ return false;
+
+ if ( nodes.item( 0 ).nodeName() != "general" )
+ return false;
+ if ( !readGeneralDocumentData( nodes.item( 0 ).toElement() ) )
+ return false;
+
+ if ( nodes.item( 1 ).nodeName() != "vcd" )
+ return false;
+
+ if ( nodes.item( 2 ).nodeName() != "contents" )
+ return false;
+
+
+ // vcd Label
+ QDomNodeList vcdNodes = nodes.item( 1 ).childNodes();
+
+ for ( uint i = 0; i < vcdNodes.count(); i++ ) {
+ QDomNode item = vcdNodes.item( i );
+ QString name = item.nodeName();
+
+ kdDebug() << QString( "(K3bVcdDoc::loadDocumentData) nodeName = '%1'" ).arg( name ) << endl;
+
+ if ( name == "volumeId" )
+ vcdOptions() ->setVolumeId( item.toElement().text() );
+ else if ( name == "albumId" )
+ vcdOptions() ->setAlbumId( item.toElement().text() );
+ else if ( name == "volumeSetId" )
+ vcdOptions() ->setVolumeSetId( item.toElement().text() );
+ else if ( name == "preparer" )
+ vcdOptions() ->setPreparer( item.toElement().text() );
+ else if ( name == "publisher" )
+ vcdOptions() ->setPublisher( item.toElement().text() );
+ else if ( name == "vcdType" )
+ setVcdType( vcdTypes( item.toElement().text().toInt() ) );
+ else if ( name == "mpegVersion" )
+ vcdOptions() ->setMpegVersion( item.toElement().text().toInt() );
+ else if ( name == "PreGapLeadout" )
+ vcdOptions() ->setPreGapLeadout( item.toElement().text().toInt() );
+ else if ( name == "PreGapTrack" )
+ vcdOptions() ->setPreGapTrack( item.toElement().text().toInt() );
+ else if ( name == "FrontMarginTrack" )
+ vcdOptions() ->setFrontMarginTrack( item.toElement().text().toInt() );
+ else if ( name == "RearMarginTrack" )
+ vcdOptions() ->setRearMarginTrack( item.toElement().text().toInt() );
+ else if ( name == "FrontMarginTrackSVCD" )
+ vcdOptions() ->setFrontMarginTrackSVCD( item.toElement().text().toInt() );
+ else if ( name == "RearMarginTrackSVCD" )
+ vcdOptions() ->setRearMarginTrackSVCD( item.toElement().text().toInt() );
+ else if ( name == "volumeCount" )
+ vcdOptions() ->setVolumeCount( item.toElement().text().toInt() );
+ else if ( name == "volumeNumber" )
+ vcdOptions() ->setVolumeNumber( item.toElement().text().toInt() );
+ else if ( name == "AutoDetect" )
+ vcdOptions() ->setAutoDetect( item.toElement().text().toInt() );
+ else if ( name == "CdiSupport" )
+ vcdOptions() ->setCdiSupport( item.toElement().text().toInt() );
+ else if ( name == "NonCompliantMode" )
+ vcdOptions() ->setNonCompliantMode( item.toElement().text().toInt() );
+ else if ( name == "Sector2336" )
+ vcdOptions() ->setSector2336( item.toElement().text().toInt() );
+ else if ( name == "UpdateScanOffsets" )
+ vcdOptions() ->setUpdateScanOffsets( item.toElement().text().toInt() );
+ else if ( name == "RelaxedAps" )
+ vcdOptions() ->setRelaxedAps( item.toElement().text().toInt() );
+ else if ( name == "UseGaps" )
+ vcdOptions() ->setUseGaps( item.toElement().text().toInt() );
+ else if ( name == "PbcEnabled" )
+ vcdOptions() ->setPbcEnabled( item.toElement().text().toInt() );
+ else if ( name == "SegmentFolder" )
+ vcdOptions() ->setSegmentFolder( item.toElement().text().toInt() );
+ else if ( name == "Restriction" )
+ vcdOptions() ->setRestriction( item.toElement().text().toInt() );
+ }
+
+ // vcd Tracks
+ QDomNodeList trackNodes = nodes.item( 2 ).childNodes();
+
+ for ( uint i = 0; i < trackNodes.length(); i++ ) {
+
+ // check if url is available
+ QDomElement trackElem = trackNodes.item( i ).toElement();
+ QString url = trackElem.attributeNode( "url" ).value();
+ if ( !QFile::exists( url ) )
+ m_notFoundFiles.append( url );
+ else {
+ KURL k;
+ k.setPath( url );
+ if ( K3bVcdTrack * track = createTrack( k ) ) {
+ track ->setPlayTime( trackElem.attribute( "playtime", "1" ).toInt() );
+ track ->setWaitTime( trackElem.attribute( "waittime", "2" ).toInt() );
+ track ->setReactivity( trackElem.attribute( "reactivity", "0" ).toInt() );
+ track -> setPbcNumKeys( ( trackElem.attribute( "numkeys", "yes" ).contains( "yes" ) ) ? true : false );
+ track -> setPbcNumKeysUserdefined( ( trackElem.attribute( "userdefinednumkeys", "no" ).contains( "yes" ) ) ? true : false );
+
+ addTrack( track, m_tracks->count() );
+ }
+ }
+ }
+
+ emit newTracks();
+
+ // do not add saved pbcTrack links when one ore more files missing.
+ // TODO: add info message to informAboutNotFoundFiles();
+ if ( m_notFoundFiles.isEmpty() ) {
+ int type;
+ int val;
+ bool pbctrack;
+ for ( uint trackId = 0; trackId < trackNodes.length(); trackId++ ) {
+ QDomElement trackElem = trackNodes.item( trackId ).toElement();
+ QDomNodeList trackNodes = trackElem.childNodes();
+ for ( uint i = 0; i < trackNodes.length(); i++ ) {
+ QDomElement trackElem = trackNodes.item( i ).toElement();
+ QString name = trackElem.tagName();
+ if ( name.contains( "pbc" ) ) {
+ if ( trackElem.hasAttribute ( "type" ) ) {
+ type = trackElem.attribute ( "type" ).toInt();
+ if ( trackElem.hasAttribute ( "pbctrack" ) ) {
+ pbctrack = ( trackElem.attribute ( "pbctrack" ) == "yes" );
+ if ( trackElem.hasAttribute ( "val" ) ) {
+ val = trackElem.attribute ( "val" ).toInt();
+ K3bVcdTrack* track = m_tracks->at( trackId );
+ K3bVcdTrack* pbcTrack = m_tracks->at( val );
+ if ( pbctrack ) {
+ pbcTrack->addToRevRefList( track );
+ track->setPbcTrack( type, pbcTrack );
+ track->setUserDefined( type, true );
+ } else {
+ track->setPbcTrack( type );
+ track->setPbcNonTrack( type, val );
+ track->setUserDefined( type, true );
+ }
+ }
+ }
+ }
+ } else if ( name.contains( "numkeys" ) ) {
+ if ( trackElem.hasAttribute ( "key" ) ) {
+ int key = trackElem.attribute ( "key" ).toInt();
+ if ( trackElem.hasAttribute ( "val" ) ) {
+ int val = trackElem.attribute ( "val" ).toInt() - 1;
+ K3bVcdTrack* track = m_tracks->at( trackId );
+ if ( val >= 0 ) {
+ K3bVcdTrack * numkeyTrack = m_tracks->at( val );
+ track->setDefinedNumKey( key, numkeyTrack );
+ } else {
+ track->setDefinedNumKey( key, 0L );
+ }
+ }
+ }
+ }
+
+ }
+
+ }
+ setPbcTracks();
+ setModified( false );
+ }
+
+ informAboutNotFoundFiles();
+ return true;
+}
+
+
+
+bool K3bVcdDoc::saveDocumentData( QDomElement * docElem )
+{
+ QDomDocument doc = docElem->ownerDocument();
+ saveGeneralDocumentData( docElem );
+
+ // save Vcd Label
+ QDomElement vcdMain = doc.createElement( "vcd" );
+
+ QDomElement vcdElem = doc.createElement( "volumeId" );
+ vcdElem.appendChild( doc.createTextNode( vcdOptions() ->volumeId() ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "albumId" );
+ vcdElem.appendChild( doc.createTextNode( vcdOptions() ->albumId() ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "volumeSetId" );
+ vcdElem.appendChild( doc.createTextNode( vcdOptions() ->volumeSetId() ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "preparer" );
+ vcdElem.appendChild( doc.createTextNode( vcdOptions() ->preparer() ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "publisher" );
+ vcdElem.appendChild( doc.createTextNode( vcdOptions() ->publisher() ) );
+ vcdMain.appendChild( vcdElem );
+
+ // applicationId()
+ // systemId()
+
+ vcdElem = doc.createElement( "vcdType" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdType() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "mpegVersion" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->mpegVersion() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "PreGapLeadout" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->PreGapLeadout() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "PreGapTrack" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->PreGapTrack() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "FrontMarginTrack" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->FrontMarginTrack() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "RearMarginTrack" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->RearMarginTrack() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "FrontMarginTrackSVCD" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->FrontMarginTrackSVCD() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "RearMarginTrackSVCD" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->RearMarginTrackSVCD() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "volumeCount" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->volumeCount() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "volumeNumber" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->volumeNumber() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "AutoDetect" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->AutoDetect() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "CdiSupport" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->CdiSupport() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "NonCompliantMode" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->NonCompliantMode() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "Sector2336" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->Sector2336() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "UpdateScanOffsets" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->UpdateScanOffsets() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "RelaxedAps" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->RelaxedAps() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "UseGaps" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->UseGaps() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "PbcEnabled" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->PbcEnabled() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "SegmentFolder" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->SegmentFolder() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ vcdElem = doc.createElement( "Restriction" );
+ vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->Restriction() ) ) );
+ vcdMain.appendChild( vcdElem );
+
+ docElem->appendChild( vcdMain );
+
+ // save the tracks
+ // -------------------------------------------------------------
+ QDomElement contentsElem = doc.createElement( "contents" );
+
+ QPtrListIterator<K3bVcdTrack> iterTrack( *m_tracks );
+ K3bVcdTrack* track;
+
+ while ( ( track = iterTrack.current() ) != 0 ) {
+ ++iterTrack;
+
+ QDomElement trackElem = doc.createElement( "track" );
+ trackElem.setAttribute( "url", KIO::decodeFileName( track->absPath() ) );
+ trackElem.setAttribute( "playtime", track->getPlayTime() );
+ trackElem.setAttribute( "waittime", track->getWaitTime() );
+ trackElem.setAttribute( "reactivity", track->Reactivity() );
+ trackElem.setAttribute( "numkeys", ( track->PbcNumKeys() ) ? "yes" : "no" );
+ trackElem.setAttribute( "userdefinednumkeys", ( track->PbcNumKeysUserdefined() ) ? "yes" : "no" );
+
+ for ( int i = 0;
+ i < K3bVcdTrack::_maxPbcTracks;
+ i++ ) {
+ if ( track->isPbcUserDefined( i ) ) {
+ // save pbcTracks
+ QDomElement pbcElem = doc.createElement( "pbc" );
+ pbcElem.setAttribute( "type", i );
+ if ( track->getPbcTrack( i ) ) {
+ pbcElem.setAttribute( "pbctrack", "yes" );
+ pbcElem.setAttribute( "val", track->getPbcTrack( i ) ->index() );
+ } else {
+ pbcElem.setAttribute( "pbctrack", "no" );
+ pbcElem.setAttribute( "val", track->getNonPbcTrack( i ) );
+ }
+ trackElem.appendChild( pbcElem );
+ }
+ }
+ QMap<int, K3bVcdTrack*> numKeyMap = track->DefinedNumKey();
+ QMap<int, K3bVcdTrack*>::const_iterator trackIt;
+
+ for ( trackIt = numKeyMap.begin();
+ trackIt != numKeyMap.end();
+ ++trackIt ) {
+ QDomElement numElem = doc.createElement( "numkeys" );
+ if ( trackIt.data() ) {
+ numElem.setAttribute( "key", trackIt.key() );
+ numElem.setAttribute( "val", trackIt.data() ->index() + 1 );
+ } else {
+ numElem.setAttribute( "key", trackIt.key() );
+ numElem.setAttribute( "val", 0 );
+ }
+ trackElem.appendChild( numElem );
+ }
+
+ contentsElem.appendChild( trackElem );
+ }
+ // -------------------------------------------------------------
+
+ docElem->appendChild( contentsElem );
+
+ return true;
+}
+
+#include "k3bvcddoc.moc"
diff --git a/libk3b/projects/videocd/k3bvcddoc.h b/libk3b/projects/videocd/k3bvcddoc.h
new file mode 100644
index 0000000..8b10837
--- /dev/null
+++ b/libk3b/projects/videocd/k3bvcddoc.h
@@ -0,0 +1,192 @@
+/*
+*
+* $Id: k3bvcddoc.h 619556 2007-01-03 17:38:12Z trueg $
+* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org>
+*
+* This file is part of the K3b project.
+* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* See the file "COPYING" for the exact licensing terms.
+*/
+
+#ifndef K3BVCDDOC_H
+#define K3BVCDDOC_H
+
+// Qt Includes
+#include <qptrqueue.h>
+#include <qfile.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qdatetime.h>
+#include <qtextstream.h>
+#include <qimage.h>
+
+// Kde Includes
+#include <kurl.h>
+
+// K3b Includes
+#include "k3bvcdoptions.h"
+#include "mpeginfo/k3bmpeginfo.h"
+#include <k3bdoc.h>
+#include "k3b_export.h"
+class K3bApp;
+class K3bVcdTrack;
+class K3bVcdJob;
+//class K3bView;
+class QWidget;
+class QTimer;
+class QDomDocument;
+class QDomElement;
+class KConfig;
+
+
+
+class LIBK3B_EXPORT K3bVcdDoc : public K3bDoc
+{
+ Q_OBJECT
+
+ public:
+ K3bVcdDoc( QObject* );
+ ~K3bVcdDoc();
+
+ int type() const { return VCD; }
+
+ QString name() const;
+
+ enum vcdTypes { VCD11, VCD20, SVCD10, HQVCD, NONE};
+
+ bool newDocument();
+ int numOfTracks() const
+ {
+ return m_tracks->count();
+ }
+
+ const QString& vcdImage() const
+ {
+ return m_vcdImage;
+ }
+ void setVcdImage( const QString& s )
+ {
+ m_vcdImage = s;
+ }
+
+ K3bVcdTrack* first()
+ {
+ return m_tracks->first();
+ }
+ K3bVcdTrack* current() const
+ {
+ return m_tracks->current();
+ }
+ K3bVcdTrack* next()
+ {
+ return m_tracks->next();
+ }
+ K3bVcdTrack* prev()
+ {
+ return m_tracks->prev();
+ }
+ K3bVcdTrack* at( uint i )
+ {
+ return m_tracks->at( i );
+ }
+ K3bVcdTrack* take( uint i )
+ {
+ return m_tracks->take( i );
+ }
+
+ const QPtrList<K3bVcdTrack>* tracks() const
+ {
+ return m_tracks;
+ }
+
+ /** get the current size of the project */
+ KIO::filesize_t size() const;
+ K3b::Msf length() const;
+
+ K3bBurnJob* newBurnJob( K3bJobHandler* hdl, QObject* parent );
+ K3bVcdOptions* vcdOptions() const
+ {
+ return m_vcdOptions;
+ }
+
+ int vcdType() const
+ {
+ return m_vcdType;
+ }
+ void setVcdType( int type );
+ void setPbcTracks();
+
+ public slots:
+ /**
+ * will test the file and add it to the project.
+ * connect to at least result() to know when
+ * the process is finished and check error()
+ * to know about the result.
+ **/
+ void addUrls( const KURL::List& );
+ void addTrack( const KURL&, uint );
+ void addTracks( const KURL::List&, uint );
+ /** adds a track without any testing */
+ void addTrack( K3bVcdTrack* track, uint position = 0 );
+
+ // --- TODO: this should read: removeTrack( K3bVcdTrack* )
+ void removeTrack( K3bVcdTrack* );
+ void moveTrack( const K3bVcdTrack* track, const K3bVcdTrack* after );
+
+ protected slots:
+ /** processes queue "urlsToAdd" **/
+ void slotWorkUrlQueue();
+
+ signals:
+ void newTracks();
+
+ void trackRemoved( K3bVcdTrack* );
+
+ protected:
+ /** reimplemented from K3bDoc */
+ bool loadDocumentData( QDomElement* root );
+ /** reimplemented from K3bDoc */
+ bool saveDocumentData( QDomElement* );
+
+ QString typeString() const;
+
+ private:
+ K3bVcdTrack* createTrack( const KURL& url );
+ void informAboutNotFoundFiles();
+
+ QStringList m_notFoundFiles;
+ QString m_vcdImage;
+
+ class PrivateUrlToAdd
+ {
+ public:
+ PrivateUrlToAdd( const KURL& u, int _pos )
+ : url( u ), position( _pos )
+ {}
+ KURL url;
+ int position;
+ };
+
+ /** Holds all the urls that have to be added to the list of tracks. **/
+ QPtrQueue<PrivateUrlToAdd> urlsToAdd;
+ QTimer* m_urlAddingTimer;
+
+ QPtrList<K3bVcdTrack>* m_tracks;
+ KIO::filesize_t calcTotalSize() const;
+ KIO::filesize_t ISOsize() const;
+
+ bool isImage( const KURL& url );
+
+ K3bVcdTrack* m_lastAddedTrack;
+ K3bVcdOptions* m_vcdOptions;
+
+ int m_vcdType;
+ uint lastAddedPosition;
+};
+
+#endif
diff --git a/libk3b/projects/videocd/k3bvcdjob.cpp b/libk3b/projects/videocd/k3bvcdjob.cpp
new file mode 100644
index 0000000..a1b347a
--- /dev/null
+++ b/libk3b/projects/videocd/k3bvcdjob.cpp
@@ -0,0 +1,567 @@
+/*
+*
+* $Id: k3bvcdjob.cpp 619556 2007-01-03 17:38:12Z trueg $
+* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org>
+*
+* This file is part of the K3b project.
+* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* See the file "COPYING" for the exact licensing terms.
+*/
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <kurl.h>
+#include <ktempfile.h>
+#include <kio/global.h>
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qfile.h>
+#include <qtimer.h>
+#include <kdebug.h>
+#include <qregexp.h>
+#include <qdom.h>
+
+#include "k3bvcdjob.h"
+
+// K3b Includes
+#include "k3bvcddoc.h"
+#include "k3bvcdtrack.h"
+#include "k3bvcdxmlview.h"
+#include <k3bcore.h>
+#include <k3bdoc.h>
+#include <k3bprocess.h>
+#include <k3bdevice.h>
+#include <k3bexternalbinmanager.h>
+#include <k3bglobals.h>
+#include <k3bcdrecordwriter.h>
+#include <k3bcdrdaowriter.h>
+
+K3bVcdJob::K3bVcdJob( K3bVcdDoc* doc, K3bJobHandler* jh, QObject* parent, const char* name )
+ : K3bBurnJob( jh, parent, name )
+{
+ m_doc = doc;
+ m_doc->setCopies( m_doc->dummy() || m_doc->onlyCreateImages() ? 1 : m_doc->copies() );
+ m_process = 0;
+ m_currentWrittenTrackNumber = 0;
+ m_bytesFinishedTracks = 0;
+ m_writerJob = 0;
+ // m_createimageonlypercent = 33.3;
+ m_createimageonlypercent = 100 / ( m_doc->copies() + 2 );
+ m_currentcopy = 1;
+ m_imageFinished = false;
+}
+
+
+K3bVcdJob::~K3bVcdJob()
+{
+ delete m_process;
+
+ if ( m_writerJob )
+ delete m_writerJob;
+}
+
+
+K3bDoc* K3bVcdJob::doc() const
+{
+ return m_doc;
+}
+
+
+K3bDevice::Device* K3bVcdJob::writer() const
+{
+ if( doc()->onlyCreateImages() )
+ return 0;
+ else
+ return doc() ->burner();
+}
+
+void K3bVcdJob::cancel()
+{
+ cancelAll();
+
+ emit canceled();
+ jobFinished( false );
+}
+
+
+void K3bVcdJob::cancelAll()
+{
+ m_canceled = true;
+
+ if ( m_writerJob )
+ m_writerJob->cancel();
+
+ if ( m_process->isRunning() ) {
+ m_process->disconnect( this );
+ m_process->kill();
+ }
+
+ // remove bin-file if it is unfinished or the user selected to remove image
+ if ( QFile::exists( m_doc->vcdImage() ) ) {
+ if ( !m_doc->onTheFly() && m_doc->removeImages() || !m_imageFinished ) {
+ emit infoMessage( i18n( "Removing Binary file %1" ).arg( m_doc->vcdImage() ), K3bJob::SUCCESS );
+ QFile::remove
+ ( m_doc->vcdImage() );
+ m_doc->setVcdImage( "" );
+ }
+ }
+
+ // remove cue-file if it is unfinished or the user selected to remove image
+ if ( QFile::exists( m_cueFile ) ) {
+ if ( !m_doc->onTheFly() && m_doc->removeImages() || !m_imageFinished ) {
+ emit infoMessage( i18n( "Removing Cue file %1" ).arg( m_cueFile ), K3bJob::SUCCESS );
+ QFile::remove
+ ( m_cueFile );
+ m_cueFile = "";
+ }
+ }
+}
+
+
+void K3bVcdJob::start()
+{
+ kdDebug() << "(K3bVcdJob) starting job" << endl;
+
+ jobStarted();
+ emit burning( false );
+ m_canceled = false;
+
+ int pos = QString( m_doc->vcdImage() ).find( ".bin", QString( m_doc->vcdImage() ).length() - 4 );
+ if ( pos > 0 ) {
+ m_cueFile = m_doc->vcdImage().left( pos ) + ".cue";
+ } else {
+ m_cueFile = m_doc->vcdImage() + ".cue";
+ m_doc->setVcdImage( m_doc->vcdImage() + ".bin" );
+ }
+
+ if ( vcdDoc() ->onlyCreateImages() )
+ m_createimageonlypercent = 50.0;
+
+ // vcdxGen();
+ xmlGen();
+}
+
+void K3bVcdJob::xmlGen()
+{
+
+ KTempFile tempF;
+ m_xmlFile = tempF.name();
+ tempF.unlink();
+
+ K3bVcdXmlView xmlView( m_doc );
+
+ if ( !xmlView.write( m_xmlFile ) ) {
+ kdDebug() << "(K3bVcdJob) could not write xmlfile." << endl;
+ emit infoMessage( i18n( "Could not write correct XML-file." ), K3bJob::ERROR );
+ cancelAll();
+ jobFinished( false );
+ }
+
+ // emit infoMessage( i18n( "XML-file successfully created" ), K3bJob::SUCCESS );
+ emit debuggingOutput( "K3bVcdXml:", xmlView.xmlString() );
+
+ vcdxBuild();
+
+}
+
+void K3bVcdJob::vcdxBuild()
+{
+ emit newTask( i18n( "Creating image files" ) );
+
+ m_stage = stageUnknown;
+ firstTrack = true;
+ delete m_process;
+ m_process = new K3bProcess();
+
+ emit infoMessage( i18n( "Creating Cue/Bin files ..." ), K3bJob::INFO );
+ const K3bExternalBin* bin = k3bcore ->externalBinManager() ->binObject( "vcdxbuild" );
+ if ( !bin ) {
+ kdDebug() << "(K3bVcdJob) could not find vcdxbuild executable" << endl;
+ emit infoMessage( i18n( "Could not find %1 executable." ).arg( "vcdxbuild" ), K3bJob::ERROR );
+ emit infoMessage( i18n( "To create VideoCDs you must install VcdImager Version %1." ).arg( ">= 0.7.12" ), K3bJob::INFO );
+ emit infoMessage( i18n( "You can find this on your distribution disks or download it from http://www.vcdimager.org" ), K3bJob::INFO );
+ cancelAll();
+ jobFinished( false );
+ return ;
+ }
+
+ if ( bin->version < K3bVersion( "0.7.12" ) ) {
+ kdDebug() << "(K3bVcdJob) vcdxbuild executable too old!" << endl;
+ emit infoMessage( i18n( "%1 executable too old: need version %2 or greater." ).arg( "Vcdxbuild" ).arg( "0.7.12" ), K3bJob::ERROR );
+ emit infoMessage( i18n( "You can find this on your distribution disks or download it from http://www.vcdimager.org" ), K3bJob::INFO );
+ cancelAll();
+ jobFinished( false );
+ return ;
+ }
+
+ if ( !bin->copyright.isEmpty() )
+ emit infoMessage( i18n( "Using %1 %2 - Copyright (C) %3" ).arg( bin->name() ).arg( bin->version ).arg( bin->copyright ), INFO );
+
+ *m_process << bin;
+
+ // additional user parameters from config
+ const QStringList& params = k3bcore->externalBinManager() ->program( "vcdxbuild" ) ->userParameters();
+ for ( QStringList::const_iterator it = params.begin(); it != params.end(); ++it )
+ *m_process << *it;
+
+
+ if ( vcdDoc() ->vcdOptions() ->Sector2336() ) {
+ kdDebug() << "(K3bVcdJob) Write 2336 Sectors = on" << endl;
+ *m_process << "--sector-2336";
+ }
+
+ *m_process << "--progress" << "--gui";
+
+ *m_process << QString( "--cue-file=%1" ).arg( m_cueFile );
+
+ *m_process << QString( "--bin-file=%1" ).arg( m_doc->vcdImage() );
+
+ *m_process << QString( "%1" ).arg( QFile::encodeName( m_xmlFile ) );
+
+ connect( m_process, SIGNAL( receivedStderr( KProcess*, char*, int ) ),
+ this, SLOT( slotParseVcdxBuildOutput( KProcess*, char*, int ) ) );
+ connect( m_process, SIGNAL( receivedStdout( KProcess*, char*, int ) ),
+ this, SLOT( slotParseVcdxBuildOutput( KProcess*, char*, int ) ) );
+ connect( m_process, SIGNAL( processExited( KProcess* ) ),
+ this, SLOT( slotVcdxBuildFinished() ) );
+
+ // vcdxbuild commandline parameters
+ kdDebug() << "***** vcdxbuild parameters:" << endl;
+ ;
+ const QValueList<QCString>& args = m_process->args();
+ QString s;
+ for ( QValueList<QCString>::const_iterator it = args.begin(); it != args.end(); ++it ) {
+ s += *it + " ";
+ }
+ kdDebug() << s << flush << endl;
+ emit debuggingOutput( "vcdxbuild command:", s );
+
+ if ( !m_process->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) {
+ kdDebug() << "(K3bVcdJob) could not start vcdxbuild" << endl;
+ emit infoMessage( i18n( "Could not start %1." ).arg( "vcdxbuild" ), K3bJob::ERROR );
+ cancelAll();
+ jobFinished( false );
+ }
+}
+
+void K3bVcdJob::slotParseVcdxBuildOutput( KProcess*, char* output, int len )
+{
+ QString buffer = QString::fromLocal8Bit( output, len );
+
+ // split to lines
+ QStringList lines = QStringList::split( "\n", buffer );
+
+ QDomDocument xml_doc;
+ QDomElement xml_root;
+
+ // do every line
+ for ( QStringList::Iterator str = lines.begin(); str != lines.end(); ++str ) {
+ *str = ( *str ).stripWhiteSpace();
+
+ emit debuggingOutput( "vcdxbuild", *str );
+
+ xml_doc.setContent( QString( "<?xml version='1.0'?><vcdxbuild>" ) + *str + "</vcdxbuild>" );
+
+ xml_root = xml_doc.documentElement();
+
+ // There should be only one... but ...
+ for ( QDomNode node = xml_root.firstChild(); !node.isNull(); node = node.nextSibling() ) {
+ QDomElement el = node.toElement();
+ if ( el.isNull() )
+ continue;
+
+ const QString tagName = el.tagName().lower();
+
+ if ( tagName == "progress" ) {
+ const QString oper = el.attribute( "operation" ).lower();
+ const unsigned long long pos = el.attribute( "position" ).toLong();
+ const long long size = el.attribute( "size" ).toLong();
+
+ if ( oper == "scan" ) {
+ // Scan Video Files
+ if ( m_stage == stageUnknown || pos < m_bytesFinished ) {
+ const uint index = el.attribute( "id" ).replace( QRegExp( "sequence-" ), "" ).toUInt();
+
+ m_currentWrittenTrack = m_doc->at( m_currentWrittenTrackNumber );
+ emit newSubTask( i18n( "Scanning video file %1 of %2 (%3)" ).arg( index + 1 ).arg( doc() ->numOfTracks() ).arg( m_currentWrittenTrack->fileName() ) );
+ m_bytesFinished = 0;
+
+ if ( !firstTrack ) {
+ m_bytesFinishedTracks += m_doc->at( m_currentWrittenTrackNumber ) ->size();
+ m_currentWrittenTrackNumber++;
+ } else
+ firstTrack = false;
+ }
+ emit subPercent( ( int ) ( 100.0 * ( double ) pos / ( double ) size ) );
+ emit processedSubSize( pos / 1024 / 1024, size / 1024 / 1024 );
+
+ // this is the first of three processes.
+ double relOverallWritten = ( ( double ) m_bytesFinishedTracks + ( double ) pos ) / ( double ) doc() ->size();
+ emit percent( ( int ) ( m_createimageonlypercent * relOverallWritten ) );
+
+ m_bytesFinished = pos;
+ m_stage = stageScan;
+
+ } else if ( oper == "write" ) {
+ emit subPercent( ( int ) ( 100.0 * ( double ) pos / ( double ) size ) );
+ emit processedSubSize( ( pos * 2048 ) / 1024 / 1024, ( size * 2048 ) / 1024 / 1024 );
+ emit percent( ( int ) ( m_createimageonlypercent + ( m_createimageonlypercent * ( double ) pos / ( double ) size ) ) );
+
+ m_stage = stageWrite;
+ } else {
+ return ;
+ }
+ } else if ( tagName == "log" ) {
+ QDomText tel = el.firstChild().toText();
+ const QString level = el.attribute( "level" ).lower();
+ if ( tel.isText() ) {
+ const QString text = tel.data();
+ if ( m_stage == stageWrite && level == "information" )
+ kdDebug() << QString( "(K3bVcdJob) VcdxBuild information, %1" ).arg( text ) << endl;
+ if ( ( text ).startsWith( "writing track" ) )
+ emit newSubTask( i18n( "Creating Image for track %1" ).arg( ( text ).mid( 14 ) ) );
+ else {
+ if ( level != "error" ) {
+ kdDebug() << QString( "(K3bVcdJob) vcdxbuild warning, %1" ).arg( text ) << endl;
+ parseInformation( text );
+ } else {
+ kdDebug() << QString( "(K3bVcdJob) vcdxbuild error, %1" ).arg( text ) << endl;
+ emit infoMessage( text, K3bJob::ERROR );
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void K3bVcdJob::slotVcdxBuildFinished()
+{
+ if ( m_process->normalExit() ) {
+ // TODO: check the process' exitStatus()
+ switch ( m_process->exitStatus() ) {
+ case 0:
+ emit infoMessage( i18n( "Cue/Bin files successfully created." ), K3bJob::SUCCESS );
+ m_imageFinished = true;
+ break;
+ default:
+ emit infoMessage( i18n( "%1 returned an unknown error (code %2)." ).arg( "vcdxbuild" ).arg( m_process->exitStatus() ),
+ K3bJob::ERROR );
+ emit infoMessage( i18n( "Please send me an email with the last output." ), K3bJob::ERROR );
+ cancelAll();
+ jobFinished( false );
+ return ;
+ }
+ } else {
+ emit infoMessage( i18n( "%1 did not exit cleanly." ).arg( "Vcdxbuild" ), K3bJob::ERROR );
+ cancelAll();
+ jobFinished( false );
+ return ;
+ }
+
+ //remove xml-file
+ if ( QFile::exists( m_xmlFile ) )
+ QFile::remove
+ ( m_xmlFile );
+
+ kdDebug() << QString( "(K3bVcdJob) create only image: %1" ).arg( vcdDoc() ->onlyCreateImages() ) << endl;
+ if ( !vcdDoc() ->onlyCreateImages() )
+ startWriterjob();
+ else
+ jobFinished( true );
+}
+
+void K3bVcdJob::startWriterjob()
+{
+ kdDebug() << QString( "(K3bVcdJob) writing copy %1 of %2" ).arg( m_currentcopy ).arg( m_doc->copies() ) << endl;
+ if ( prepareWriterJob() ) {
+ if ( waitForMedia( m_doc->burner() ) < 0 ) {
+ cancel();
+ return ;
+ }
+ // just to be sure we did not get canceled during the async discWaiting
+ if ( m_canceled )
+ return ;
+
+ if ( m_doc->copies() > 1 )
+ emit newTask( i18n( "Writing Copy %1 of %2" ).arg( m_currentcopy ).arg( m_doc->copies() ) );
+
+ emit burning( true );
+ m_writerJob->start();
+ }
+}
+
+bool K3bVcdJob::prepareWriterJob()
+{
+ if ( m_writerJob )
+ delete m_writerJob;
+
+ const K3bExternalBin* cdrecordBin = k3bcore->externalBinManager() ->binObject( "cdrecord" );
+ if ( writingApp() == K3b::DEFAULT && cdrecordBin->hasFeature( "cuefile" ) && m_doc->burner() ->dao() )
+ setWritingApp( K3b::CDRECORD );
+
+ if ( writingApp() == K3b::CDRDAO || writingApp() == K3b::DEFAULT ) {
+ K3bCdrdaoWriter * writer = new K3bCdrdaoWriter( m_doc->burner(), this, this );
+ // create cdrdao job
+ writer->setCommand( K3bCdrdaoWriter::WRITE );
+ writer->setSimulate( m_doc->dummy() );
+ writer->setBurnSpeed( m_doc->speed() );
+
+ writer->setTocFile( m_cueFile );
+
+ m_writerJob = writer;
+
+ } else if ( writingApp() == K3b::CDRECORD ) {
+ K3bCdrecordWriter * writer = new K3bCdrecordWriter( m_doc->burner(), this, this );
+ // create cdrecord job
+
+ writer->setSimulate( m_doc->dummy() );
+ writer->setBurnSpeed( m_doc->speed() );
+ writer->setDao( true );
+ writer->setCueFile( m_cueFile );
+
+ m_writerJob = writer;
+
+ }
+
+ connect( m_writerJob, SIGNAL( infoMessage( const QString&, int ) ), this, SIGNAL( infoMessage( const QString&, int ) ) );
+ connect( m_writerJob, SIGNAL( percent( int ) ), this, SLOT( slotWriterJobPercent( int ) ) );
+ connect( m_writerJob, SIGNAL( processedSize( int, int ) ), this, SLOT( slotProcessedSize( int, int ) ) );
+ connect( m_writerJob, SIGNAL( subPercent( int ) ), this, SIGNAL( subPercent( int ) ) );
+ connect( m_writerJob, SIGNAL( processedSubSize( int, int ) ), this, SIGNAL( processedSubSize( int, int ) ) );
+ connect( m_writerJob, SIGNAL( nextTrack( int, int ) ), this, SLOT( slotWriterNextTrack( int, int ) ) );
+ connect( m_writerJob, SIGNAL( buffer( int ) ), this, SIGNAL( bufferStatus( int ) ) );
+ connect( m_writerJob, SIGNAL( deviceBuffer( int ) ), this, SIGNAL( deviceBuffer( int ) ) );
+ connect( m_writerJob, SIGNAL( writeSpeed( int, int ) ), this, SIGNAL( writeSpeed( int, int ) ) );
+ connect( m_writerJob, SIGNAL( finished( bool ) ), this, SLOT( slotWriterJobFinished( bool ) ) );
+ connect( m_writerJob, SIGNAL( newTask( const QString& ) ), this, SIGNAL( newTask( const QString& ) ) );
+ connect( m_writerJob, SIGNAL( newSubTask( const QString& ) ), this, SIGNAL( newSubTask( const QString& ) ) );
+ connect( m_writerJob, SIGNAL( debuggingOutput( const QString&, const QString& ) ), this, SIGNAL( debuggingOutput( const QString&, const QString& ) ) );
+
+ return true;
+}
+
+void K3bVcdJob::slotWriterJobPercent( int p )
+{
+ emit percent( ( int ) ( ( m_createimageonlypercent * ( m_currentcopy + 1 ) ) + p / ( m_doc->copies() + 2 ) ) );
+}
+
+void K3bVcdJob::slotProcessedSize( int cs, int ts )
+{
+ emit processedSize( cs + ( ts * ( m_currentcopy - 1 ) ) , ts * m_doc->copies() );
+}
+
+void K3bVcdJob::slotWriterNextTrack( int t, int tt )
+{
+ emit newSubTask( i18n( "Writing Track %1 of %2" ).arg( t ).arg( tt ) );
+}
+
+void K3bVcdJob::slotWriterJobFinished( bool success )
+{
+ if ( m_canceled )
+ return ;
+
+ if ( m_currentcopy >= m_doc->copies() ) {
+ // remove bin-file if it is unfinished or the user selected to remove image
+ if ( QFile::exists( m_doc->vcdImage() ) ) {
+ if ( !m_doc->onTheFly() && m_doc->removeImages() || !m_imageFinished ) {
+ emit infoMessage( i18n( "Removing Binary file %1" ).arg( m_doc->vcdImage() ), K3bJob::SUCCESS );
+ QFile::remove
+ ( m_doc->vcdImage() );
+ m_doc->setVcdImage( "" );
+ }
+ }
+
+ // remove cue-file if it is unfinished or the user selected to remove image
+ if ( QFile::exists( m_cueFile ) ) {
+ if ( !m_doc->onTheFly() && m_doc->removeImages() || !m_imageFinished ) {
+ emit infoMessage( i18n( "Removing Cue file %1" ).arg( m_cueFile ), K3bJob::SUCCESS );
+ QFile::remove
+ ( m_cueFile );
+ m_cueFile = "";
+ }
+ }
+ }
+
+ if ( success ) {
+ // allright
+ // the writerJob should have emited the "simulation/writing successful" signal
+ if ( m_currentcopy >= m_doc->copies() ) {
+ jobFinished( true );
+ } else {
+ m_currentcopy++;
+ startWriterjob();
+ }
+ } else {
+ cancelAll();
+ jobFinished( false );
+ }
+}
+
+void K3bVcdJob::parseInformation( const QString &text )
+{
+ // parse warning
+ if ( text.contains( "mpeg user scan data: one or more BCD fields out of range for" ) ) {
+ int index = text.find( " for" );
+
+ emit infoMessage( i18n( "One or more BCD fields out of range for %1" ).arg( text.mid( index + 4 ).stripWhiteSpace() ), K3bJob::WARNING );
+
+ } else if ( text.contains( "mpeg user scan data: from now on, scan information data errors will not be reported anymore" ) ) {
+ emit infoMessage( i18n( "From now on, scan information data errors will not be reported anymore" ), K3bJob::INFO );
+ emit infoMessage( i18n( "Consider enabling the 'update scan offsets' option, if it is not enabled already." ), K3bJob::INFO );
+
+ } else if ( text.contains( "APS' pts seems out of order (actual pts" ) ) {
+ int index = text.find( "(actual pts" );
+ int index2 = text.find( ", last seen pts" );
+ int index3 = text.find( ") -- ignoring this aps" );
+
+ emit infoMessage( i18n( "APS' pts seems out of order (actual pts %1, last seen pts %2)" ).arg( text.mid( index + 12, index2 - index - 12 ).stripWhiteSpace() ).arg( text.mid( index2 + 14, index3 - index2 - 14 ).stripWhiteSpace() ), K3bJob::WARNING );
+ emit infoMessage( i18n( "Ignoring this aps" ), K3bJob::INFO );
+
+ } else if ( text.contains( "bad packet at packet" ) ) {
+ int index = text.find( "at packet #" );
+ int index2 = text.find( "(stream byte offset" );
+ int index3 = text.find( ") -- remaining " );
+ int index4 = text.find( "bytes of stream will be ignored" );
+
+ emit infoMessage( i18n( "Bad packet at packet #%1 (stream byte offset %2)" ).arg( text.mid( index + 11, index2 - index - 11 ).stripWhiteSpace() ).arg( text.mid( index2 + 19, index3 - index2 - 19 ).stripWhiteSpace() ), K3bJob::WARNING );
+ emit infoMessage( i18n( "Remaining %1 bytes of stream will be ignored." ).arg( text.mid( index3 + 15, index4 - index3 - 15 ).stripWhiteSpace() ), K3bJob::WARNING );
+ }
+}
+
+QString K3bVcdJob::jobDescription() const
+{
+ switch ( m_doc->vcdType() ) {
+ case K3bVcdDoc::VCD11:
+ return i18n( "Writing Video CD (Version 1.1)" );
+ case K3bVcdDoc::VCD20:
+ return i18n( "Writing Video CD (Version 2.0)" );
+ case K3bVcdDoc::SVCD10:
+ return i18n( "Writing Super Video CD" );
+ case K3bVcdDoc::HQVCD:
+ return i18n( "Writing High-Quality Video CD" );
+ default:
+ return i18n( "Writing Video CD" );
+ }
+}
+
+
+QString K3bVcdJob::jobDetails() const
+{
+ return ( i18n( "1 MPEG (%1)",
+ "%n MPEGs (%1)",
+ m_doc->tracks() ->count() ).arg( KIO::convertSize( m_doc->size() ) )
+ + ( m_doc->copies() > 1
+ ? i18n( " - %n copy", " - %n copies", m_doc->copies() )
+ : QString::null ) );
+}
+
+#include "k3bvcdjob.moc"
diff --git a/libk3b/projects/videocd/k3bvcdjob.h b/libk3b/projects/videocd/k3bvcdjob.h
new file mode 100644
index 0000000..917c8b1
--- /dev/null
+++ b/libk3b/projects/videocd/k3bvcdjob.h
@@ -0,0 +1,115 @@
+/*
+*
+* $Id: k3bvcdjob.h 619556 2007-01-03 17:38:12Z trueg $
+* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org>
+*
+* This file is part of the K3b project.
+* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* See the file "COPYING" for the exact licensing terms.
+*/
+
+#ifndef K3BVCDJOB_H
+#define K3BVCDJOB_H
+
+#include <k3bjob.h>
+
+class K3bVcdDoc;
+class K3bVcdTrack;
+class QString;
+class K3bProcess;
+class KProcess;
+class QDataStream;
+class K3bAbstractWriter;
+class K3bDevice::Device;
+
+
+class K3bVcdJob : public K3bBurnJob
+{
+ Q_OBJECT
+
+ public:
+ K3bVcdJob( K3bVcdDoc*, K3bJobHandler*, QObject* parent = 0, const char* name = 0 );
+ ~K3bVcdJob();
+
+ K3bDoc* doc() const;
+ K3bVcdDoc* vcdDoc() const
+ {
+ return m_doc;
+ }
+ K3bDevice::Device* writer() const;
+
+ QString jobDescription() const;
+ QString jobDetails() const;
+
+ public slots:
+ void start();
+ void cancel();
+
+ private slots:
+ void cancelAll();
+
+ protected slots:
+ void slotVcdxBuildFinished();
+ void slotParseVcdxBuildOutput( KProcess*, char* output, int len );
+
+ void slotWriterJobPercent( int p );
+ void slotProcessedSize( int cs, int ts );
+ void slotWriterNextTrack( int t, int tt );
+ void slotWriterJobFinished( bool success );
+
+
+ private:
+ bool prepareWriterJob();
+
+ void xmlGen();
+ void vcdxBuild();
+ void parseInformation( const QString& );
+ void startWriterjob();
+
+ int m_copies;
+ int m_finishedCopies;
+
+ unsigned long m_blocksToCopy;
+ unsigned long m_bytesFinishedTracks;
+ unsigned long m_bytesFinished;
+
+ enum { stageUnknown, stageScan, stageWrite, _stage_max };
+
+ K3bVcdDoc* m_doc;
+ K3bDevice::Device* m_writer;
+ K3bDevice::Device* m_reader;
+ K3bVcdTrack* m_currentWrittenTrack;
+
+ int m_speed;
+ int m_stage;
+ int m_currentcopy;
+ int m_currentWrittenTrackNumber;
+
+ double m_createimageonlypercent;
+
+ bool firstTrack;
+ bool m_burnProof;
+ bool m_keepImage;
+ bool m_onlyCreateImage;
+ bool m_onTheFly;
+ bool m_dummy;
+ bool m_fastToc;
+ bool m_readRaw;
+ bool m_imageFinished;
+ bool m_canceled;
+
+ QString m_tempPath;
+ QString m_cueFile;
+ QString m_xmlFile;
+ QString m_collectedOutput;
+
+ K3bAbstractWriter* m_writerJob;
+ K3bProcess* m_process;
+};
+
+#endif
diff --git a/libk3b/projects/videocd/k3bvcdoptions.cpp b/libk3b/projects/videocd/k3bvcdoptions.cpp
new file mode 100644
index 0000000..6009a4a
--- /dev/null
+++ b/libk3b/projects/videocd/k3bvcdoptions.cpp
@@ -0,0 +1,146 @@
+/*
+*
+* $Id: k3bvcdoptions.cpp 619556 2007-01-03 17:38:12Z trueg $
+* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org>
+*
+* This file is part of the K3b project.
+* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* See the file "COPYING" for the exact licensing terms.
+*/
+
+// Kde Includes
+#include <kapplication.h>
+#include <kconfig.h>
+#include <k3bcore.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+// Qt Includes
+#include <qstring.h>
+#include <qfile.h>
+
+// K3b Includes
+#include "k3bvcdoptions.h"
+#include <k3bversion.h>
+
+K3bVcdOptions::K3bVcdOptions()
+ : m_restriction( 0 ),
+ m_segment( 0 ),
+ m_sequence( 0 ),
+ m_pbcenabled( PbcEnabled() ),
+ m_pbcnumkeysenabled( PbcNumkeysEnabled() ),
+ m_volumeID( "VIDEOCD" ),
+ m_albumID( "" ),
+ m_volumeSetId( "" ),
+ m_publisher( QString( "K3b - Version %1" ).arg( k3bcore->version() ) ),
+ m_applicationId( "CDI/CDI_VCD.APP;1" ),
+ m_systemId( "CD-RTOS CD-BRIDGE" ),
+ m_vcdclass( "vcd" ),
+ m_vcdversion( "2.0" ),
+ m_pregapleadout( 150 ),
+ m_pregaptrack( 150 ),
+ m_frontmargintrack( 30 ),
+ m_rearmargintrack( 45 ),
+ m_frontmargintrackSVCD( 0 ),
+ m_rearmargintrackSVCD( 0 ),
+ m_mpegversion( 1 ),
+ m_volumeCount( 1 ),
+ m_volumeNumber( 1 ),
+ m_autodetect( true ),
+ m_cdisupport( false ),
+ m_brokensvcdmode( false ),
+ m_VCD30interpretation( false ),
+ m_sector2336( false ),
+ m_updatescanoffsets( false ),
+ m_relaxedaps( false ),
+ m_segmentfolder( true ),
+ m_usegaps( false )
+{}
+
+bool K3bVcdOptions::checkCdiFiles()
+{
+ m_cdisize = 0;
+ if ( !QFile::exists( locate( "data", "k3b/cdi/cdi_imag.rtf" ) ) )
+ return false;
+ if ( !QFile::exists( locate( "data", "k3b/cdi/cdi_text.fnt" ) ) )
+ return false;
+ if ( !QFile::exists( locate( "data", "k3b/cdi/cdi_vcd.app" ) ) )
+ return false;
+ if ( !QFile::exists( locate( "data", "k3b/cdi/cdi_vcd.cfg" ) ) )
+ return false;
+
+ m_cdisize += QFile( locate( "data", "k3b/cdi/cdi_imag.rtf" ) ).size();
+ m_cdisize += QFile( locate( "data", "k3b/cdi/cdi_text.fnt" ) ).size();
+ m_cdisize += QFile( locate( "data", "k3b/cdi/cdi_vcd.app" ) ).size();
+ m_cdisize += QFile( locate( "data", "k3b/cdi/cdi_vcd.cfg" ) ).size();
+
+ return true;
+}
+
+void K3bVcdOptions::save( KConfigBase* c )
+{
+ c->writeEntry( "volume_id", m_volumeID );
+ c->writeEntry( "album_id", m_albumID );
+ c->writeEntry( "volume_set_id", m_volumeSetId );
+ c->writeEntry( "preparer", m_preparer );
+ c->writeEntry( "publisher", m_publisher );
+ c->writeEntry( "volume_count", m_volumeCount );
+ c->writeEntry( "volume_number", m_volumeNumber );
+ c->writeEntry( "autodetect", m_autodetect );
+ c->writeEntry( "cdi_support", m_cdisupport );
+ c->writeEntry( "broken_svcd_mode", m_brokensvcdmode );
+ c->writeEntry( "VCD30interpretation", m_VCD30interpretation );
+ c->writeEntry( "2336_sectors", m_sector2336 );
+ c->writeEntry( "UpdateScanOffsets", m_updatescanoffsets );
+ c->writeEntry( "RelaxedAps", m_relaxedaps );
+ c->writeEntry( "PbcEnabled", m_pbcenabled );
+ c->writeEntry( "SegmentFolder", m_segmentfolder );
+ c->writeEntry( "Restriction", m_restriction );
+ c->writeEntry( "PreGapLeadout", m_pregapleadout );
+ c->writeEntry( "PreGapTrack", m_pregaptrack );
+ c->writeEntry( "FrontMarginTrack", m_frontmargintrack );
+ c->writeEntry( "RearMarginTrack", m_rearmargintrack );
+ c->writeEntry( "UseGaps", m_usegaps );
+}
+
+
+K3bVcdOptions K3bVcdOptions::load( KConfigBase* c )
+{
+ K3bVcdOptions options;
+
+ options.setVolumeId( c->readEntry( "volume_id", options.volumeId() ) );
+ options.setAlbumId( c->readEntry( "album_id", options.albumId() ) );
+ options.setVolumeSetId( c->readEntry( "volume_set_id", options.volumeSetId() ) );
+ options.setPreparer( c->readEntry( "preparer", options.preparer() ) );
+ options.setPublisher( c->readEntry( "publisher", options.publisher() ) );
+ options.setVolumeCount( c->readNumEntry( "volume_count", options.volumeCount() ) );
+ options.setVolumeNumber( c->readNumEntry( "volume_number", options.volumeNumber() ) );
+ options.setAutoDetect( c->readBoolEntry( "autodetect", options.AutoDetect() ) );
+ options.setCdiSupport( c->readBoolEntry( "cdi_support", options.CdiSupport() ) );
+ options.setNonCompliantMode( c->readBoolEntry( "broken_svcd_mode", options.NonCompliantMode() ) );
+ options.setVCD30interpretation( c->readBoolEntry( "VCD30interpretation", options.VCD30interpretation() ) );
+ options.setSector2336( c->readBoolEntry( "2336_sectors", options.Sector2336() ) );
+ options.setUpdateScanOffsets( c->readBoolEntry( "UpdateScanOffsets", options.UpdateScanOffsets() ) );
+ options.setRelaxedAps( c->readBoolEntry( "RelaxedAps", options.RelaxedAps() ) );
+ options.setPbcEnabled( c->readBoolEntry( "PbcEnabled", options.PbcEnabled() ) );
+ options.setSegmentFolder( c->readBoolEntry( "SegmentFolder", options.SegmentFolder() ) );
+ options.setRestriction( c->readNumEntry( "Restriction", options.Restriction() ) );
+ options.setPreGapLeadout( c->readNumEntry( "PreGapLeadout", options.PreGapLeadout() ) );
+ options.setPreGapTrack( c->readNumEntry( "PreGapTrack", options.PreGapTrack() ) );
+ options.setFrontMarginTrack( c->readNumEntry( "FrontMarginTrack", options.FrontMarginTrack() ) );
+ options.setRearMarginTrack( c->readNumEntry( "RearMarginTrack", options.RearMarginTrack() ) );
+ options.setUseGaps( c->readBoolEntry( "UseGaps", options.UseGaps() ) );
+
+ return options;
+}
+
+K3bVcdOptions K3bVcdOptions::defaults()
+{
+ // let the constructor create defaults
+ return K3bVcdOptions();
+}
diff --git a/libk3b/projects/videocd/k3bvcdoptions.h b/libk3b/projects/videocd/k3bvcdoptions.h
new file mode 100644
index 0000000..aa5fed2
--- /dev/null
+++ b/libk3b/projects/videocd/k3bvcdoptions.h
@@ -0,0 +1,377 @@
+/*
+*
+* $Id: k3bvcdoptions.h 619556 2007-01-03 17:38:12Z trueg $
+* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org>
+*
+* This file is part of the K3b project.
+* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* See the file "COPYING" for the exact licensing terms.
+*/
+
+#ifndef K3B_VCD_OPTIONS_H
+#define K3B_VCD_OPTIONS_H
+
+#include <qstring.h>
+#include "k3b_export.h"
+
+class KConfigBase;
+
+class LIBK3B_EXPORT K3bVcdOptions
+{
+ public:
+ K3bVcdOptions();
+ const QString& volumeId() const
+ {
+ return m_volumeID;
+ }
+ const QString& albumId() const
+ {
+ return m_albumID;
+ }
+ const QString& volumeSetId() const
+ {
+ return m_volumeSetId;
+ }
+ const QString& preparer() const
+ {
+ return m_preparer;
+ }
+ const QString& publisher() const
+ {
+ return m_publisher;
+ }
+
+ const QString& applicationId() const
+ {
+ return m_applicationId;
+ }
+ const QString& systemId() const
+ {
+ return m_systemId;
+ }
+
+ const QString& vcdClass() const
+ {
+ return m_vcdclass;
+ }
+ const QString& vcdVersion() const
+ {
+ return m_vcdversion;
+ }
+
+ const int PreGapLeadout()
+ {
+ return m_pregapleadout;
+ }
+ const int PreGapTrack()
+ {
+ return m_pregaptrack;
+ }
+ const int FrontMarginTrack()
+ {
+ return m_frontmargintrack;
+ }
+ const int RearMarginTrack()
+ {
+ return m_rearmargintrack;
+ }
+ const int FrontMarginTrackSVCD()
+ {
+ return m_frontmargintrackSVCD;
+ }
+ const int RearMarginTrackSVCD()
+ {
+ return m_rearmargintrackSVCD;
+ }
+
+ const int mpegVersion() const
+ {
+ return m_mpegversion;
+ }
+
+ const int volumeCount() const
+ {
+ return m_volumeCount;
+ }
+ const int volumeNumber() const
+ {
+ return m_volumeNumber;
+ }
+
+ const bool AutoDetect() const
+ {
+ return m_autodetect;
+ }
+ const bool CdiSupport() const
+ {
+ return m_cdisupport;
+ }
+ const bool NonCompliantMode() const
+ {
+ return m_brokensvcdmode;
+ }
+ const bool VCD30interpretation() const
+ {
+ return m_VCD30interpretation;
+ }
+ const bool Sector2336() const
+ {
+ return m_sector2336;
+ }
+ const bool UpdateScanOffsets() const
+ {
+ return m_updatescanoffsets;
+ }
+ const bool RelaxedAps() const
+ {
+ return m_relaxedaps;
+ }
+ const bool UseGaps() const
+ {
+ return m_usegaps;
+ }
+ const unsigned long long CDIsize() const
+ {
+ return m_cdisize;
+ }
+
+ void setAlbumId( const QString& s )
+ {
+ m_albumID = s;
+ }
+ void setVolumeId( const QString& s )
+ {
+ m_volumeID = s;
+ }
+ void setVolumeSetId( const QString& s )
+ {
+ m_volumeSetId = s;
+ }
+ void setPreparer( const QString& s )
+ {
+ m_preparer = s;
+ }
+ void setPublisher( const QString& s )
+ {
+ m_publisher = s;
+ }
+
+ void setVcdClass( const QString& s )
+ {
+ m_vcdclass = s;
+ }
+ void setVcdVersion( const QString& s )
+ {
+ m_vcdversion = s;
+ }
+
+ void setPreGapLeadout( const int i )
+ {
+ m_pregapleadout = i;
+ }
+ void setPreGapTrack( const int i )
+ {
+ m_pregaptrack = i;
+ }
+ void setFrontMarginTrack( const int i )
+ {
+ m_frontmargintrack = i;
+ }
+ void setRearMarginTrack( const int i )
+ {
+ m_rearmargintrack = i;
+ }
+ void setFrontMarginTrackSVCD( const int i )
+ {
+ m_frontmargintrackSVCD = i;
+ }
+ void setRearMarginTrackSVCD( const int i )
+ {
+ m_rearmargintrackSVCD = i;
+ }
+
+ void setMpegVersion( const int v )
+ {
+ m_mpegversion = v;
+ }
+ void setVolumeCount( const int c )
+ {
+ m_volumeCount = c;
+ }
+ void setVolumeNumber( const int n )
+ {
+ m_volumeNumber = n;
+ }
+
+ void setAutoDetect( const bool& b )
+ {
+ m_autodetect = b;
+ }
+ void setCdiSupport( const bool& b )
+ {
+ m_cdisupport = b;
+ }
+ void setNonCompliantMode( const bool& b )
+ {
+ m_brokensvcdmode = b;
+ }
+ void setVCD30interpretation( const bool& b )
+ {
+ m_VCD30interpretation = b;
+ }
+ void setSector2336( const bool& b )
+ {
+ m_sector2336 = b;
+ }
+ void setUpdateScanOffsets( const bool& b )
+ {
+ m_updatescanoffsets = b;
+ }
+ void setRelaxedAps( const bool& b )
+ {
+ m_relaxedaps = b;
+ }
+ void setUseGaps( const bool& b )
+ {
+ m_usegaps = b;
+ }
+
+ bool checkCdiFiles();
+ void save( KConfigBase* c );
+
+ static K3bVcdOptions load( KConfigBase* c );
+ static K3bVcdOptions defaults();
+
+ void setPbcEnabled( const bool& b )
+ {
+ m_pbcenabled = b;
+ }
+ bool PbcEnabled() const
+ {
+ return m_pbcenabled;
+ };
+ void setPbcNumkeysEnabled( const bool& b )
+ {
+ m_pbcnumkeysenabled = b;
+ }
+ bool PbcNumkeysEnabled() const
+ {
+ return m_pbcnumkeysenabled;
+ };
+
+ void setPbcPlayTime( const int i )
+ {
+ m_def_pbcplaytime = i;
+ }
+ int PbcPlayTime( )
+ {
+ return m_def_pbcplaytime;
+ }
+
+ void setPbcWaitTime( const int i )
+ {
+ m_def_pbcwaittime = i;
+ }
+ int PbcWaitTime( )
+ {
+ return m_def_pbcwaittime;
+ }
+
+ void setSegmentFolder( const bool& b )
+ {
+ m_segmentfolder = b;
+ }
+ bool SegmentFolder() const
+ {
+ return m_segmentfolder;
+ };
+
+ void setRestriction( const int i )
+ {
+ m_restriction = i;
+ }
+ int Restriction() const
+ {
+ return m_restriction;
+ };
+ void increaseSegments( )
+ {
+ m_segment += 1;
+ }
+ void decreaseSegments( )
+ {
+ m_segment -= 1;
+ }
+ bool haveSegments() const
+ {
+ return m_segment > 0;
+ };
+ void increaseSequence( )
+ {
+ m_sequence += 1;
+ }
+ void decreaseSequence( )
+ {
+ m_sequence -= 1;
+ }
+
+ bool haveSequence() const
+ {
+ return m_sequence > 0;
+ };
+
+ private:
+ int m_restriction;
+ int m_segment;
+ int m_sequence;
+
+ // pbc
+ bool m_pbcenabled;
+ bool m_pbcnumkeysenabled;
+
+ // volume descriptor
+ QString m_volumeID;
+ QString m_albumID;
+ QString m_volumeSetId;
+
+ QString m_preparer;
+ QString m_publisher;
+
+ QString m_applicationId;
+ QString m_systemId;
+
+ QString m_vcdclass;
+ QString m_vcdversion;
+
+ int m_pregapleadout;
+ int m_pregaptrack;
+ int m_frontmargintrack;
+ int m_rearmargintrack;
+ int m_frontmargintrackSVCD;
+ int m_rearmargintrackSVCD;
+
+ int m_mpegversion;
+ int m_volumeCount;
+ int m_volumeNumber;
+
+ bool m_autodetect;
+ bool m_cdisupport;
+ bool m_brokensvcdmode;
+ bool m_VCD30interpretation;
+ bool m_sector2336;
+ bool m_updatescanoffsets;
+ bool m_relaxedaps;
+ bool m_segmentfolder;
+ bool m_usegaps;
+
+ int m_def_pbcplaytime;
+ int m_def_pbcwaittime;
+ unsigned long long m_cdisize;
+};
+
+#endif
diff --git a/libk3b/projects/videocd/k3bvcdtrack.cpp b/libk3b/projects/videocd/k3bvcdtrack.cpp
new file mode 100644
index 0000000..7f0043f
--- /dev/null
+++ b/libk3b/projects/videocd/k3bvcdtrack.cpp
@@ -0,0 +1,456 @@
+/*
+*
+* $Id: k3bvcdtrack.cpp 619556 2007-01-03 17:38:12Z trueg $
+* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org>
+*
+* This file is part of the K3b project.
+* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* See the file "COPYING" for the exact licensing terms.
+*/
+
+#include <kapplication.h>
+#include <kconfig.h>
+
+#include <qstring.h>
+#include <qfileinfo.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+// K3b Includes
+#include "k3bvcdtrack.h"
+#include <k3bglobals.h>
+
+K3bVcdTrack::K3bVcdTrack( QPtrList<K3bVcdTrack>* parent, const QString& filename )
+ : m_pbcnumkeys( true ),
+ m_pbcnumkeysuserdefined( false ),
+ m_file( filename )
+{
+ m_parent = parent;
+ m_title = QFileInfo( m_file ).baseName( true );
+
+ m_revreflist = new QPtrList<K3bVcdTrack>;
+
+ for ( int i = 0; i < K3bVcdTrack::_maxPbcTracks; i++ ) {
+ m_pbctrackmap.insert( i, 0L );
+ m_pbcnontrackmap.insert( i, K3bVcdTrack::DISABLED );
+ m_pbcusrdefmap.insert( i, false );
+ }
+
+ m_reactivity = false;
+
+ m_definedkeysmap.clear();
+
+ mpeg_info = new Mpeginfo();
+}
+
+
+K3bVcdTrack::~K3bVcdTrack()
+{}
+
+
+KIO::filesize_t K3bVcdTrack::size() const
+{
+ return m_file.size();
+}
+
+int K3bVcdTrack::index() const
+{
+ int i = m_parent->find( this );
+ if ( i < 0 )
+ kdDebug() << "(K3bVcdTrack) I'm not part of my parent!" << endl;
+ return i;
+}
+
+void K3bVcdTrack::addToRevRefList( K3bVcdTrack* revreftrack )
+{
+ kdDebug() << "K3bVcdTrack::addToRevRefList: track = " << revreftrack << endl;
+
+ m_revreflist->append( revreftrack );
+
+ kdDebug() << "K3bVcdTrack::hasRevRef count = " << m_revreflist->count() << " empty = " << m_revreflist->isEmpty() << endl;
+}
+
+void K3bVcdTrack::delFromRevRefList( K3bVcdTrack* revreftrack )
+{
+ if ( !m_revreflist->isEmpty() ) {
+ m_revreflist->remove
+ ( revreftrack );
+ }
+}
+
+bool K3bVcdTrack::hasRevRef()
+{
+ return !m_revreflist->isEmpty() ;
+}
+
+void K3bVcdTrack::delRefToUs()
+{
+ for ( K3bVcdTrack * track = m_revreflist->first(); track; track = m_revreflist->next() ) {
+ for ( int i = 0; i < K3bVcdTrack::_maxPbcTracks; i++ ) {
+ kdDebug() << "K3bVcdTrack::delRefToUs count = " << m_revreflist->count() << " empty = " << m_revreflist->isEmpty() << " track = " << track << " this = " << this << endl;
+ if ( this == track->getPbcTrack( i ) ) {
+ track->setPbcTrack( i );
+ track->setUserDefined( i, false );
+ track->delFromRevRefList( this );
+ }
+ }
+ }
+}
+
+void K3bVcdTrack::delRefFromUs()
+{
+ for ( int i = 0; i < K3bVcdTrack::_maxPbcTracks; i++ ) {
+ if ( this->getPbcTrack( i ) ) {
+ this->getPbcTrack( i ) ->delFromRevRefList( this );
+ }
+ }
+}
+
+void K3bVcdTrack::setPbcTrack( int which, K3bVcdTrack* pbctrack )
+{
+ kdDebug() << "K3bVcdTrack::setPbcTrack " << which << ", " << pbctrack << endl;
+ m_pbctrackmap.replace( which, pbctrack );
+}
+
+void K3bVcdTrack::setPbcNonTrack( int which, int type )
+{
+ kdDebug() << "K3bVcdTrack::setNonPbcTrack " << which << ", " << type << endl;
+ m_pbcnontrackmap.replace( which, type );
+}
+
+void K3bVcdTrack::setUserDefined( int which, bool ud )
+{
+ m_pbcusrdefmap.replace( which, ud );
+}
+
+K3bVcdTrack* K3bVcdTrack::getPbcTrack( const int& which )
+{
+ if ( m_pbctrackmap.find( which ) == m_pbctrackmap.end() )
+ return 0;
+ else
+ return m_pbctrackmap[ which ];
+}
+
+int K3bVcdTrack::getNonPbcTrack( const int& which )
+{
+ if ( m_pbcnontrackmap.find( which ) == m_pbcnontrackmap.end() )
+ return 0;
+ else
+ return m_pbcnontrackmap[ which ];
+}
+
+bool K3bVcdTrack::isPbcUserDefined( int which )
+{
+ return m_pbcusrdefmap[ which ];
+}
+
+const QString K3bVcdTrack::resolution()
+{
+ if ( mpeg_info->has_video ) {
+ for ( int i = 0; i < 2; i++ ) {
+ if ( mpeg_info->video[ i ].seen ) {
+ return QString( "%1 x %2" ).arg( mpeg_info->video[ i ].hsize ).arg( mpeg_info->video[ i ].vsize );
+ }
+ }
+ }
+
+ return i18n( "n/a" );
+}
+
+const QString K3bVcdTrack::highresolution()
+{
+ if ( mpeg_info->has_video ) {
+ if ( mpeg_info->video[ 2 ].seen ) {
+ return QString( "%1 x %2" ).arg( mpeg_info->video[ 2 ].hsize ).arg( mpeg_info->video[ 2 ].vsize );
+ }
+ }
+ return i18n( "n/a" );
+}
+
+const QString K3bVcdTrack::video_frate()
+{
+ if ( mpeg_info->has_video ) {
+ for ( int i = 0; i < 2; i++ ) {
+ if ( mpeg_info->video[ i ].seen ) {
+ return QString::number( mpeg_info->video[ i ].frate );
+ }
+ }
+ }
+
+ return i18n( "n/a" );
+}
+
+const QString K3bVcdTrack::video_bitrate()
+{
+ if ( mpeg_info->has_video ) {
+ for ( int i = 0; i < 2; i++ ) {
+ if ( mpeg_info->video[ i ].seen ) {
+ return i18n( "%1 bit/s" ).arg( mpeg_info->video[ i ].bitrate ) ;
+ }
+ }
+ }
+
+ return i18n( "n/a" );
+}
+
+
+
+const QString K3bVcdTrack::video_format()
+{
+ if ( mpeg_info->has_video ) {
+ for ( int i = 0; i < 2; i++ ) {
+ if ( mpeg_info->video[ i ].seen ) {
+ switch ( mpeg_info->video[ i ].video_format ) {
+ case 0 :
+ return i18n( "Component" );
+ break;
+ case 1 :
+ return "PAL";
+ break;
+ case 2 :
+ return "NTSC";
+ break;
+ case 3 :
+ return "SECAM";
+ break;
+ case 4 :
+ return "MAC";
+ break;
+ case 5 :
+ default:
+ return i18n( "Unspecified" );
+ kdDebug() << "K3bVcdTrack::video_format() :" << mpeg_info->video[ i ].video_format << endl;
+ break;
+ }
+ }
+ }
+ }
+ return i18n( "n/a" );
+}
+
+const QString K3bVcdTrack::video_chroma()
+{
+ if ( mpeg_info->has_video ) {
+ // MPEG1 only supports 4:2:0 Format
+ if ( version() == K3bMpegInfo::MPEG_VERS_MPEG1 )
+ return QString( "4:2:0" );
+
+ for ( int i = 0; i < 2; i++ ) {
+ if ( mpeg_info->video[ i ].seen ) {
+ switch ( mpeg_info->video[ i ].chroma_format ) {
+ case 1 :
+ return QString( "4:2:0" );
+ break;
+ case 2 :
+ return QString( "4:2:2" );
+ break;
+ case 3 :
+ return QString( "4:4:4" );
+ break;
+
+ }
+ }
+ }
+ }
+
+ return i18n( "n/a" );
+}
+
+const QString K3bVcdTrack::audio_layer()
+{
+ if ( mpeg_info->has_audio ) {
+ for ( int i = 0; i < 2; i++ ) {
+ if ( mpeg_info->audio[ i ].seen ) {
+ return QString::number( mpeg_info->audio[ i ].layer );
+ }
+ }
+ }
+
+ return i18n( "n/a" );
+}
+
+const QString K3bVcdTrack::audio_bitrate()
+{
+ if ( mpeg_info->has_audio ) {
+ for ( int i = 0; i < 2; i++ ) {
+ if ( mpeg_info->audio[ i ].seen ) {
+ return i18n( "%1 bit/s" ).arg( mpeg_info->audio[ i ].bitrate ) ;
+ }
+ }
+ }
+
+ return i18n( "n/a" );
+}
+
+const QString K3bVcdTrack::audio_sampfreq()
+{
+ if ( mpeg_info->has_audio ) {
+ for ( int i = 0; i < 2; i++ ) {
+ if ( mpeg_info->audio[ i ].seen ) {
+ return i18n( "%1 Hz" ).arg( mpeg_info->audio[ i ].sampfreq ) ;
+ }
+ }
+ }
+
+ return i18n( "n/a" );
+}
+
+const QString K3bVcdTrack::audio_mode( )
+{
+ if ( mpeg_info->has_audio ) {
+ for ( int i = 2; i >= 0; i-- )
+ if ( mpeg_info->audio[ i ].seen )
+ return QString( audio_type2str( mpeg_info->audio[ i ].version, mpeg_info->audio[ i ].mode, i ) );
+
+ }
+
+ return i18n( "n/a" );
+}
+
+const QString K3bVcdTrack::audio_copyright( )
+{
+ if ( mpeg_info->has_audio ) {
+ for ( int i = 2; i >= 0; i-- )
+ if ( mpeg_info->audio[ i ].seen )
+ if ( mpeg_info->audio[ i ].copyright )
+ return QString( "(c) " ) + ( mpeg_info->audio[ i ].original ? i18n( "original" ) : i18n( "duplicate" ) );
+ else
+ return ( mpeg_info->audio[ i ].original ? i18n( "original" ) : i18n( "duplicate" ) );
+ }
+
+ return i18n( "n/a" );
+}
+
+const QString K3bVcdTrack::mpegTypeS( bool audio )
+{
+ if ( mpeg_info->has_video && !audio ) {
+ for ( int i = 0; i < 3; i++ )
+ if ( mpeg_info->video[ i ].seen ) {
+ if ( i == 0 ) {
+ return QString( "MPEG%1 " ).arg( mpeg_info->version ) + i18n( "Motion Picture" );
+ } else {
+ return QString( "MPEG%1 " ).arg( mpeg_info->version ) + i18n( "Still Picture" );
+ }
+ }
+ }
+ if ( mpeg_info->has_audio && audio ) {
+ for ( int i = 0; i < 3; i++ )
+ if ( mpeg_info->audio[ i ].seen ) {
+ return QString( "MPEG%1 " ).arg( mpeg_info->audio[ i ].version ) + i18n( "Layer %1" ).arg( mpeg_info->audio[ i ].layer );
+ }
+ }
+
+ return i18n( "n/a" );
+}
+
+const int K3bVcdTrack::mpegType( )
+{
+ if ( mpeg_info->has_video ) {
+ for ( int i = 0; i < 3; i++ )
+ if ( mpeg_info->video[ i ].seen ) {
+ if ( i == 0 ) {
+ return 0; // MPEG_MOTION;
+ } else {
+ return 1; // MPEG_STILL;
+ }
+ }
+ }
+ if ( mpeg_info->has_audio ) {
+ for ( int i = 0; i < 3; i++ )
+ if ( mpeg_info->audio[ i ].seen )
+ return 2; // MPEG_AUDIO;
+ }
+
+ return -1; // MPEG_UNKNOWN;
+}
+
+const QString K3bVcdTrack::audio_type2str( unsigned int version, unsigned int audio_mode, unsigned int audio_type )
+{
+ kdDebug() << "K3bVcdTrack::audio_type2str() version:" << version << " audio_mode:" << audio_mode << " audio_type:" << audio_type << endl;
+
+ QString audio_types[ 3 ][ 5 ] = {
+ {
+ i18n( "unknown" ),
+ i18n( "invalid" ),
+ QString::null,
+ QString::null,
+ QString::null
+ },
+ {
+ i18n( "stereo" ),
+ i18n( "joint stereo" ),
+ i18n( "dual channel" ),
+ i18n( "single channel" )
+ },
+ {
+ QString::null,
+ i18n( "dual channel" ),
+ i18n( "surround sound" ),
+ QString::null,
+ QString::null
+ }
+ };
+ switch ( version ) {
+ case K3bMpegInfo::MPEG_VERS_MPEG1:
+ return audio_types[ 1 ][ audio_mode ];
+ break;
+
+ case K3bMpegInfo::MPEG_VERS_MPEG2:
+ if ( audio_type > 0 ) {
+ return audio_types[ 2 ][ audio_type ];
+ }
+ return audio_types[ 1 ][ audio_mode ];
+ break;
+ }
+
+ return i18n( "n/a" );
+}
+
+// convert a time in second to HH:mm:ss notation
+QString K3bVcdTrack::SecsToHMS( double duration )
+{
+ byte hours = ( byte ) ( duration / 3600 );
+ byte mins = ( byte ) ( ( duration / 60 ) - ( hours * 60 ) );
+ float secs = duration - 60 * mins - 3600 * hours;
+ if ( hours != 0 ) {
+ return QString( "%1:" ).arg( hours ).rightJustify( 3, ' ' ) + QString( "%1:" ).arg( mins ).rightJustify( 3, '0' ) + QString::number( secs, 'f', 2 );
+ }
+ if ( mins != 0 ) {
+ return QString( "%1:" ).arg( mins ).rightJustify( 3, '0' ) + QString::number( secs, 'f', 2 );
+ }
+ return QString::number( secs, 'f', 2 );
+}
+
+void K3bVcdTrack::PrintInfo()
+{
+
+ kdDebug() << "K3bVcdTrack::PrintInfo() ....................." << endl;
+ kdDebug() << " version : MPEG" << version() << endl;
+ kdDebug() << " duration : " << duration() << endl;
+ kdDebug() << " muxrate : " << muxrate() << endl;
+ kdDebug() << " video ......................................" << endl;
+ kdDebug() << " type : " << mpegTypeS() << endl;
+ kdDebug() << " resolution : " << resolution() << endl;
+ kdDebug() << " high resolution: " << highresolution() << endl;
+ kdDebug() << " frate : " << video_frate() << endl;
+ kdDebug() << " bitrate : " << video_bitrate() << endl;
+ kdDebug() << " format : " << video_format( ) << endl;
+ kdDebug() << " chroma : " << video_chroma( ) << endl;
+ kdDebug() << " audio ......................................" << endl;
+ kdDebug() << " type : " << mpegTypeS( true ) << endl;
+ kdDebug() << " mode : " << audio_mode() << endl;
+ kdDebug() << " layer : " << audio_layer() << endl;
+ kdDebug() << " bitrate : " << audio_bitrate() << endl;
+ kdDebug() << " sampfreq : " << audio_sampfreq() << endl;
+
+}
diff --git a/libk3b/projects/videocd/k3bvcdtrack.h b/libk3b/projects/videocd/k3bvcdtrack.h
new file mode 100644
index 0000000..0d9a3cf
--- /dev/null
+++ b/libk3b/projects/videocd/k3bvcdtrack.h
@@ -0,0 +1,198 @@
+/*
+*
+* $Id: k3bvcdtrack.h 619556 2007-01-03 17:38:12Z trueg $
+* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org>
+*
+* This file is part of the K3b project.
+* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* See the file "COPYING" for the exact licensing terms.
+*/
+
+#ifndef K3BVCDTRACK_H
+#define K3BVCDTRACK_H
+
+// Qt Includes
+#include <qstring.h>
+#include <qfileinfo.h>
+#include <qfile.h>
+#include <qptrlist.h>
+
+// Kde Includes
+#include <kio/global.h>
+
+// K3b Includes
+#include "mpeginfo/k3bmpeginfo.h"
+#include "k3b_export.h"
+class LIBK3B_EXPORT K3bVcdTrack
+{
+ public:
+ K3bVcdTrack( QPtrList<K3bVcdTrack>* parent, const QString& filename );
+ ~K3bVcdTrack();
+
+ QString fileName() const
+ {
+ return QFileInfo( m_file ).fileName();
+ }
+ QString absPath() const
+ {
+ return QFileInfo( m_file ).absFilePath();
+ }
+ KIO::filesize_t size() const;
+ int index() const;
+
+ const QString& title() const
+ {
+ return m_title;
+ }
+ void setTitle( const QString& t )
+ {
+ m_title = t;
+ }
+ bool isSegment()
+ {
+ return mpegType() == 1;
+ };
+
+
+
+ // PBC
+ enum PbcTracks { PREVIOUS, NEXT, RETURN, DEFAULT, AFTERTIMEOUT, _maxPbcTracks };
+ enum PbcTypes { DISABLED, VIDEOEND };
+
+ void addToRevRefList( K3bVcdTrack* revreftrack );
+ void delFromRevRefList( K3bVcdTrack* revreftrack );
+ bool hasRevRef();
+ void delRefToUs();
+ void delRefFromUs();
+
+ void setPbcTrack( int, K3bVcdTrack* pbctrack = 0L );
+ void setPbcNonTrack( int, int );
+ void setUserDefined( int, bool );
+ void setPlayTime( int t )
+ {
+ m_pbcplaytime = t;
+ }
+ void setWaitTime( int t )
+ {
+ m_pbcwaittime = t;
+ }
+ void setReactivity( bool b )
+ {
+ m_reactivity = b;
+ }
+ void setPbcNumKeys( const bool& b )
+ {
+ m_pbcnumkeys = b;
+ }
+ bool PbcNumKeys() const
+ {
+ return m_pbcnumkeys;
+ };
+ void setPbcNumKeysUserdefined( const bool& b )
+ {
+ m_pbcnumkeysuserdefined = b;
+ };
+ bool PbcNumKeysUserdefined() const
+ {
+ return m_pbcnumkeysuserdefined;
+ };
+
+ K3bVcdTrack* getPbcTrack( const int& );
+ int getNonPbcTrack( const int& );
+ bool isPbcUserDefined( int );
+ int getPlayTime()
+ {
+ return m_pbcplaytime;
+ }
+ int getWaitTime()
+ {
+ return m_pbcwaittime;
+ }
+ bool Reactivity()
+ {
+ return m_reactivity;
+ }
+
+ // Numeric keys
+ void setDefinedNumKey( int key, K3bVcdTrack* track )
+ {
+ m_definedkeysmap.insert( key, track );
+ }
+ void delDefinedNumKey( int key )
+ {
+ m_definedkeysmap.remove( key );
+ }
+ void delDefinedNumKey()
+ {
+ m_definedkeysmap.clear();
+ }
+ QMap<int, K3bVcdTrack*> DefinedNumKey()
+ {
+ return m_definedkeysmap;
+ }
+
+ // Mpeg Infos
+ const QString resolution();
+ const QString highresolution();
+ const QString video_frate();
+ const QString video_bitrate();
+ const QString audio_layer();
+ const QString audio_bitrate();
+ const QString audio_sampfreq();
+
+ const QString duration()
+ {
+ return SecsToHMS( mpeg_info->playing_time );
+ };
+ const int version()
+ {
+ return mpeg_info->version;
+ };
+ const unsigned long muxrate()
+ {
+ return mpeg_info->muxrate;
+ };
+ const QString video_format( );
+ const QString video_chroma( );
+ const QString audio_mode( );
+ const QString audio_copyright( );
+ const QString mpegTypeS( bool audio = false );
+ const int mpegType();
+
+ void PrintInfo();
+
+ Mpeginfo* mpeg_info;
+
+ protected:
+
+ const QString audio_type2str( unsigned int , unsigned int, unsigned int );
+ QString SecsToHMS( double );
+
+ QPtrList<K3bVcdTrack>* m_parent;
+
+ // PBC
+ QPtrList<K3bVcdTrack>* m_revreflist; // List of Tracks which points to us
+ QMap<int, K3bVcdTrack*> m_pbctrackmap; // Pbc Tracks (Previous, Next, ...)
+ QMap<int, int> m_pbcnontrackmap; // Pbc NON Track types (Previous, Next, ...)
+ QMap<int, bool> m_pbcusrdefmap; // Pbc is userdefined or defaults (Previous, Next, ...)
+ QMap<int, K3bVcdTrack*> m_definedkeysmap;
+
+ bool m_pbcnumkeys;
+ bool m_pbcnumkeysuserdefined;
+
+ int m_pbcplaytime;
+ int m_pbcwaittime;
+ /********************************************************************************/
+
+ bool m_reactivity;
+ int m_filetype;
+ QFile m_file;
+ QString m_title;
+};
+
+#endif
diff --git a/libk3b/projects/videocd/k3bvcdxmlview.cpp b/libk3b/projects/videocd/k3bvcdxmlview.cpp
new file mode 100644
index 0000000..0b6f250
--- /dev/null
+++ b/libk3b/projects/videocd/k3bvcdxmlview.cpp
@@ -0,0 +1,440 @@
+/*
+*
+* $Id: k3bvcdxmlview.cpp 619556 2007-01-03 17:38:12Z trueg $
+* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org>
+* THX to Manfred Odenstein <odix@chello.at>
+*
+* This file is part of the K3b project.
+* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* See the file "COPYING" for the exact licensing terms.
+*/
+
+#include <qfile.h>
+
+#include <kstandarddirs.h>
+#include <kdebug.h>
+
+
+#include "k3bvcdxmlview.h"
+#include "k3bvcdtrack.h"
+#include <k3bcore.h>
+#include <k3bversion.h>
+
+K3bVcdXmlView::K3bVcdXmlView( K3bVcdDoc* pDoc )
+{
+
+ m_doc = pDoc;
+
+}
+
+K3bVcdXmlView::~K3bVcdXmlView()
+{}
+
+bool K3bVcdXmlView::write( const QString& fname )
+{
+
+ QDomDocument xmlDoc( "videocd PUBLIC \"-//GNU//DTD VideoCD//EN\" \"http://www.gnu.org/software/vcdimager/videocd.dtd\"" );
+ // xmlDoc.appendChild( xmlDoc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"iso-8859-1\"" ) );
+ xmlDoc.appendChild( xmlDoc.createProcessingInstruction( "xml", "version=\"1.0\"" ) );
+
+ // create root element
+ QDomElement root = xmlDoc.createElement( "videocd" );
+ root.setAttribute( "xmlns", "http://www.gnu.org/software/vcdimager/1.0/" );
+ root.setAttribute( "class", m_doc->vcdOptions() ->vcdClass() );
+ root.setAttribute( "version", m_doc->vcdOptions() ->vcdVersion() );
+ xmlDoc.appendChild( root );
+
+ // create option elements
+
+ // Broken SVCD mode - NonCompliantMode
+ if ( m_doc->vcdOptions() ->NonCompliantMode() ) {
+ QDomElement elemOption;
+ elemOption = addSubElement( xmlDoc, root, "option" );
+ elemOption.setAttribute( "name", "svcd vcd30 mpegav" );
+ elemOption.setAttribute( "value", "true" );
+
+ elemOption = addSubElement( xmlDoc, root, "option" );
+ elemOption.setAttribute( "name", "svcd vcd30 entrysvd" );
+ elemOption.setAttribute( "value", "true" );
+ }
+
+ // VCD3.0 track interpretation
+ if ( m_doc->vcdOptions() ->VCD30interpretation() ) {
+ QDomElement elemOption;
+ elemOption = addSubElement( xmlDoc, root, "option" );
+ elemOption.setAttribute( "name", "svcd vcd30 tracksvd" );
+ elemOption.setAttribute( "value", "true" );
+ }
+
+ // Relaxed aps
+ if ( m_doc->vcdOptions() ->RelaxedAps() ) {
+ QDomElement elemOption;
+ elemOption = addSubElement( xmlDoc, root, "option" );
+ elemOption.setAttribute( "name", "relaxed aps" );
+ elemOption.setAttribute( "value", "true" );
+ }
+
+ // Update scan offsets
+ if ( m_doc->vcdOptions() ->UpdateScanOffsets() ) {
+ QDomElement elemOption;
+ elemOption = addSubElement( xmlDoc, root, "option" );
+ elemOption.setAttribute( "name", "update scan offsets" );
+ elemOption.setAttribute( "value", "true" );
+
+ }
+
+ // Gaps & Margins
+ if ( m_doc->vcdOptions() ->UseGaps() ) {
+ QDomElement elemOption;
+ elemOption = addSubElement( xmlDoc, root, "option" );
+ elemOption.setAttribute( "name", "leadout pregap" );
+ elemOption.setAttribute( "value", m_doc->vcdOptions() ->PreGapLeadout() );
+
+ elemOption = addSubElement( xmlDoc, root, "option" );
+ elemOption.setAttribute( "name", "track pregap" );
+ elemOption.setAttribute( "value", m_doc->vcdOptions() ->PreGapTrack() );
+
+ if ( m_doc->vcdOptions() ->vcdClass() == "vcd" ) {
+ elemOption = addSubElement( xmlDoc, root, "option" );
+ elemOption.setAttribute( "name", "track front margin" );
+ elemOption.setAttribute( "value", m_doc->vcdOptions() ->FrontMarginTrack() );
+
+ elemOption = addSubElement( xmlDoc, root, "option" );
+ elemOption.setAttribute( "name", "track rear margin" );
+ elemOption.setAttribute( "value", m_doc->vcdOptions() ->RearMarginTrack() );
+ } else {
+ elemOption = addSubElement( xmlDoc, root, "option" );
+ elemOption.setAttribute( "name", "track front margin" );
+ elemOption.setAttribute( "value", m_doc->vcdOptions() ->FrontMarginTrackSVCD() );
+
+ elemOption = addSubElement( xmlDoc, root, "option" );
+ elemOption.setAttribute( "name", "track rear margin" );
+ elemOption.setAttribute( "value", m_doc->vcdOptions() ->RearMarginTrackSVCD() );
+ }
+
+ }
+
+ // create info element
+ QDomElement elemInfo = addSubElement( xmlDoc, root, "info" );
+ addSubElement( xmlDoc, elemInfo, "album-id", m_doc->vcdOptions() ->albumId().upper() );
+ addSubElement( xmlDoc, elemInfo, "volume-count", m_doc->vcdOptions() ->volumeCount() );
+ addSubElement( xmlDoc, elemInfo, "volume-number", m_doc->vcdOptions() ->volumeNumber() );
+ addSubElement( xmlDoc, elemInfo, "restriction", m_doc->vcdOptions() ->Restriction() );
+
+ // create pvd element
+ QDomElement elemPvd = addSubElement( xmlDoc, root, "pvd" );
+ addSubElement( xmlDoc, elemPvd, "volume-id", m_doc->vcdOptions() ->volumeId().upper() );
+ addSubElement( xmlDoc, elemPvd, "system-id", m_doc->vcdOptions() ->systemId() );
+ addSubElement( xmlDoc, elemPvd, "application-id", m_doc->vcdOptions() ->applicationId() );
+ addSubElement( xmlDoc, elemPvd, "preparer-id", QString( "K3b - Version %1" ).arg( k3bcore->version() ).upper() );
+ addSubElement( xmlDoc, elemPvd, "publisher-id", m_doc->vcdOptions() ->publisher().upper() );
+
+
+ // create filesystem element
+ QDomElement elemFileSystem = addSubElement( xmlDoc, root, "filesystem" );
+
+ // SEGMENT folder, some standalone DVD-Player need this
+ if ( !m_doc->vcdOptions() ->haveSegments() && m_doc->vcdOptions() ->SegmentFolder() )
+ addFolderElement( xmlDoc, elemFileSystem, "SEGMENT" );
+
+ // create cdi element
+ if ( m_doc->vcdOptions() ->CdiSupport() ) {
+ QDomElement elemFolder = addFolderElement( xmlDoc, elemFileSystem, "CDI" );
+
+ addFileElement( xmlDoc, elemFolder, locate( "data", "k3b/cdi/cdi_imag.rtf" ), "CDI_IMAG.RTF", true );
+ addFileElement( xmlDoc, elemFolder, locate( "data", "k3b/cdi/cdi_text.fnt" ), "CDI_TEXT.FNT" );
+ addFileElement( xmlDoc, elemFolder, locate( "data", "k3b/cdi/cdi_vcd.app" ), "CDI_VCD.APP" );
+
+ QString usercdicfg = locateLocal( "appdata", "cdi/cdi_vcd.cfg" );
+ if ( QFile::exists( usercdicfg ) )
+ addFileElement( xmlDoc, elemFolder, usercdicfg, "CDI_VCD.CFG" );
+ else
+ addFileElement( xmlDoc, elemFolder, locate( "data", "k3b/cdi/cdi_vcd.cfg" ), "CDI_VCD.CFG" );
+ }
+
+ // sequence-items element & segment-items element
+ QDomElement elemsequenceItems;
+ QDomElement elemsegmentItems;
+
+ // sequence-item element & segment-item element
+ QDomElement elemsequenceItem;
+ QDomElement elemsegmentItem;
+
+ // if we have segments, elemsegmentItems must be before any sequence in xml file order
+ if ( m_doc->vcdOptions()->haveSegments() )
+ elemsegmentItems = addSubElement( xmlDoc, root, "segment-items" );
+
+ // sequence must always available ...
+ elemsequenceItems = addSubElement( xmlDoc, root, "sequence-items" );
+ // if we have no sequence (photo (s)vcd) we must add a dummy sequence they inform the user to turn on pbc on there videoplayer
+ if ( !m_doc->vcdOptions()->haveSequence() ) {
+ QString filename;
+ if ( m_doc->vcdOptions()->mpegVersion() == 1 )
+ filename = locate( "data", "k3b/extra/k3bphotovcd.mpg" );
+ else
+ filename = locate( "data", "k3b/extra/k3bphotosvcd.mpg" );
+
+ elemsequenceItem = addSubElement( xmlDoc, elemsequenceItems, "sequence-item" );
+ elemsequenceItem.setAttribute( "src", QString( "%1" ).arg( QFile::encodeName( filename ) ) );
+ elemsequenceItem.setAttribute( "id", "sequence-000" );
+ // default entry
+ QDomElement elemdefaultEntry;
+ elemdefaultEntry = addSubElement( xmlDoc, elemsequenceItem, "default-entry" );
+ elemdefaultEntry.setAttribute( "id", "entry-000" );
+ }
+
+
+ // pbc
+ QDomElement elemPbc;
+
+ // Add Tracks to XML
+ QPtrListIterator<K3bVcdTrack> it( *m_doc->tracks() );
+ for ( ; it.current(); ++it ) {
+ if ( !it.current() ->isSegment() ) {
+ QString seqId = QString::number( it.current() ->index() ).rightJustify( 3, '0' );
+
+ elemsequenceItem = addSubElement( xmlDoc, elemsequenceItems, "sequence-item" );
+ elemsequenceItem.setAttribute( "src", QString( "%1" ).arg( QFile::encodeName( it.current() ->absPath() ) ) );
+ elemsequenceItem.setAttribute( "id", QString( "sequence-%1" ).arg( seqId ) );
+
+ // default entry
+ QDomElement elemdefaultEntry;
+ elemdefaultEntry = addSubElement( xmlDoc, elemsequenceItem, "default-entry" );
+ elemdefaultEntry.setAttribute( "id", QString( "entry-%1" ).arg( seqId ) );
+
+ } else {
+ // sequence-items element needs at least one segment to fit the XML
+ elemsegmentItem = addSubElement( xmlDoc, elemsegmentItems, "segment-item" );
+ elemsegmentItem.setAttribute( "src", QString( "%1" ).arg( QFile::encodeName( it.current() ->absPath() ) ) );
+ elemsegmentItem.setAttribute( "id", QString( "segment-%1" ).arg( QString::number( it.current() ->index() ).rightJustify( 3, '0' ) ) );
+
+ }
+ }
+ for ( it.toFirst(); it.current(); ++it ) {
+
+ if ( m_doc->vcdOptions() ->PbcEnabled() ) {
+ if ( elemPbc.isNull() )
+ elemPbc = addSubElement( xmlDoc, root, "pbc" );
+
+ doPbc( xmlDoc, elemPbc, it.current() );
+ }
+ }
+
+ if ( ! elemPbc.isNull() ) {
+ QDomElement elemEndlist = addSubElement( xmlDoc, elemPbc, "endlist" );
+ elemEndlist.setAttribute( "id", "end" );
+ elemEndlist.setAttribute( "rejected", "true" );
+ }
+
+ m_xmlstring = xmlDoc.toString();
+ kdDebug() << QString( "(K3bVcdXmlView) Write Data to %1:" ).arg( fname ) << endl;
+
+ QFile xmlFile( fname );
+ if ( xmlFile.open( IO_WriteOnly ) ) {
+ QTextStream ts( & xmlFile );
+ ts << m_xmlstring;
+ xmlFile.close();
+ return true;
+ }
+
+ return false;
+}
+
+void K3bVcdXmlView::addComment( QDomDocument& doc, QDomElement& parent, const QString& text )
+{
+ QDomComment comment = doc.createComment( text );
+ parent.appendChild( comment );
+}
+
+QDomElement K3bVcdXmlView::addSubElement( QDomDocument& doc, QDomElement& parent, const QString& name, const QString& value )
+{
+ QDomElement element = doc.createElement( name );
+ parent.appendChild( element );
+ if ( !value.isNull() ) {
+ QDomText t = doc.createTextNode( value );
+ element.appendChild( t );
+ }
+ return element;
+}
+
+QDomElement K3bVcdXmlView::addSubElement( QDomDocument& doc, QDomElement& parent, const QString& name, const int& value )
+{
+ QDomElement element = doc.createElement( name );
+ parent.appendChild( element );
+ if ( value >= -1 ) {
+ QDomText t = doc.createTextNode( QString( "%1" ).arg( value ) );
+ element.appendChild( t );
+ }
+ return element;
+}
+
+QDomElement K3bVcdXmlView::addFolderElement( QDomDocument& doc, QDomElement& parent, const QString& name )
+{
+ QDomElement elemFolder = addSubElement( doc, parent, "folder" );
+ addSubElement( doc, elemFolder, "name", name );
+
+ return elemFolder;
+}
+
+void K3bVcdXmlView::addFileElement( QDomDocument& doc, QDomElement& parent, const QString& src, const QString& name, bool mixed )
+{
+ QDomElement elemFile = addSubElement( doc, parent, "file" );
+ elemFile.setAttribute( "src", QString( "%1" ).arg( src ) );
+ if ( mixed )
+ elemFile.setAttribute( "format", "mixed" );
+
+ addSubElement( doc, elemFile, "name", name );
+}
+
+void K3bVcdXmlView::doPbc( QDomDocument& doc, QDomElement& parent, K3bVcdTrack* track )
+{
+ QString ref = ( track->isSegment() ) ? "segment" : "sequence";
+
+ QDomElement elemSelection = addSubElement( doc, parent, "selection" );
+ elemSelection.setAttribute( "id", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( track->index() ).rightJustify( 3, '0' ) ) );
+
+ setNumkeyBSN( doc, elemSelection, track );
+
+ for ( int i = 0; i < K3bVcdTrack::_maxPbcTracks; i++ ) {
+ QDomElement elemPbcSelectionPNRDT;
+
+ if ( track->getPbcTrack( i ) ) {
+ int index = track->getPbcTrack( i ) ->index();
+ QString ref = ( track->getPbcTrack( i ) ->isSegment() ) ? "segment" : "sequence";
+
+ switch ( i ) {
+ case K3bVcdTrack::PREVIOUS:
+ elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "prev" );
+ elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustify( 3, '0' ) ) );
+ break;
+ case K3bVcdTrack::NEXT:
+ elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "next" );
+ elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustify( 3, '0' ) ) );
+ break;
+ case K3bVcdTrack::RETURN:
+ elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "return" );
+ elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustify( 3, '0' ) ) );
+ break;
+ case K3bVcdTrack::DEFAULT:
+ elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "default" );
+ elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustify( 3, '0' ) ) );
+ break;
+ case K3bVcdTrack::AFTERTIMEOUT:
+ if ( track->getWaitTime() >= 0 ) {
+ elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "timeout" );
+ elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustify( 3, '0' ) ) );
+ }
+ break;
+ }
+ } else {
+ // jump to <endlist> otherwise do noop while disabled
+ if ( track->getNonPbcTrack( i ) == K3bVcdTrack::VIDEOEND ) {
+ switch ( i ) {
+ case K3bVcdTrack::PREVIOUS:
+ elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "prev" );
+ elemPbcSelectionPNRDT.setAttribute( "ref", "end" );
+ break;
+ case K3bVcdTrack::NEXT:
+ elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "next" );
+ elemPbcSelectionPNRDT.setAttribute( "ref", "end" );
+ break;
+ case K3bVcdTrack::RETURN:
+ elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "return" );
+ elemPbcSelectionPNRDT.setAttribute( "ref", "end" );
+ break;
+ case K3bVcdTrack::DEFAULT:
+ elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "default" );
+ elemPbcSelectionPNRDT.setAttribute( "ref", "end" );
+ break;
+ case K3bVcdTrack::AFTERTIMEOUT:
+ if ( track->getWaitTime() >= 0 ) {
+ elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "timeout" );
+ elemPbcSelectionPNRDT.setAttribute( "ref", "end" );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ addSubElement( doc, elemSelection, "wait", track->getWaitTime() );
+ QDomElement loop = addSubElement( doc, elemSelection, "loop", track->getPlayTime() );
+ if ( track->Reactivity() )
+ loop.setAttribute( "jump-timing", "delayed" );
+ else
+ loop.setAttribute( "jump-timing", "immediate" );
+
+ addSubElement( doc, elemSelection, "play-item" ).setAttribute( "ref", QString( "%1-%2" ).arg( ref ).arg( QString::number( track->index() ).rightJustify( 3, '0' ) ) );
+
+ setNumkeySEL( doc, elemSelection, track );
+}
+
+void K3bVcdXmlView::setNumkeyBSN( QDomDocument& doc, QDomElement& parent, K3bVcdTrack* track )
+{
+ if ( track->PbcNumKeys() ) {
+ if ( track->PbcNumKeysUserdefined() ) {
+ QMap<int, K3bVcdTrack*> numKeyMap = track->DefinedNumKey();
+ QMap<int, K3bVcdTrack*>::const_iterator trackIt;
+
+ m_startkey = 0;
+ trackIt = numKeyMap.begin();
+ if ( trackIt != numKeyMap.end() )
+ m_startkey = trackIt.key();
+
+ if ( m_startkey > 0 )
+ addSubElement( doc, parent, "bsn", m_startkey );
+ else // user has no numKeys defined for this track
+ track->setPbcNumKeys( false );
+
+ } else {
+ // default start with key #1
+ addSubElement( doc, parent, "bsn", 1 );
+ }
+ }
+}
+
+void K3bVcdXmlView::setNumkeySEL( QDomDocument& doc, QDomElement& parent, K3bVcdTrack* track )
+{
+ if ( track->PbcNumKeys() ) {
+ QDomElement elemPbcSelectionNumKeySEL;
+ QString ref = ( track->isSegment() ) ? "segment" : "sequence";
+ int none = m_startkey;
+ if ( track->PbcNumKeysUserdefined() ) {
+ QMap<int, K3bVcdTrack*> numKeyMap = track->DefinedNumKey();
+ QMap<int, K3bVcdTrack*>::const_iterator trackIt;
+
+ for ( trackIt = numKeyMap.begin(); trackIt != numKeyMap.end(); ++trackIt ) {
+
+ kdDebug() << QString( "trackIt key: %1 none: %2" ).arg( trackIt.key() ).arg( none ) << endl;
+ while ( none < trackIt.key() ) {
+ elemPbcSelectionNumKeySEL = addSubElement( doc, parent, "select" );
+ elemPbcSelectionNumKeySEL.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( track->index() ).rightJustify( 3, '0' ) ) );
+ addComment( doc, parent, QString( "key %1 -> %2 (normal none)" ).arg( none ).arg( QFile::encodeName( track->absPath() ) ) );
+ none++;
+ }
+
+ if ( trackIt.data() ) {
+ QString ref = ( trackIt.data() ->isSegment() ) ? "segment" : "sequence";
+ elemPbcSelectionNumKeySEL = addSubElement( doc, parent, "select" );
+ elemPbcSelectionNumKeySEL.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( trackIt.data() ->index() ).rightJustify( 3, '0' ) ) );
+ addComment( doc, parent, QString( "key %1 -> %2" ).arg( trackIt.key() ).arg( QFile::encodeName( trackIt.data() ->absPath() ) ) );
+ } else {
+ elemPbcSelectionNumKeySEL = addSubElement( doc, parent, "select" );
+ elemPbcSelectionNumKeySEL.setAttribute( "ref", "end" );
+ addComment( doc, parent, QString( "key %1 -> end" ).arg( trackIt.key() ) );
+ }
+ none++;
+ }
+ } else {
+ // default reference to itSelf
+ elemPbcSelectionNumKeySEL = addSubElement( doc, parent, "select" );
+ elemPbcSelectionNumKeySEL.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( track->index() ).rightJustify( 3, '0' ) ) );
+ }
+ }
+}
+
diff --git a/libk3b/projects/videocd/k3bvcdxmlview.h b/libk3b/projects/videocd/k3bvcdxmlview.h
new file mode 100644
index 0000000..d99549b
--- /dev/null
+++ b/libk3b/projects/videocd/k3bvcdxmlview.h
@@ -0,0 +1,59 @@
+/*
+*
+* $Id: k3bvcdxmlview.h 619556 2007-01-03 17:38:12Z trueg $
+* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org>
+* THX to Manfred Odenstein <odix@chello.at>
+*
+* This file is part of the K3b project.
+* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* See the file "COPYING" for the exact licensing terms.
+*/
+
+#ifndef K3B_VCD_XMLVIEW_H
+#define K3B_VCD_XMLVIEW_H
+
+#include <qstring.h>
+#include <qdom.h>
+#include <ktempfile.h>
+
+#include <k3bvcddoc.h>
+
+class K3bVcdOptions;
+class K3bVcdTrack;
+
+
+class K3bVcdXmlView
+{
+
+ public:
+ K3bVcdXmlView( K3bVcdDoc* );
+ ~K3bVcdXmlView();
+
+ bool write( const QString& );
+ QString xmlString()
+ {
+ return m_xmlstring;
+ }
+
+ private:
+ QString m_xmlstring;
+
+ void addComment( QDomDocument& doc, QDomElement& parent, const QString& text );
+ QDomElement addSubElement( QDomDocument&, QDomElement&, const QString& name, const QString& value = QString::null );
+ QDomElement addSubElement( QDomDocument&, QDomElement&, const QString& name, const int& value );
+
+ QDomElement addFolderElement( QDomDocument&, QDomElement&, const QString& name );
+ void addFileElement( QDomDocument&, QDomElement&, const QString& src, const QString& name, bool mixed = false );
+ void doPbc( QDomDocument&, QDomElement&, K3bVcdTrack* );
+ void setNumkeyBSN( QDomDocument& , QDomElement&, K3bVcdTrack* );
+ void setNumkeySEL( QDomDocument& , QDomElement&, K3bVcdTrack* );
+ K3bVcdDoc* m_doc;
+ int m_startkey;
+};
+
+#endif
diff --git a/libk3b/projects/videocd/mpeginfo/Makefile.am b/libk3b/projects/videocd/mpeginfo/Makefile.am
new file mode 100644
index 0000000..af1b06b
--- /dev/null
+++ b/libk3b/projects/videocd/mpeginfo/Makefile.am
@@ -0,0 +1,5 @@
+INCLUDES = $(all_includes)
+noinst_LTLIBRARIES = libmpeginfo.la
+
+libmpeginfo_la_SOURCES = k3bmpeginfo.cpp
+
diff --git a/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.cpp b/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.cpp
new file mode 100644
index 0000000..583a0aa
--- /dev/null
+++ b/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.cpp
@@ -0,0 +1,844 @@
+/*
+*
+* $Id: k3bmpeginfo.cpp 619556 2007-01-03 17:38:12Z trueg $
+* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org>
+*
+* This file is part of the K3b project.
+* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* See the file "COPYING" for the exact licensing terms.
+*/
+
+// kde includes
+#include <klocale.h>
+
+// k3b includes
+#include "k3bmpeginfo.h"
+
+static const double frame_rates[ 16 ] =
+ {
+ 0.0, 24000.0 / 1001, 24.0, 25.0,
+ 30000.0 / 1001, 30.0, 50.0, 60000.0 / 1001,
+ 60.0, 0.0,
+ };
+
+K3bMpegInfo::K3bMpegInfo( const char* filename )
+ : m_mpegfile( 0 ),
+ m_filename( filename ),
+ m_done( false ),
+ m_buffstart( 0 ),
+ m_buffend( 0 ),
+ m_buffer( 0 ),
+ m_initial_TS( 0.0 )
+{
+
+ mpeg_info = new Mpeginfo();
+
+ m_mpegfile = fopen( filename, "rb" );
+
+ if ( m_mpegfile == 0 ) {
+ kdDebug() << QString( "Unable to open %1" ).arg( m_filename ) << endl;
+ return ;
+ }
+
+ if ( fseeko( m_mpegfile, 0, SEEK_END ) ) {
+ kdDebug() << QString( "Unable to seek in file %1" ).arg( m_filename ) << endl;
+ return ;
+ }
+
+ llong lof = ftello( m_mpegfile );
+
+ if ( lof == -1 ) {
+ kdDebug() << QString( "Seeking to end of input file %1 failed." ).arg( m_filename ) << endl;
+ //give up..
+ return ;
+ } else
+ m_filesize = lof;
+
+ // nothing to do on an empty file
+ if ( !m_filesize ) {
+ kdDebug() << QString( "File %1 is empty." ).arg( m_filename ) << endl;
+ m_error_string = i18n( "File %1 is empty." ).arg( m_filename );
+ return ;
+ }
+
+ m_buffer = new byte[ BUFFERSIZE ];
+
+ MpegParsePacket ( );
+
+}
+
+K3bMpegInfo::~K3bMpegInfo()
+{
+ if ( m_buffer ) {
+ delete[] m_buffer;
+ }
+ if ( m_mpegfile ) {
+ fclose( m_mpegfile );
+ }
+
+ delete mpeg_info;
+}
+bool K3bMpegInfo::MpegParsePacket ()
+{
+
+ /* verify the packet begins with a pack header */
+ if ( !EnsureMPEG( 0, MPEG_PACK_HEADER_CODE ) ) {
+ llong code = GetNBytes( 0, 4 );
+
+ kdDebug() << QString( "(K3bMpegInfo::mpeg_parse_packet ()) pack header code 0x%1 expected, but 0x%2 found" ).arg( 0x00000100 + MPEG_PACK_HEADER_CODE, 0, 16 ).arg( code, 0, 16 ) << endl;
+
+ if ( code == 0x00000100 + MPEG_SEQUENCE_CODE ) {
+ kdDebug() << "...this looks like a elementary video stream but a multiplexed program stream was required." << endl;
+ m_error_string = i18n( "This looks like a elementary video stream but a multiplexed program stream was required." );
+ }
+
+ if ( ( 0xfff00000 & code ) == 0xfff00000 ) {
+ kdDebug() << "...this looks like a elementary audio stream but a multiplexed program stream was required." << endl;
+ m_error_string = i18n( "This looks like a elementary audio stream but a multiplexed program stream was required." );
+ }
+
+ if ( code == 0x52494646 ) {
+ kdDebug() << "...this looks like a RIFF header but a plain multiplexed program stream was required." << endl;
+ m_error_string = i18n( "This looks like a RIFF header but a plain multiplexed program stream was required." );
+ }
+
+ return false;
+ }
+
+
+ /* take a look at the pack header */
+ int offset = 0;
+ while ( GetByte( offset ) == 0x00 )
+ offset ++;
+ //here we're on the first non null byte let's get back to leave two zeros (packet start code)
+ offset -= 2;
+
+ if ( offset != 0 ) {
+ // we actually skipped some zeroes
+ kdDebug() << QString( "Skipped %1 zeroes at start of file" ).arg( offset ) << endl;
+ }
+
+ // here while schleife
+ while ( offset != -1 ) {
+ offset = MpegParsePacket( offset );
+ }
+
+ /*
+ int pkt = 0;
+ offset = FindNextMarker( 0, MPEG_PACK_HEADER_CODE );
+
+ while ( offset != -1 ) {
+ pkt++;
+ offset = FindNextMarker( offset+1, MPEG_PACK_HEADER_CODE );
+ }
+
+ kdDebug() << "Pkt found: " << pkt << endl;
+ */
+
+ //seek the file duration by fetching the last PACK
+ //and reading its timestamp
+ llong last_pack = bdFindNextMarker( m_filesize - 13, MPEG_PACK_HEADER_CODE );
+ // -12 because a PACK is at least 12 bytes
+ double duration;
+ last_pack += 4;
+ int bits = GetByte( last_pack ) >> 4;
+
+ if ( bits == 0x2 ) /* %0010 ISO11172-1 */
+ {
+ duration = ReadTS( last_pack );
+ } else if ( bits >> 2 == 0x1 ) /* %01xx ISO13818-1 */
+ {
+ duration = ReadTSMpeg2( last_pack );
+ } else {
+ kdDebug() << QString( "no timestamp found" ) << endl;
+ duration = ReadTS( last_pack );
+ }
+
+ mpeg_info->playing_time = duration - m_initial_TS;
+
+
+ if ( !mpeg_info->has_video )
+ for ( int i = 0; i < 2; i++ )
+ if ( mpeg_info->video[ i ].seen )
+ mpeg_info->has_video = true;
+
+ if ( !mpeg_info->has_audio )
+ for ( int i = 0; i < 2; i++ )
+ if ( mpeg_info->audio[ i ].seen )
+ mpeg_info->has_audio = true;
+
+ return true;
+}
+
+llong K3bMpegInfo::MpegParsePacket ( llong offset )
+{
+ byte mark = 0;
+ uint size = 0;
+
+ /* continue until start code seen */
+ offset = FindNextMarker( offset, &mark );
+
+ if ( offset < 0 )
+ return offset;
+
+ switch ( mark ) {
+ int bits;
+
+ case MPEG_PACK_HEADER_CODE:
+ // kdDebug() << QString( "MPEG_PACK_HEADER_CODE @ %1" ).arg( offset ) << endl;
+
+ offset += 4;
+
+ if ( mpeg_info->version != MPEG_VERS_INVALID )
+ break;
+
+ bits = GetByte( offset ) >> 4;
+
+ if ( bits == 0x2 ) /* %0010 ISO11172-1 */
+ {
+ mpeg_info->version = MPEG_VERS_MPEG1;
+
+ unsigned long muxrate = 0;
+
+ muxrate = ( GetByte( offset + 5 ) & 0x7F ) << 15;
+ muxrate |= ( GetByte( offset + 6 ) << 7 );
+ muxrate |= ( GetByte( offset + 7 ) >> 1 );
+
+ mpeg_info->muxrate = muxrate * 50 * 8;
+
+ if ( m_initial_TS == 0.0 )
+ {
+ m_initial_TS = ReadTS( offset );
+ kdDebug() << QString( "Initial TS = %1" ).arg( m_initial_TS ) << endl;
+ }
+
+ } else if ( bits >> 2 == 0x1 ) /* %01xx ISO13818-1 */
+ {
+ mpeg_info->version = MPEG_VERS_MPEG2;
+
+ unsigned long muxrate = 0;
+ muxrate = GetByte( offset + 6 ) << 14;
+ muxrate |= GetByte( offset + 7 ) << 6;
+ muxrate |= GetByte( offset + 8 ) >> 2;
+
+ mpeg_info->muxrate = muxrate * 50 * 8;
+
+ if ( m_initial_TS == 0.0 )
+ {
+ m_initial_TS = ReadTSMpeg2( offset );
+ kdDebug() << QString( "Initial TS = %1" ).arg( m_initial_TS ) << endl;
+ }
+
+ } else {
+ kdDebug() << QString( "packet not recognized as either version 1 or 2 (%1)" ).arg( bits ) << endl;
+ mpeg_info->version = MPEG_VERS_INVALID;
+ return -1;
+ }
+ break;
+
+ case MPEG_SYSTEM_HEADER_CODE:
+ case MPEG_PAD_CODE:
+ case MPEG_PRIVATE_1_CODE:
+ case MPEG_VIDEO_E0_CODE:
+ case MPEG_VIDEO_E1_CODE:
+ case MPEG_VIDEO_E2_CODE:
+ case MPEG_AUDIO_C0_CODE:
+ case MPEG_AUDIO_C1_CODE:
+ case MPEG_AUDIO_C2_CODE:
+
+ offset += 4;
+ size = GetSize( offset );
+ offset += 2;
+ // kdDebug() << QString( "offset = %1, size = %2" ).arg( offset ).arg( size ) << endl;
+
+ switch ( mark ) {
+ case MPEG_SYSTEM_HEADER_CODE:
+ // kdDebug() << QString( "Systemheader: %1" ).arg( m_code, 0, 16 ) << endl;
+ break;
+
+ case MPEG_VIDEO_E0_CODE:
+ case MPEG_VIDEO_E1_CODE:
+ case MPEG_VIDEO_E2_CODE:
+ ParseVideo( offset, mark );
+ // _analyze_video_pes (code & 0xff, buf + pos, size, !parse_pes, ctx);
+ if ( mpeg_info->has_video && mpeg_info->has_audio ) {
+ return -1;
+ } else if ( mark == MPEG_VIDEO_E0_CODE || mpeg_info->version == MPEG_VERS_MPEG2 && mark == MPEG_VIDEO_E1_CODE || mpeg_info->version == MPEG_VERS_MPEG1 && mark == MPEG_VIDEO_E2_CODE ) {
+ mpeg_info->has_video = true;
+ offset = FindNextAudio( offset );
+ }
+ break;
+ case MPEG_AUDIO_C0_CODE:
+ case MPEG_AUDIO_C1_CODE:
+ case MPEG_AUDIO_C2_CODE:
+ offset = SkipPacketHeader( offset - 6 );
+ ParseAudio( offset, mark );
+ // audio packet doesn't begin with 0xFFF
+ if ( !mpeg_info->audio[ GetAudioIdx( mark ) ].seen ) {
+ int a_idx = GetAudioIdx( mark );
+ while ( ( offset < m_filesize - 10 ) && !mpeg_info->audio[ a_idx ].seen ) {
+ if ( ( GetByte( offset ) == 0xFF ) && ( GetByte( offset + 1 ) & 0xF0 ) == 0xF0 )
+ ParseAudio( offset, mark );
+ offset++;
+ }
+ }
+
+ mpeg_info->has_audio = true;
+ if ( mpeg_info->has_video )
+ return -1;
+
+ offset = FindNextVideo( offset );
+ break;
+
+ case MPEG_PRIVATE_1_CODE:
+ kdDebug() << QString( "PrivateCode: %1" ).arg( mark, 0, 16 ) << endl;
+ break;
+ }
+ break;
+
+ case MPEG_PROGRAM_END_CODE:
+ kdDebug() << QString( "ProgramEndCode: %1" ).arg( mark, 0, 16 ) << endl;
+ offset += 4;
+ break;
+
+ case MPEG_PICTURE_CODE:
+ kdDebug() << QString( "PictureCode: %1" ).arg( mark, 0, 16 ) << endl;
+ offset += 3;
+ break;
+
+ default:
+ offset += 4;
+ break;
+ }
+
+ return offset;
+}
+
+byte K3bMpegInfo::GetByte( llong offset )
+{
+ unsigned long nread;
+ if ( ( offset >= m_buffend ) || ( offset < m_buffstart ) ) {
+
+ if ( fseeko( m_mpegfile, offset, SEEK_SET ) ) {
+ kdDebug() << QString( "could not get seek to offset (%1) in file %2 (size:%3)" ).arg( offset ).arg( m_filename ).arg( m_filesize ) << endl;
+ return 0x11;
+ }
+ nread = fread( m_buffer, 1, BUFFERSIZE, m_mpegfile );
+ m_buffstart = offset;
+ m_buffend = offset + nread;
+ if ( ( offset >= m_buffend ) || ( offset < m_buffstart ) ) {
+ // weird
+ kdDebug() << QString( "could not get offset %1 in file %2 [%3]" ).arg( offset ).arg( m_filename ).arg( m_filesize ) << endl;
+ return 0x11;
+ }
+ }
+ return m_buffer[ offset - m_buffstart ];
+}
+
+// same as above but improved for backward search
+byte K3bMpegInfo::bdGetByte( llong offset )
+{
+ unsigned long nread;
+ if ( ( offset >= m_buffend ) || ( offset < m_buffstart ) ) {
+ llong start = offset - BUFFERSIZE + 1 ;
+ start = start >= 0 ? start : 0;
+
+ fseeko( m_mpegfile, start, SEEK_SET );
+
+ nread = fread( m_buffer, 1, BUFFERSIZE, m_mpegfile );
+ m_buffstart = start;
+ m_buffend = start + nread;
+ if ( ( offset >= m_buffend ) || ( offset < m_buffstart ) ) {
+ // weird
+ kdDebug() << QString( "could not get offset %1 in file %2 [%3]" ).arg( offset ).arg( m_filename ).arg( m_filesize ) << endl;
+
+ return 0x11;
+ }
+ }
+ return m_buffer[ offset - m_buffstart ];
+}
+
+
+llong K3bMpegInfo::GetNBytes( llong offset, int n )
+{
+ llong nbytes = 0;
+ n--;
+ for ( int i = 0; i < n; i++ )
+ ( ( char* ) & nbytes ) [ n - i ] = GetByte( offset + i );
+
+ return nbytes;
+
+}
+
+// get a two byte size
+unsigned short int K3bMpegInfo::GetSize( llong offset )
+{
+ return GetByte( offset ) * 256 + GetByte( offset + 1 );
+ // return GetNBytes( offset, 2 );
+
+}
+
+bool K3bMpegInfo::EnsureMPEG( llong offset, byte mark )
+{
+ if ( ( GetByte( offset ) == 0x00 ) &&
+ ( GetByte( offset + 1 ) == 0x00 ) &&
+ ( GetByte( offset + 2 ) == 0x01 ) &&
+ ( GetByte( offset + 3 ) == mark ) )
+ return true;
+ else
+ return false;
+}
+
+
+// find next 0x 00 00 01 xx sequence, returns offset or -1 on err
+llong K3bMpegInfo::FindNextMarker( llong from )
+{
+ llong offset;
+ for ( offset = from; offset < ( m_filesize - 4 ); offset++ ) {
+ if (
+ ( GetByte( offset + 0 ) == 0x00 ) &&
+ ( GetByte( offset + 1 ) == 0x00 ) &&
+ ( GetByte( offset + 2 ) == 0x01 ) ) {
+ return offset;
+ }
+ }
+ return -1;
+}
+
+// find next 0x 00 00 01 xx sequence, returns offset or -1 on err and
+// change mark to xx
+llong K3bMpegInfo::FindNextMarker( llong from, byte* mark )
+{
+ llong offset = FindNextMarker( from );
+ if ( offset >= 0 ) {
+ *mark = GetByte( offset + 3 );
+ return offset;
+ } else {
+ return -1;
+ }
+}
+
+// find next 0X00 00 01 mark
+llong K3bMpegInfo::FindNextMarker( llong from, byte mark )
+{
+ llong offset = from;
+ while ( offset >= 0 ) {
+ offset = FindNextMarker( offset );
+ if ( offset < 0 ) {
+ return -1;
+ }
+ if ( EnsureMPEG( offset, mark ) ) {
+ return offset;
+ } else
+ offset++;
+ }
+
+ //shouldn't be here
+ return -1;
+}
+
+llong K3bMpegInfo::bdFindNextMarker( llong from, byte mark )
+{
+ llong offset;
+ for ( offset = from; offset >= 0; offset-- ) {
+ if (
+ ( bdGetByte( offset ) == 0x00 ) &&
+ ( bdGetByte( offset + 1 ) == 0x00 ) &&
+ ( bdGetByte( offset + 2 ) == 0x01 ) &&
+ ( bdGetByte( offset + 3 ) == mark ) ) {
+ return offset;
+ }
+ }
+ return -1;
+}
+
+llong K3bMpegInfo::bdFindNextMarker( llong from, byte* mark )
+{
+ llong offset;
+ for ( offset = from; offset >= 0; offset-- ) {
+ if ( ( bdGetByte( offset ) == 0x00 ) &&
+ ( bdGetByte( offset + 1 ) == 0x00 ) &&
+ ( bdGetByte( offset + 2 ) == 0x01 ) ) {
+ *mark = bdGetByte( offset + 3 );
+ return offset;
+ }
+ }
+ return -1;
+
+}
+
+llong K3bMpegInfo::FindNextVideo( llong from )
+{
+ llong offset = from;
+ while ( offset >= 0 ) {
+ offset = FindNextMarker( offset );
+ if ( offset < 0 ) {
+ return -1;
+ }
+ if ( EnsureMPEG( offset, MPEG_VIDEO_E0_CODE ) || EnsureMPEG( offset, MPEG_VIDEO_E1_CODE ) || EnsureMPEG( offset, MPEG_VIDEO_E2_CODE ) ) {
+ return offset;
+ } else
+ offset++;
+ }
+
+ //shouldn't be here
+ return -1;
+}
+
+llong K3bMpegInfo::FindNextAudio( llong from )
+{
+ llong offset = from;
+ while ( offset >= 0 ) {
+ offset = FindNextMarker( offset );
+ if ( offset < 0 ) {
+ return -1;
+ }
+ if ( EnsureMPEG( offset, MPEG_AUDIO_C0_CODE ) || EnsureMPEG( offset, MPEG_AUDIO_C1_CODE ) || EnsureMPEG( offset, MPEG_AUDIO_C2_CODE ) ) {
+ return offset;
+ } else
+ offset++;
+ }
+
+ return -1;
+}
+
+
+int K3bMpegInfo::GetVideoIdx ( byte marker )
+{
+ switch ( marker ) {
+ case MPEG_VIDEO_E0_CODE:
+ return 0;
+ break;
+
+ case MPEG_VIDEO_E1_CODE:
+ return 1;
+ break;
+
+ case MPEG_VIDEO_E2_CODE:
+ return 2;
+ break;
+
+ default:
+ kdDebug() << "VideoCode not reached" << endl;
+ break;
+ }
+
+ return -1;
+}
+
+int K3bMpegInfo::GetAudioIdx ( byte marker )
+{
+ switch ( marker ) {
+ case MPEG_AUDIO_C0_CODE:
+ return 0;
+ break;
+
+ case MPEG_AUDIO_C1_CODE:
+ return 1;
+ break;
+
+ case MPEG_AUDIO_C2_CODE:
+ return 2;
+ break;
+
+ default:
+ kdDebug() << "VideoCode not reached" << endl;
+ break;
+ }
+
+ return -1;
+}
+
+llong K3bMpegInfo::SkipPacketHeader( llong offset )
+{
+ byte tmp_byte;
+ if ( mpeg_info->version == MPEG_VERS_MPEG1 ) {
+ // skip startcode and packet size
+ offset += 6;
+ //remove stuffing bytes
+ tmp_byte = GetByte( offset );
+ while ( tmp_byte & 0x80 )
+ tmp_byte = GetByte( ++offset );
+
+ if ( ( tmp_byte & 0xC0 ) == 0x40 ) // next two bits are 01
+ offset += 2;
+
+ tmp_byte = GetByte( offset );
+ if ( ( tmp_byte & 0xF0 ) == 0x20 )
+ offset += 5;
+ else if ( ( tmp_byte & 0xF0 ) == 0x30 )
+ offset += 10;
+ else
+ offset++;
+
+ return offset;
+ } else if ( mpeg_info->version == MPEG_VERS_MPEG2 ) {
+ return ( offset + 9 + GetByte( offset + 8 ) );
+ } else
+ return ( offset + 10 );
+}
+
+void K3bMpegInfo::ParseAudio ( llong offset, byte marker )
+{
+ unsigned brate, srate;
+ bool mpeg2_5 = false;
+
+ const int a_idx = GetAudioIdx( marker );
+
+ if ( mpeg_info->audio[ a_idx ].seen ) /* we have it already */
+ return ;
+
+ if ( ( GetByte( offset ) != 0xFF ) || ( ( GetByte( offset + 1 ) & 0xF0 ) != 0xF0 ) ) {
+ // doesn't start with 12 bits set
+ if ( ( GetByte( offset ) != 0xFF ) || ( ( GetByte( offset + 1 ) & 0xE0 ) != 0xE0 ) ) {
+ // doesn't start with 11 bits set
+ return ;
+ } else {
+ // start with 11 bits set
+ mpeg2_5 = true;
+ }
+ }
+
+ // Find mpeg version 1.0 or 2.0
+ if ( GetByte( offset + 1 ) & 0x08 ) {
+ if ( !mpeg2_5 )
+ mpeg_info->audio[ a_idx ].version = 1;
+ else
+ return ; // invalid 01 encountered
+ } else {
+ if ( !mpeg2_5 )
+ mpeg_info->audio[ a_idx ].version = 2;
+ else
+ mpeg_info->audio[ a_idx ].version = 3; //for mpeg 2.5
+ }
+
+ // Find Layer
+ mpeg_info->audio[ a_idx ].layer = ( GetByte( offset + 1 ) & 0x06 ) >> 1;
+ switch ( mpeg_info->audio[ a_idx ].layer ) {
+ case 0:
+ mpeg_info->audio[ a_idx ].layer = 0;
+ break;
+ case 1:
+ mpeg_info->audio[ a_idx ].layer = 3;
+ break;
+ case 2:
+ mpeg_info->audio[ a_idx ].layer = 2;
+ break;
+ case 3:
+ mpeg_info->audio[ a_idx ].layer = 1;
+ break;
+ }
+
+ // Protection Bit
+ mpeg_info->audio[ a_idx ].protect = GetByte( offset + 1 ) & 0x01;
+ if ( mpeg_info->audio[ a_idx ].protect )
+ mpeg_info->audio[ a_idx ].protect = 0;
+ else
+ mpeg_info->audio[ a_idx ].protect = 1;
+
+ const unsigned bit_rates[ 4 ][ 16 ] = {
+ {
+ 0,
+ },
+ {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0},
+ {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0},
+ {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0}
+ };
+
+
+ /* const unsigned bit_rates [ 3 ][ 3 ][ 16 ] = {
+ {
+ {0, },
+ {0, },
+ {0, },
+ },
+ {
+ {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0},
+ {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0},
+ {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0}
+ },
+ {
+ {0, 32, 48, 56, 64, 80 , 96 , 112, 128, 144, 160, 176, 192, 224, 256, 0},
+ {0, 8, 16, 24, 32, 40, 48, 56, 64 , 80 , 96 , 112, 128, 144, 160, 0},
+ {0, 8, 16, 24, 32, 40, 48, 56, 64 , 80 , 96 , 112, 128, 144, 160, 0}
+ }
+ };
+ */
+
+ const unsigned sampling_rates[ 4 ][ 4 ] = {
+ {
+ 0,
+ },
+ {44100, 48000, 32000, 0}, //mpeg 1
+ {22050, 24000, 16000, 0}, //mpeg 2
+ {11025, 12000, 8000, 0} //mpeg 2.5
+ };
+
+
+ // Bitrate index and sampling index to pass through the array
+ brate = GetByte( offset + 2 ) >> 4;
+ srate = ( GetByte( offset + 2 ) & 0x0f ) >> 2;
+
+ mpeg_info->audio[ a_idx ].bitrate = 1024 * bit_rates[ mpeg_info->audio[ a_idx ].layer ][ brate ];
+ mpeg_info->audio[ a_idx ].byterate = ( float ) ( mpeg_info->audio[ a_idx ].bitrate / 8.0 );
+ mpeg_info->audio[ a_idx ].sampfreq = sampling_rates[ mpeg_info->audio[ a_idx ].version ][ srate ];
+
+ // Audio mode
+ mpeg_info->audio[ a_idx ].mode = 1 + ( GetByte( offset + 3 ) >> 6 ) ;
+
+ // Copyright bit
+ if ( GetByte( offset + 3 ) & 0x08 )
+ mpeg_info->audio[ a_idx ].copyright = true;
+ else
+ mpeg_info->audio[ a_idx ].copyright = false;
+
+ // Original/Copy bit
+ if ( GetByte( offset + 3 ) & 0x04 )
+ mpeg_info->audio[ a_idx ].original = true;
+ else
+ mpeg_info->audio[ a_idx ].original = false;
+
+
+ mpeg_info->audio[ a_idx ].seen = true;
+}
+
+void K3bMpegInfo::ParseVideo ( llong offset, byte marker )
+{
+ unsigned long aratio, frate, brate;
+
+ const int v_idx = GetVideoIdx( marker );
+
+ const double aspect_ratios[ 16 ] = {
+ 0.0000, 1.0000, 0.6735, 0.7031,
+ 0.7615, 0.8055, 0.8437, 0.8935,
+ 0.9375, 0.9815, 1.0255, 1.0695,
+ 1.1250, 1.1575, 1.2015, 0.0000
+ };
+
+ if ( mpeg_info->video[ v_idx ].seen ) /* we have it already */
+ return ;
+
+ offset = FindNextMarker( offset + 1, MPEG_SEQUENCE_CODE );
+
+ if ( !offset )
+ return ;
+
+ offset += 4;
+
+ mpeg_info->video[ v_idx ].hsize = GetSize( offset ) >> 4;
+ mpeg_info->video[ v_idx ].vsize = GetSize( offset + 1 ) & 0x0FFF;
+
+ // Get picture rate
+ offset += 3; // after picture sizes
+
+ aratio = ( GetByte( offset ) & 0x0F ) >> 4;
+ mpeg_info->video[ v_idx ].aratio = aspect_ratios[ aratio ];
+
+ // offset += 3; // after picture sizes
+ frate = GetByte( offset ) & 0x0F;
+ mpeg_info->video[ v_idx ].frate = frame_rates[ frate ];
+
+ offset += 1; // after picture rate
+
+ // 18 following bytes are the bitrate /400
+
+ //read first 16 bytes
+ brate = GetSize( offset );
+ // scale
+ brate <<= 2;
+ byte lasttwo = GetByte( offset + 2 );
+ lasttwo >>= 6;
+ brate |= lasttwo;
+
+ mpeg_info->video[ v_idx ].bitrate = 400 * brate;
+
+ byte mark;
+ while ( true ) {
+ offset = FindNextMarker( offset, &mark );
+ if ( mark == MPEG_GOP_CODE )
+ break;
+ switch ( GetByte( offset + 3 ) ) {
+ case MPEG_EXT_CODE :
+ // Extension
+ offset += 4;
+ switch ( GetByte( offset ) >> 4 ) {
+ case 1:
+ //SequenceExt
+ if ( GetByte( offset + 1 ) & 0x08 )
+ mpeg_info->video[ v_idx ].progressive = true;
+ mpeg_info->video[ v_idx ].chroma_format = ( GetByte( offset + 1 ) & 0x06 ) >> 1;
+ break;
+ case 2:
+ // SequenceDisplayExt
+ mpeg_info->video[ v_idx ].video_format = ( GetByte( offset ) & 0x0E ) >> 1;
+ break;
+ }
+
+ break;
+ case MPEG_USER_CODE :
+ // UserData
+ break;
+ }
+ offset++;
+ }
+
+ mpeg_info->video[ v_idx ].seen = true;
+}
+
+double K3bMpegInfo::ReadTS( llong offset )
+{
+ byte highbit;
+ unsigned long low4Bytes;
+ double TS;
+
+ highbit = ( GetByte( offset ) >> 3 ) & 0x01;
+
+ low4Bytes = ( ( GetByte( offset ) >> 1 ) & 0x03 ) << 30;
+ low4Bytes |= GetByte( offset + 1 ) << 22;
+ low4Bytes |= ( GetByte( offset + 2 ) >> 1 ) << 15;
+ low4Bytes |= GetByte( offset + 3 ) << 7;
+ low4Bytes |= GetByte( offset + 4 ) >> 1;
+
+
+ TS = ( double ) ( highbit * FLOAT_0x10000 * FLOAT_0x10000 );
+ TS += ( double ) ( low4Bytes );
+ TS /= ( double ) ( STD_SYSTEM_CLOCK_FREQ );
+
+ return TS;
+}
+
+double K3bMpegInfo::ReadTSMpeg2( llong offset )
+{
+ byte highbit;
+ unsigned long low4Bytes;
+ unsigned long sys_clock_ref;
+ double TS;
+
+ highbit = ( GetByte( offset ) & 0x20 ) >> 5;
+
+ low4Bytes = ( ( GetByte( offset ) & 0x18 ) >> 3 ) << 30;
+ low4Bytes |= ( GetByte( offset ) & 0x03 ) << 28;
+ low4Bytes |= GetByte( offset + 1 ) << 20;
+ low4Bytes |= ( GetByte( offset + 2 ) & 0xF8 ) << 12;
+ low4Bytes |= ( GetByte( offset + 2 ) & 0x03 ) << 13;
+ low4Bytes |= GetByte( offset + 3 ) << 5;
+ low4Bytes |= ( GetByte( offset + 4 ) ) >> 3;
+
+ sys_clock_ref = ( GetByte( offset + 4 ) & 0x3 ) << 7;
+ sys_clock_ref |= ( GetByte( offset + 5 ) >> 1 );
+
+ TS = ( double ) ( highbit * FLOAT_0x10000 * FLOAT_0x10000 );
+ TS += ( double ) ( low4Bytes );
+ if ( sys_clock_ref == 0 )
+ TS /= ( double ) ( STD_SYSTEM_CLOCK_FREQ );
+ else {
+ TS /= ( double ) ( 27000000 / sys_clock_ref );
+ }
+
+ return TS;
+}
diff --git a/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.h b/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.h
new file mode 100644
index 0000000..3436214
--- /dev/null
+++ b/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.h
@@ -0,0 +1,178 @@
+/*
+*
+* $Id: k3bmpeginfo.h 619556 2007-01-03 17:38:12Z trueg $
+* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org>
+*
+* This file is part of the K3b project.
+* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* See the file "COPYING" for the exact licensing terms.
+*/
+
+#ifndef K3BMPEGINFO
+#define K3BMPEGINFO
+
+#include <stdio.h>
+
+// #define BUFFERSIZE 16384
+#define BUFFERSIZE 65536
+
+#define MPEG_START_CODE_PATTERN ((ulong) 0x00000100)
+#define MPEG_START_CODE_MASK ((ulong) 0xffffff00)
+
+#define MPEG_PICTURE_CODE ((ulong) 0x00000100)
+/* [...slice codes... 0x1a7] */
+
+#define MPEG_USER_CODE ((uchar) 0xb2)
+#define MPEG_SEQUENCE_CODE ((uchar) 0xb3)
+#define MPEG_EXT_CODE ((uchar) 0xb5)
+#define MPEG_SEQ_END_CODE ((uchar) 0xb7)
+#define MPEG_GOP_CODE ((uchar) 0xb8)
+#define MPEG_PROGRAM_END_CODE ((uchar) 0xb9)
+#define MPEG_PACK_HEADER_CODE ((uchar) 0xba)
+#define MPEG_SYSTEM_HEADER_CODE ((uchar) 0xbb)
+#define MPEG_PRIVATE_1_CODE ((uchar) 0xbd)
+#define MPEG_PAD_CODE ((uchar) 0xbe)
+
+#define MPEG_AUDIO_C0_CODE ((uchar) 0xc0) /* default */
+#define MPEG_AUDIO_C1_CODE ((uchar) 0xc1) /* 2nd audio stream id (dual channel) */
+#define MPEG_AUDIO_C2_CODE ((uchar) 0xc2) /* 3rd audio stream id (surround sound) */
+
+#define MPEG_VIDEO_E0_CODE ((uchar) 0xe0) /* motion */
+#define MPEG_VIDEO_E1_CODE ((uchar) 0xe1) /* lowres still */
+#define MPEG_VIDEO_E2_CODE ((uchar) 0xe2) /* hires still */
+
+#define FLOAT_0x10000 (double)((unsigned long)1 << 16)
+#define STD_SYSTEM_CLOCK_FREQ (unsigned long)90000
+
+typedef unsigned char byte;
+typedef long long llong;
+
+#include <kdebug.h>
+
+class video_info
+{
+ public:
+ bool seen;
+ unsigned long hsize;
+ unsigned long vsize;
+ double aratio;
+ double frate;
+ unsigned long bitrate;
+ unsigned long vbvsize;
+ bool progressive;
+ unsigned char video_format;
+ unsigned char chroma_format;
+ bool constrained_flag;
+};
+
+class audio_info
+{
+ public:
+ bool seen;
+ unsigned int version;
+ unsigned int layer;
+ unsigned int protect;
+ unsigned long bitrate;
+ float byterate;
+ unsigned long sampfreq;
+ int mode;
+ bool copyright;
+ bool original;
+};
+
+class Mpeginfo
+{
+
+ public:
+ Mpeginfo()
+ : version( 0 ),
+ muxrate( 0 ),
+ playing_time( 0 ),
+ has_video ( false ),
+ has_audio ( false )
+ {
+ for ( int i = 0; i < 3; i++ ) {
+ video[ i ].seen = false;
+ audio[ i ].seen = false;
+ }
+ };
+
+ ~Mpeginfo()
+ {}
+ ;
+
+ unsigned int version;
+ unsigned long muxrate;
+ double playing_time;
+ bool has_video;
+ bool has_audio;
+ video_info video[ 3 ];
+ audio_info audio[ 3 ];
+};
+
+class K3bMpegInfo
+{
+ public:
+ K3bMpegInfo( const char* filename );
+ ~K3bMpegInfo();
+ enum mpeg_version { MPEG_VERS_INVALID = 0, MPEG_VERS_MPEG1 = 1, MPEG_VERS_MPEG2 = 2 };
+ enum mode { MPEG_STEREO = 1, MPEG_JOINT_STEREO, MPEG_DUAL_CHANNEL, MPEG_SINGLE_CHANNEL };
+
+ const int version()
+ {
+ return mpeg_info->version;
+ };
+ const QString error_string()
+ {
+ return m_error_string;
+ };
+ Mpeginfo* mpeg_info;
+
+
+ private:
+ // General ToolBox
+ byte GetByte( llong offset );
+ byte bdGetByte( llong offset );
+ llong GetNBytes( llong, int );
+ unsigned short int GetSize( llong offset );
+ llong FindNextMarker( llong );
+ llong FindNextMarker( llong, byte* );
+ llong FindNextMarker( llong, byte );
+ llong bdFindNextMarker( llong, byte );
+ llong bdFindNextMarker( llong, byte* );
+ llong FindNextVideo( llong );
+ llong FindNextAudio( llong );
+
+ int GetVideoIdx ( byte );
+ int GetAudioIdx ( byte );
+ bool EnsureMPEG( llong, byte );
+ void ParseVideo ( llong, byte );
+ void ParseAudio ( llong, byte );
+ bool MpegParsePacket ();
+ llong MpegParsePacket ( llong );
+ llong SkipPacketHeader( llong );
+
+ double ReadTS( llong offset );
+ double ReadTSMpeg2( llong offset );
+
+ FILE* m_mpegfile;
+
+ const char* m_filename;
+ llong m_filesize;
+
+ bool m_done;
+
+ llong m_buffstart;
+ llong m_buffend;
+ byte* m_buffer;
+ double m_initial_TS;
+ QString m_error_string;
+
+};
+
+#endif //K3bMpegInfo