[Matroska-cvs] [matroska] r1292 - in trunk/DvdMenuXtractor/dmx: . vobparser vobparser/iso

smssms at matroska.org smssms at matroska.org
Sat Mar 10 22:46:31 CET 2007


Author: smssms
Date: 2007-03-11 00:46:03 +0300 (Sun, 11 Mar 2007)
New Revision: 1292

Added:
   trunk/DvdMenuXtractor/dmx/vobparser/
   trunk/DvdMenuXtractor/dmx/vobparser/IFOContent.cpp
   trunk/DvdMenuXtractor/dmx/vobparser/IFOContent.h
   trunk/DvdMenuXtractor/dmx/vobparser/IFOFile.cpp
   trunk/DvdMenuXtractor/dmx/vobparser/IFOFile.h
   trunk/DvdMenuXtractor/dmx/vobparser/VobParser.cpp
   trunk/DvdMenuXtractor/dmx/vobparser/VobParser.h
   trunk/DvdMenuXtractor/dmx/vobparser/iso/
   trunk/DvdMenuXtractor/dmx/vobparser/iso/iso-639.def
   trunk/DvdMenuXtractor/dmx/vobparser/iso/iso_lang.c
   trunk/DvdMenuXtractor/dmx/vobparser/iso/iso_lang.h
   trunk/DvdMenuXtractor/dmx/vobparser/vobparser.proj
Log:


Added: trunk/DvdMenuXtractor/dmx/vobparser/IFOContent.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/DvdMenuXtractor/dmx/vobparser/IFOContent.cpp	2007-03-10 21:45:2=
8 UTC (rev 1291)
+++ trunk/DvdMenuXtractor/dmx/vobparser/IFOContent.cpp	2007-03-10 21:46:0=
3 UTC (rev 1292)
@@ -0,0 +1,273 @@
+// ---------------------------------------------------------------------=
-------
+#include "IFOContent.h"
+// ---------------------------------------------------------------------=
-------
+// Macro to convert Binary Coded Decimal to Decimal
+#define BCD2D(__x__) (((__x__ & 0xf0) >> 4) * 10 + (__x__ & 0x0f))
+// ---------------------------------------------------------------------=
-------
+int dvdtime2frame(dvd_time_t* dtime, double & frame_dur)
+{
+	double frame_rate;
+	double result =3D 0.0;
+	assert((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa);
+	assert((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa);
+	assert((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa);
+	assert((dtime->frame_u&0xf) < 0xa);
+
+	int hh, min, sec, ff;
+	hh =3D BCD2D(dtime->hour);
+	min =3D BCD2D(dtime->minute);
+	sec =3D BCD2D(dtime->second);
+	ff =3D BCD2D(dtime->frame_u & 0x3f);
+
+	frame_rate =3D ((dtime->frame_u & 0xc0) >> 6) =3D=3D 1 ? 25.0 : (30000.=
0/1001.0);
+	result =3D (((((hh * 60) + min) * 60) + sec) * frame_rate) + (ff & 0x3f=
);
+	frame_dur =3D 1000.0 / frame_rate;
+
+	return (int)result;
+}
+// ---------------------------------------------------------------------=
-------
+IFOContent::IFOContent(dvd_reader_t *dvdr, int16_t title)
+	:m_title(title)
+{
+	m_handle =3D ifoOpen(dvdr, title);
+	if (!m_handle)
+		throw IFOInvalidFileFormatException();
+
+	CellsHashType CellsHash;
+
+	if (title =3D=3D 0)
+	{
+		if (m_handle->vmgi_mat)
+		{
+			const vmgi_mat_t &vmgi_mat =3D *m_handle->vmgi_mat;
+			if (vmgi_mat.nr_of_vmgm_audio_streams)
+				m_langAudio.push_back(&vmgi_mat.vmgm_audio_attr);
+			if (vmgi_mat.nr_of_vmgm_subp_streams)
+				m_langSubs.push_back(&vmgi_mat.vmgm_subp_attr);
+		}
+
+		if (m_handle->pgci_ut && m_handle->menu_c_adt)
+		{
+			// add each cell in a list
+			// order this list according to vob ID, cell ID
+			// for each cell, find the duration (and start time) from all menu PG=
Cs
+			for(uint16_t i =3D 0; i < m_handle->pgci_ut->nr_of_lus; i++)
+			{
+				pgci_lu_t& lu =3D m_handle->pgci_ut->lu[i];
+				GetPGCCells(*lu.pgcit, *m_handle->menu_c_adt, &CellsHash);
+			}
+
+			// Transfer hash map to the list to be sorted
+			m_langCellsList.clear();
+		=09
+			for(CellsHashType::iterator it =3D CellsHash.begin(); it !=3D CellsHa=
sh.end(); ++it )
+			{
+				m_langCellsList.append(it.value());
+			}
+
+			m_langCellsList.arrange();
+		}
+	}
+	else
+	{
+		if (m_handle->vtsi_mat)
+		{
+			const vtsi_mat_t & vtsi_mat =3D *m_handle->vtsi_mat;
+			if (vtsi_mat.nr_of_vtsm_audio_streams)
+				m_langAudio.push_back(&vtsi_mat.vtsm_audio_attr);
+			if (vtsi_mat.nr_of_vtsm_subp_streams)
+				m_langSubs.push_back(&vtsi_mat.vtsm_subp_attr);
+
+			uint8_t _stream;
+			for (_stream=3D0; _stream < vtsi_mat.nr_of_vts_audio_streams; _stream=
++)
+				m_Audio.push_back(&vtsi_mat.vts_audio_attr[_stream]);
+			for (_stream=3D0; _stream < vtsi_mat.nr_of_vts_subp_streams; _stream+=
+)
+				m_Subs.push_back(&vtsi_mat.vts_subp_attr[_stream]);
+		}
+
+		// handle the list of menu cells with their ID and sectors
+		CellsHash.clear();
+		if (m_handle->pgci_ut && m_handle->menu_c_adt)
+		{
+			// add each cell in a list
+			// order this list according to vob ID, cell ID
+			// for each cell, find the duration (and start time) from all menu PG=
Cs
+			for(int i =3D 0; i < m_handle->pgci_ut->nr_of_lus; i++)
+			{
+				pgci_lu_t& lu =3D m_handle->pgci_ut->lu[i];
+				GetPGCCells(*lu.pgcit, *m_handle->menu_c_adt, &CellsHash);
+			}
+
+			// Transfer hash map to the list to be sorted
+			m_langCellsList.clear();
+			CellsHashType::iterator it;
+			for( it =3D CellsHash.begin(); it !=3D CellsHash.end(); ++it )
+			{
+				m_langCellsList.append(it.value());
+			}
+
+			m_langCellsList.arrange();
+		}
+
+		// handle the list of cells with their ID and sectors
+		CellsHash.clear();
+		if (m_handle->vts_pgcit && m_handle->vts_c_adt)
+		{
+			// add each cell in a list
+			// order this list according to vob ID, cell ID
+			// for each cell, find the duration (and start time) from all PGCs
+			GetPGCCells(*m_handle->vts_pgcit, *m_handle->vts_c_adt, &CellsHash);
+
+			// Transfer hash map to the list to be sorted
+			m_CellsList.clear();
+		=09
+			for(CellsHashType::iterator it =3D CellsHash.begin(); it !=3D CellsHa=
sh.end(); ++it )
+			{
+				m_CellsList.append(it.value());
+			}
+
+			m_CellsList.arrange();
+		}
+	}
+}
+// ---------------------------------------------------------------------=
-------
+void IFOContent::GetPGCCells(const pgcit_t & pgcit, const c_adt_t & adt,=
 CellsHashType * CellsHash)
+{
+	CellListElem* cle;
+
+	for(int j=3D0; j < pgcit.nr_of_pgci_srp; j++)
+	{
+		pgci_srp_t& srp =3D pgcit.pgci_srp[j];
+		for(int k=3D0; k < srp.pgc->nr_of_cells; k++)
+		{
+			uint16_t vob_id =3D srp.pgc->cell_position[k].vob_id_nr;
+			uint8_t cell_id =3D srp.pgc->cell_position[k].cell_nr;
+
+			if (CellsHash->find(MAKE_CELLS_KEY(vob_id, cell_id)) =3D=3D CellsHash=
->end())
+			{
+				size_t cell_nr =3D adt.last_byte;
+				cell_nr -=3D 7;
+				cell_nr /=3D sizeof(cell_adr_t);
+				for (size_t l=3D0; l < cell_nr; l++)
+				{
+					if (adt.cell_adr_table[l].vob_id =3D=3D vob_id && adt.cell_adr_tabl=
e[l].cell_id =3D=3D cell_id)
+					{
+						cle =3D new CellListElem();
+						(*CellsHash)[MAKE_CELLS_KEY(vob_id, cell_id)] =3D cle;
+
+						cle->vobid =3D vob_id;
+						cle->cellid =3D cell_id;
+
+						cle->start_sector =3D adt.cell_adr_table[l].start_sector;
+						cle->last_sector =3D adt.cell_adr_table[l].last_sector;
+						cle->selected =3D true; // all cells selected for the moment
+						cle->found =3D false;
+						/* debug	* /			cle->found =3D true;*/
+
+						cle->nb_frames =3D dvdtime2frame(&srp.pgc->cell_playback[k].playba=
ck_time, cle->frame_dur);
+						cle->isStill =3D (srp.pgc->cell_playback[k].still_time > 0);
+						if (cle->isStill)
+						{
+							if (srp.pgc->cell_playback[k].still_time =3D=3D 0xFF) {
+							  qWarning(qPrintable(QString("Still cell (%1.%2) detected with i=
nfinite duration !").arg(vob_id).arg(cell_id)));
+							} else {
+							  qWarning(qPrintable(QString("Still cell (%1.%2) detected. Assum=
ing there is just one frame.").arg(vob_id).arg(cell_id)));
+								cle->nb_frames =3D 1; // maybe not true ?
+								cle->frame_dur =3D srp.pgc->cell_playback[k].still_time * 1000.0=
 / cle->nb_frames;
+							}
+						}
+						break;
+					}
+				}
+			}
+		}
+	}
+}
+// ---------------------------------------------------------------------=
-------
+uint8_t IFOContent::FindAudioStream(uint8_t streamID, bool menu) const
+{
+	assert(m_handle !=3D NULL);
+	if (menu)
+	{
+		if (m_handle->pgci_ut)
+		{
+			for (int i=3D0; i<m_handle->pgci_ut->nr_of_lus; i++)
+			{
+				pgci_lu_t &_lu =3D m_handle->pgci_ut->lu[i];
+				for (int j=3D0; j < _lu.pgcit->nr_of_pgci_srp; j++)
+				{
+					pgc_t *_pgc =3D _lu.pgcit->pgci_srp[j].pgc;
+					if(_pgc->audio_control[streamID] & 0x8000) // if present
+						return (_pgc->audio_control[streamID] >> 8) & 0x7F;
+				}
+			}
+		}
+	}
+	else
+	{
+		if (m_handle->vts_pgcit)
+		{
+			for (int j=3D0; j < m_handle->vts_pgcit->nr_of_pgci_srp; j++)
+			{
+				pgc_t *_pgc =3D m_handle->vts_pgcit->pgci_srp[j].pgc;
+				if(_pgc->audio_control[streamID] & 0x8000) // if present
+					return (_pgc->audio_control[streamID] >> 8) & 0x7F;
+			}
+		}
+	}
+	return streamID;
+}
+// ---------------------------------------------------------------------=
-------
+IdArray IFOContent::FindSubStream(uint8_t streamID, bool menu) const
+{
+	IdArray result;
+
+	assert(m_handle !=3D NULL);
+	if (menu)
+	{
+		if (m_handle->pgci_ut)
+		{
+			for (int i=3D0; i<m_handle->pgci_ut->nr_of_lus; i++)
+			{
+				pgci_lu_t &_lu =3D m_handle->pgci_ut->lu[i];
+				for (int j=3D0; j < _lu.pgcit->nr_of_pgci_srp; j++)
+				{
+					pgc_t *_pgc =3D _lu.pgcit->pgci_srp[j].pgc;
+					if(_pgc->subp_control[streamID] & 0x80000000) // if present
+					{
+						result.push_back( _pgc->subp_control[streamID] >> 24 & 0x7F);
+						if (_pgc->subp_control[streamID] & 0x007F0000)
+							result.push_back( _pgc->subp_control[streamID] >> 16 & 0x7F);
+						if (_pgc->subp_control[streamID] & 0x00007F00)
+							result.push_back( _pgc->subp_control[streamID] >>  8 & 0x7F);
+						if (_pgc->subp_control[streamID] & 0x0000007F)
+							result.push_back( _pgc->subp_control[streamID] >>  0 & 0x7F);
+					}
+				}
+			}
+		}
+	}
+	else
+	{
+		if (m_handle->vts_pgcit)
+		{
+			for (int j=3D0; j < m_handle->vts_pgcit->nr_of_pgci_srp; j++)
+			{
+				pgc_t *_pgc =3D m_handle->vts_pgcit->pgci_srp[j].pgc;
+				if(_pgc->subp_control[streamID] & 0x80000000) // if present
+				{
+					result.push_back( _pgc->subp_control[streamID] >> 24 & 0x7F);
+					if (_pgc->subp_control[streamID] & 0x007F0000)
+						result.push_back( _pgc->subp_control[streamID] >> 16 & 0x7F);
+					if (_pgc->subp_control[streamID] & 0x00007F00)
+						result.push_back( _pgc->subp_control[streamID] >>  8 & 0x7F);
+					if (_pgc->subp_control[streamID] & 0x0000007F)
+						result.push_back( _pgc->subp_control[streamID] >>  0 & 0x7F);
+				}
+			}
+		}
+	}
+
+	return result;
+}
+// ---------------------------------------------------------------------=
-------

Added: trunk/DvdMenuXtractor/dmx/vobparser/IFOContent.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/DvdMenuXtractor/dmx/vobparser/IFOContent.h	2007-03-10 21:45:28 =
UTC (rev 1291)
+++ trunk/DvdMenuXtractor/dmx/vobparser/IFOContent.h	2007-03-10 21:46:03 =
UTC (rev 1292)
@@ -0,0 +1,71 @@
+// ---------------------------------------------------------------------=
-------
+#ifndef _IFO_CONTENT_H_
+#define _IFO_CONTENT_H_
+// ---------------------------------------------------------------------=
-------
+#include <QHash>
+#include <vector>
+
+#include "VobParser.h"
+#include "dvdread/ifo_read.h"
+// ---------------------------------------------------------------------=
-------
+typedef std::vector<uint8_t> IdArray;
+
+typedef QHash<int, CellListElem *> CellsHashType;
+typedef std::vector<const audio_attr_t*> AudioTrackList;
+typedef std::vector<const subp_attr_t*> SubtitleTrackList;
+
+#define MAKE_CELLS_KEY(vob_id,cell_id)  ((vob_id << 8) | cell_id)
+// ---------------------------------------------------------------------=
-------
+class IFOException { };
+class IFOFileIOException : public IFOException { };
+class IFOInvalidFileFormatException : public IFOException { };
+// ---------------------------------------------------------------------=
-------
+typedef QList<CellListElem*> CellsListBaseType;
+class CellsListType : public CellsListBaseType
+{
+public:
+	void arrange();
+	CellListElem* at(uint16_t vob_id, uint8_t cell_id) const;
+	const CellListElem* at(const cell_position_t & position) const;
+
+	// comperator for qSort()
+	static int cellListElemCompare(const CellListElem *arg1, const CellList=
Elem *arg2);
+};
+// ---------------------------------------------------------------------=
-------
+class IFOContent=20
+{
+public:
+	IFOContent(dvd_reader_t *dvdr, int16_t title);
+
+	~IFOContent()
+	{
+		ifoClose(m_handle);
+		m_CellsList.clear();
+		m_langCellsList.clear();
+	}
+
+	ifo_handle_t& Handle()
+	{
+		assert(m_handle !=3D NULL);
+		return *m_handle;
+	}
+
+	IdArray FindSubStream(uint8_t streamID, bool menu) const;
+	uint8_t FindAudioStream(uint8_t streamID, bool menu) const;
+=09
+	void GetPGCCells(const pgcit_t & pgcit, const c_adt_t & adt, CellsHashT=
ype * CellsHash);
+
+	int16_t m_title;
+	AudioTrackList m_langAudio;
+	AudioTrackList m_Audio;
+	SubtitleTrackList m_langSubs;
+	SubtitleTrackList m_Subs;
+	CellsListType m_CellsList;
+	CellsListType m_langCellsList;
+
+protected:
+	ifo_handle_t *m_handle;
+};
+// ---------------------------------------------------------------------=
-------
+#endif
+// ---------------------------------------------------------------------=
-------

Added: trunk/DvdMenuXtractor/dmx/vobparser/IFOFile.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/DvdMenuXtractor/dmx/vobparser/IFOFile.cpp	2007-03-10 21:45:28 U=
TC (rev 1291)
+++ trunk/DvdMenuXtractor/dmx/vobparser/IFOFile.cpp	2007-03-10 21:46:03 U=
TC (rev 1292)
@@ -0,0 +1,300 @@
+// ---------------------------------------------------------------------=
-------
+#include "IFOFile.h"
+#include "iso/iso_lang.h"
+#include "dvdread/ifo_print.h"
+// ---------------------------------------------------------------------=
-------
+IFOFile::IFOFile(const QString& filename)
+{=09
+	m_dvd =3D DVDOpen(QFile::encodeName(filename));
+=09
+	if(!m_dvd) {
+		throw IFOInvalidFileFormatException();
+	}
+
+	try {
+		m_ifos.append(new IFOContent(m_dvd, 0));	=09
+	}
+	catch (...)	{
+		qCritical("Cannot open VIDEO_TS.IFO.");
+		throw;
+	}
+
+	IFOContent *_ifo =3D m_ifos.getIfoContent(0);
+
+	if (_ifo && _ifo->Handle().vmgi_mat)
+	{
+		for (int i =3D 1; i <=3D _ifo->Handle().vmgi_mat->vmg_nr_of_title_sets=
; i++)
+		{
+			try {
+				m_ifos.append(new IFOContent(m_dvd,i));
+			}
+			catch (...)	{
+			  qCritical(qPrintable(QString("Cannot open VTS_%1_X.IFO").arg(i)));
+			}
+		}
+	}
+}
+// ---------------------------------------------------------------------=
-------
+IFOFile::~IFOFile()
+{
+	for (int i =3D 0; i < m_ifos.size(); i++)
+		delete m_ifos.at(i);
+=09
+	if (m_dvd)
+	{
+		DVDClose(m_dvd);
+	}
+}
+// ---------------------------------------------------------------------=
-------
+const pgc_t *IFOFile::FirstPlayPGC() const
+{
+	if (m_ifos.at(0))
+		return m_ifos.at(0)->Handle().first_play_pgc;
+	else
+		return NULL;
+}
+// ---------------------------------------------------------------------=
-------
+const tt_srpt_t *IFOFile::TitleMap() const
+{
+	if (m_ifos.at(0))
+		return m_ifos.at(0)->Handle().tt_srpt;
+	else
+		return NULL;
+}
+// ---------------------------------------------------------------------=
-------
+const pgci_ut_t *IFOFile::LanguageUnits(unsigned int title) const
+{
+	IFOContent *_ifo =3D m_ifos.getIfoContent(title);
+=09
+	if (_ifo)
+		return _ifo->Handle().pgci_ut;
+	=09
+	return NULL;
+}
+// ---------------------------------------------------------------------=
-------
+const vts_ptt_srpt_t *IFOFile::VtsTitles(unsigned int title) const
+{
+	IFOContent *_ifo =3D m_ifos.getIfoContent(title);
+	if (_ifo)
+	{
+		return _ifo->Handle().vts_ptt_srpt;
+	}
+	return NULL;
+}
+// ---------------------------------------------------------------------=
-------
+const pgcit_t *IFOFile::VtsPGCs(unsigned int title) const
+{
+	IFOContent *_ifo =3D m_ifos.getIfoContent(title);
+	if (_ifo)
+	{
+		return _ifo->Handle().vts_pgcit;
+	}
+	return NULL;
+}
+// ---------------------------------------------------------------------=
-------
+const int16_t IFOFile::NumberOfTitles() const
+{
+	if (m_ifos.count() && m_ifos.at(0)->Handle().vmgi_mat)
+		return m_ifos.at(0)->Handle().vmgi_mat->vmg_nr_of_title_sets;
+	return 0;
+}
+// ---------------------------------------------------------------------=
-------
+int CellsListType::cellListElemCompare(const CellListElem *arg1, const C=
ellListElem *arg2)
+{
+	const CellListElem* cle1 =3D arg1;
+	const CellListElem* cle2 =3D arg2;
+
+	return (cle1->vobid > cle2->vobid) ? 1 :
+		(cle1->vobid < cle2->vobid) ? -1 :
+			(cle1->cellid > cle2->cellid) ? 1 :=20
+				(cle1->cellid < cle2->cellid) ? -1 :
+					0;
+}
+// ---------------------------------------------------------------------=
-------
+const CellsListType* IFOFile::GetCellsList(unsigned int title, bool menu=
)
+{
+	CellsHashType CellsHash;
+
+	IFOContent *ifoc =3D m_ifos.getIfoContent(title);
+	if (!ifoc)
+		return NULL;
+
+	if (menu)
+		return &ifoc->m_langCellsList;
+	else
+		return &ifoc->m_CellsList;
+}
+// ---------------------------------------------------------------------=
-------
+const AudioTrackList & IFOFile::AudioTracks(unsigned int title, bool men=
u) const
+{
+	IFOContent *_ifo =3D m_ifos.getIfoContent(title);
+	if (!_ifo)
+		throw;
+
+	if (menu)
+		return _ifo->m_langAudio;
+	else
+		return _ifo->m_Audio;
+}
+// ---------------------------------------------------------------------=
-------
+const SubtitleTrackList & IFOFile::SubsTracks(unsigned int title, bool m=
enu) const
+{
+	IFOContent *_ifo =3D m_ifos.getIfoContent(title);
+	if (!_ifo)
+		throw;
+
+	if (menu)
+		return _ifo->m_langSubs;
+	else
+		return _ifo->m_Subs;
+}
+// ---------------------------------------------------------------------=
-------
+const CellsListType & IFOFile::CellsList(unsigned int title, bool menu) =
const
+{
+	IFOContent *_ifo =3D m_ifos.getIfoContent(title);
+	if (!_ifo)
+		throw;
+
+	if (menu)
+		return _ifo->m_langCellsList;
+	else
+		return _ifo->m_CellsList;
+}
+// ---------------------------------------------------------------------=
-------
+bool IFOFile::VideoSize(unsigned int title, bool menu, uint16_t & width,=
 uint16_t & height, double & fps) const
+{
+	IFOContent *_ifo =3D m_ifos.getIfoContent(title);
+	assert(_ifo !=3D NULL);
+	video_attr_t *_attr =3D NULL;
+	if (menu)
+	{
+		if (title =3D=3D 0)
+		{
+			if (_ifo->Handle().vmgi_mat)
+			{
+				_attr =3D &_ifo->Handle().vmgi_mat->vmgm_video_attr;
+			}
+		}
+		else
+		{
+			if (_ifo->Handle().vtsi_mat)
+			{
+				_attr =3D &_ifo->Handle().vtsi_mat->vtsm_video_attr;
+			}
+		}
+	}
+	else
+	{
+		if (_ifo->Handle().vtsi_mat)
+		{
+			_attr =3D &_ifo->Handle().vtsi_mat->vts_video_attr;
+		}
+	}
+
+	if (_attr !=3D NULL)
+	{
+		height =3D 480;
+		if(_attr->video_format !=3D 0) {
+			fps =3D 25.0;
+			height =3D 576;
+		} else {
+			fps =3D 30000.0/1001.0;
+		}
+		switch(_attr->picture_size) {
+			case 0:
+				width =3D 720;
+				break;
+			case 1:
+				width =3D 704;
+				break;
+			case 2:
+				width =3D 352;
+				break;
+			case 3:
+				width =3D 352;
+				height >>=3D 1;
+			break;     =20
+		}
+		return true;
+	}
+	return false;
+}
+// ---------------------------------------------------------------------=
-------
+const uint32_t * IFOFile::GetPalette(unsigned int title, bool menu) cons=
t
+{
+	IFOContent *_ifo =3D m_ifos.getIfoContent(title);
+	assert(_ifo !=3D NULL);
+=09
+	if (menu)
+		return (_ifo->Handle().pgci_ut->lu->pgcit->pgci_srp->pgc->palette);
+=09
+	return (_ifo->Handle().vts_pgcit->pgci_srp->pgc->palette);
+}
+// ---------------------------------------------------------------------=
-------
+uint8_t IFOFile::GetAudioId(uint8_t streamID, uint8_t title, bool menu) =
const
+{
+	IFOContent *_ifo =3D m_ifos.getIfoContent(title);
+	if (!_ifo)
+		throw;
+
+	return _ifo->FindAudioStream(streamID, menu);
+}
+// ---------------------------------------------------------------------=
-------
+IdArray IFOFile::GetSubsId(uint8_t streamID, uint8_t title, bool menu) c=
onst
+{
+	IFOContent *_ifo =3D m_ifos.getIfoContent(title);
+	if (!_ifo)
+		throw;
+
+	return _ifo->FindSubStream(streamID, menu);
+}
+// ---------------------------------------------------------------------=
-------
+IFOContent * IfoHandleList::getIfoContent(int16_t title) const
+{
+	for (size_type _index =3D 0; _index < size(); _index++)
+	{
+		if (at(_index)->m_title =3D=3D title)
+			return at(_index);
+	}
+	return NULL;
+}
+// ---------------------------------------------------------------------=
-------
+const CellListElem* CellsListType::at(const cell_position_t & position) =
const
+{
+	return at(position.vob_id_nr, position.cell_nr);
+}
+// ---------------------------------------------------------------------=
-------
+CellListElem* CellsListType::at(uint16_t vob_id, uint8_t cell_id) const
+{
+	CellsListType::const_iterator node =3D begin();
+	while (node !=3D end())
+	{
+		CellListElem *cell =3D *node;
+	=09
+		if (cell->cellid =3D=3D cell_id && cell->vobid =3D=3D vob_id)
+			return cell;
+	=09
+		++node;
+	}
+=09
+	return NULL;
+}
+// ---------------------------------------------------------------------=
-------
+void CellsListType::arrange()
+{
+	qSort(begin(), end(), &CellsListType::cellListElemCompare);
+
+	// make the timecodes continuous
+	int64_t timecode =3D 0;
+	CellsListType::const_iterator node =3D begin();
+	while (node !=3D end())
+	{
+		CellListElem *cell =3D *node;
+		cell->start_time =3D timecode;
+		cell->duration =3D int64_t(cell->frame_dur * cell->nb_frames * 1000000=
.0);
+		if (cell->found)
+			timecode +=3D cell->duration;
+		++node;
+	}
+}
+// ---------------------------------------------------------------------=
-------

Added: trunk/DvdMenuXtractor/dmx/vobparser/IFOFile.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/DvdMenuXtractor/dmx/vobparser/IFOFile.h	2007-03-10 21:45:28 UTC=
 (rev 1291)
+++ trunk/DvdMenuXtractor/dmx/vobparser/IFOFile.h	2007-03-10 21:46:03 UTC=
 (rev 1292)
@@ -0,0 +1,43 @@
+// ---------------------------------------------------------------------=
-------
+#ifndef _IFO_FILE_H_
+#define _IFO_FILE_H_
+// ---------------------------------------------------------------------=
-------
+#include <QStringList>
+
+#include "IFOContent.h"
+// ---------------------------------------------------------------------=
-------
+class IfoHandleList: public QList<IFOContent*>
+{
+public:
+	/// look for IfoContent corresponding to the title
+	IFOContent* getIfoContent(int16_t title) const;
+};
+// ---------------------------------------------------------------------=
-------
+class IFOFile =20
+{
+public:
+	IFOFile(const QString& filename);
+	const CellsListType* GetCellsList(unsigned int title, bool menu);
+	virtual ~IFOFile();
+	const pgc_t *FirstPlayPGC() const;
+	const tt_srpt_t *TitleMap() const;
+	const pgci_ut_t *LanguageUnits(unsigned int title) const;
+	const vts_ptt_srpt_t *VtsTitles(unsigned int title) const;
+	const pgcit_t *VtsPGCs(unsigned int title) const;
+	const int16_t NumberOfTitles() const;
+	const AudioTrackList & AudioTracks(unsigned int title, bool menu) const=
;
+	const SubtitleTrackList & SubsTracks(unsigned int title, bool menu) con=
st;
+	const CellsListType & CellsList(unsigned int title, bool menu) const;
+	bool VideoSize(unsigned int title, bool menu, uint16_t & width, uint16_=
t & height, double & fps) const;
+	const uint32_t * GetPalette(unsigned int title, bool menu) const;
+
+	uint8_t GetAudioId(uint8_t streamID, uint8_t title, bool menu) const;
+	IdArray GetSubsId(uint8_t streamID, uint8_t title, bool menu) const;
+
+private:
+	IfoHandleList m_ifos;
+	dvd_reader_t* m_dvd;
+};
+// ---------------------------------------------------------------------=
-------
+#endif
+// ---------------------------------------------------------------------=
-------

Added: trunk/DvdMenuXtractor/dmx/vobparser/VobParser.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/DvdMenuXtractor/dmx/vobparser/VobParser.cpp	2007-03-10 21:45:28=
 UTC (rev 1291)
+++ trunk/DvdMenuXtractor/dmx/vobparser/VobParser.cpp	2007-03-10 21:46:03=
 UTC (rev 1292)
@@ -0,0 +1,1351 @@
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+// VOBParser class
+// Copyright =A9 2002 : Christophe PARIS (christophe.paris at free.fr)
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+
+#include <QFileInfo>
+
+#include "IFOFile.h"
+#include "VobParser.h"
+#include "iso/iso_lang.h"
+
+// ---------------------------------------------------------------------=
-------
+
+#define VOB_SLICE			0x00000100
+#define PACK_HEADER			0xBA
+#define SYSTEM_HEADER		0xBB
+#define PROGRAM_STREAM_MAP	0xBC
+#define PRIVATE_STREAM1		0xBD
+#define PADDING_STREAM		0xBE
+#define PRIVATE_STREAM2		0xBF
+#define CURRENT_OFFSET		(m_pktindex * DVD_VIDEO_LB_LEN + m_index)
+
+#define INDENT_UNIT 2
+unsigned int indent_lvl =3D 0;
+inline void inc_lvl() { indent_lvl +=3D INDENT_UNIT; }
+inline void dec_lvl() { indent_lvl -=3D INDENT_UNIT; }
+void debug (const QString& str)
+{
+	QString debugStr (indent_lvl, ' ');
+	debugStr +=3D str;
+	qDebug(qPrintable(debugStr));
+}
+
+// ---------------------------------------------------------------------=
-------
+// CompositeDemuxWriter
+// ---------------------------------------------------------------------=
-------
+
+CompositeDemuxWriter::CompositeDemuxWriter()
+{
+	for (int i=3D0; i<256; i++)
+		m_muxers[i] =3D NULL;
+}
+
+CompositeDemuxWriter::~CompositeDemuxWriter()
+{
+	Reset();
+}
+
+bool CompositeDemuxWriter::AddDemuxer(uint8_t streamID, Writer * demuxer=
, QString& CommandLine)
+{
+	if (m_muxers[streamID] !=3D NULL)
+		return false;
+	m_muxers[streamID] =3D demuxer;
+	m_strings[streamID] =3D CommandLine;
+	return true;
+}
+
+void CompositeDemuxWriter::ProcessStream(int streamID, uint8_t* buff, ui=
nt32_t size, int32_t start_time, int32_t end_time, const QString& debug)
+{
+	if (m_muxers[streamID] !=3D NULL)
+		m_muxers[streamID]->ProcessStream(buff, size, start_time, end_time, de=
bug);
+}
+
+void CompositeDemuxWriter::Reset()
+{
+	for (int i=3D0; i<256; i++)
+	{
+		if (m_muxers[i] !=3D NULL)
+		{
+			delete m_muxers[i];
+			m_muxers[i] =3D NULL;
+		}
+	}
+}
+
+void CompositeDemuxWriter::SetBoundary(uint32_t start_timecode, uint32_t=
 duration, const CellListElem *cell)
+{
+	for (int i=3D0; i<256; i++)
+	{
+		if (m_muxers[i] !=3D NULL)
+		{
+			m_muxers[i]->SetBoundary(start_timecode, duration, cell);
+		}
+	}
+}
+
+// ---------------------------------------------------------------------=
-------
+
+VobParser::VobParser(const char* dirname, int16_t title, bool menu)
+	:m_title(title)
+	,m_dvdhandle(NULL)
+	,m_stream(NULL)
+	,m_language(menu)
+	,m_bFirstPacket(true)
+{
+	m_pktcount =3D 0;
+
+	QFileInfo _tmpDirName(dirname);
+
+	// handle all parts of this title (VIDEO_TS.vob or VTS_XX_Y.vob)
+	m_dvdhandle =3D DVDOpen(QFile::encodeName(_tmpDirName.canonicalPath()))=
;
+
+	if (m_dvdhandle)
+	{
+		if (m_language)
+			m_stream =3D DVDOpenFile(m_dvdhandle, title, DVD_READ_MENU_VOBS);
+		else
+			m_stream =3D DVDOpenFile(m_dvdhandle, title, DVD_READ_TITLE_VOBS);
+	}
+
+	if(!m_stream)
+	{
+		throw VobParserFileNotFoundException(dirname);
+	}
+	else
+	{
+		m_pktcount =3D DVDFileSize(m_stream);
+	}
+
+	Reset();
+}
+
+// ---------------------------------------------------------------------=
-------
+
+VobParser::~VobParser()
+{
+	if (m_stream)
+		DVDCloseFile(m_stream);
+
+	if (m_dvdhandle)
+		DVDClose(m_dvdhandle);
+}
+
+// ---------------------------------------------------------------------=
-------
+
+uint32_t VobParser::GetPacketCount() const
+{
+	return m_pktcount;
+}
+
+// ---------------------------------------------------------------------=
-------
+
+uint32_t VobParser::GetPacketIndex() const
+{
+	return m_pktindex;
+}
+
+// ---------------------------------------------------------------------=
-------
+
+char* VobParser::GetCurrentPacketData() const
+{
+	return (char*)m_buff;
+}
+
+// ---------------------------------------------------------------------=
-------
+
+bool VobParser::ParseNextPacket(const CellsListType & Cells)
+{
+	if(GetNextPacket())
+	{=09
+		pktinfo.identifier =3D GetNext32Bits();
+		if((pktinfo.identifier & VOB_SLICE) !=3D VOB_SLICE || (pktinfo.identif=
ier & PACK_HEADER) !=3D PACK_HEADER)
+		{
+			// Invalid block start code
+			throw VobParserInvalidPacketException(CURRENT_OFFSET-4);
+		}
+	=09
+		ParseSCR(); // System Clock Reference
+
+		// Program Mux Rate (measured in units of 50 bytes/second)
+		pktinfo.program_mux_rate =3D (GetNext8Bits() << 14) |=20
+			(GetNext8Bits() << 6) | (GetNext8Bits() >> 2);
+
+		// Skip Pack stuffing length
+		int stuffing_nb =3D GetNext8Bits() & 0x07;
+		SkipNBytes(stuffing_nb);
+	=09
+		uint32_t _Header =3D GetNext32Bits();
+		int _StreamID;
+		if ((_Header & VOB_SLICE) =3D=3D VOB_SLICE)
+		{
+			_StreamID =3D _Header & 0xFF;
+			if (_StreamID =3D=3D SYSTEM_HEADER)
+			{
+				// skip the system header data
+				uint16_t _size =3D GetNext16Bits();
+				SkipNBytes(_size);
+
+				while (AvailablePacketData())
+				{
+					_Header =3D GetNext32Bits();
+					uint8_t _StreamId =3D _Header & 0xFF;
+					if (_StreamId =3D=3D PRIVATE_STREAM2)
+					{
+						debug("Navigation pack {\n");
+						inc_lvl();
+						debug(QString("SCR: %1.%2\n").arg(pktinfo.scr).arg(pktinfo.scr_ext=
));
+						debug(QString("Program mux rate: %1 (%2 bps)\n").arg(pktinfo.progr=
am_mux_rate).arg(pktinfo.program_mux_rate * 50 * 8));
+						ParseNavPacket();
+						dec_lvl();
+						debug("}\n");
+					}
+					else
+					{
+						// skip these data
+						uint16_t _size =3D GetNext16Bits();
+						SkipNBytes(_size);
+					}
+				}
+				if (IsNewCell()) {
+					CellListElem* cell =3D Cells.at(GetVobID(), GetCellID());
+
+					if (cell !=3D NULL)
+					{
+						cell->found =3D true;
+						if (m_dsi.nv_pck_scr =3D=3D 0)
+							m_pci_vob_timecode_offset =3D m_pci.vobu_s_ptm / 90;
+						m_demuxer.SetBoundary(m_pci.vobu_s_ptm/90 - m_pci_vob_timecode_off=
set, cell->nb_frames * cell->frame_dur, cell);
+					}
+				}
+				if (m_pci.btn_ns !=3D 0)
+				{ // there are some buttons
+					uint32_t t3 =3D m_pci.vobu_s_ptm/90 - m_pci_vob_timecode_offset;
+					uint32_t t4 =3D m_pci.vobu_e_ptm/90 - m_pci_vob_timecode_offset;
+					m_demuxer.ProcessStream(SUBSTREAM_PCI, &m_buff[m_pci_position], m_p=
ci_size+2, t3, t4,=20
+						QString("# %1 -> %2 / %3 / %4 / %5 / %6 / off %7\n")
+						.arg(m_pci.vobu_s_ptm/90).arg(m_pci.vobu_e_ptm/90)
+						.arg(m_dsi.c_eltm, 0, 16).arg(m_pci.c_eltm, 0, 16)
+						.arg(t3).arg(t4).arg(m_pci_vob_timecode_offset));
+					=09
+				}
+			}
+			else if ((_StreamID & VIDEO_STREAM) =3D=3D VIDEO_STREAM)
+			{
+				debug("Video pack {}\n");
+				ParseVideoPacket();
+			}
+			else if ((_StreamID & AUDIO_STREAM) =3D=3D AUDIO_STREAM)
+			{
+				debug("Audio pack {}\n");
+				ParseAudioPacket(_StreamID);
+			}
+			else if (_StreamID =3D=3D PRIVATE_STREAM1)
+			{
+				debug("Private stream 1 pack {\n");
+				inc_lvl();
+				ParsePrivateStream1();
+				dec_lvl();
+				debug("}\n");
+			}
+			else
+			{
+				uint16_t _size =3D GetNext16Bits();
+				SkipNBytes(_size);
+				debug("Unknown slice type\n");
+			}
+
+			if (m_bFirstPacket && _StreamID !=3D SYSTEM_HEADER)
+			{
+				m_bFirstPacket =3D false;
+				m_startdts =3D pktinfo.dts;
+				m_startpts =3D pktinfo.pts;
+			}
+		}
+		else
+		{
+			debug("Unknown start code\n");
+		}
+	=09
+		m_pktindex++;
+	}
+	else
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ---------------------------------------------------------------------=
-------
+
+bool VobParser::AvailablePacketData() const
+{
+	return (m_index < DVD_VIDEO_LB_LEN);
+}
+
+// ---------------------------------------------------------------------=
-------
+
+bool VobParser::GetNextPacket()
+{
+	m_index =3D 0;
+
+	return (DVDReadBlocks(m_stream, m_pktindex, 1, m_buff) =3D=3D 1);
+}
+
+// ---------------------------------------------------------------------=
-------
+
+uint32_t VobParser::GetNext32Bits()
+{
+	uint32_t result =3D 0;
+	result |=3D m_buff[m_index++];
+	result <<=3D 8;
+	result |=3D m_buff[m_index++];
+	result <<=3D 8;
+	result |=3D m_buff[m_index++];
+	result <<=3D 8;
+	result |=3D m_buff[m_index++];
+    return result;
+}
+
+// ---------------------------------------------------------------------=
-------
+
+uint16_t VobParser::GetNext16Bits()
+{
+	uint32_t result =3D 0;
+	result |=3D m_buff[m_index++];
+	result <<=3D 8;
+	result |=3D m_buff[m_index++];
+	return result;
+}
+
+// ---------------------------------------------------------------------=
-------
+
+uint8_t VobParser::GetNext8Bits()
+{
+	return m_buff[m_index++];
+}
+
+// ---------------------------------------------------------------------=
-------
+
+void VobParser::SkipNBytes(int n)
+{
+	m_index +=3D n;
+}
+
+// ---------------------------------------------------------------------=
-------
+
+void VobParser::ParseSCR()
+{
+
+/* From http://dvd.sourceforge.net/dvdinfo/packhdr.html
+
+	      Byte 4                      Byte 5
+	      +--+--+--+--+--+--+--+--+   +--+--+--+--+--+--+--+--+
+          | 7| 6| 5| 4| 3| 2| 1| 0|   | 7| 6| 5| 4| 3| 2| 1| 0|
+	      +--+--+--+--+--+--+--+--+   +--+--+--+--+--+--+--+--+
+SCR bits  |f0|f1|32|31|30|f1|29|28|   |27|26|25|24|23|22|21|20|
+          +--+--+--+--+--+--+--+--+   +--+--+--+--+--+--+--+--+
+
+	      Byte 6                      Byte 7
+	      +--+--+--+--+--+--+--+--+   +--+--+--+--+--+--+--+--+
+          | 7| 6| 5| 4| 3| 2| 1| 0|   | 7| 6| 5| 4| 3| 2| 1| 0|
+	      +--+--+--+--+--+--+--+--+   +--+--+--+--+--+--+--+--+
+SCR bits  |19|18|17|16|15|f1|14|13|   |12|11|10| 9| 8| 7| 6| 5|
+          +--+--+--+--+--+--+--+--+   +--+--+--+--+--+--+--+--+
+
+	      Byte 8                      Byte 9
+	      +--+--+--+--+--+--+--+--+   +--+--+--+--+--+--+--+--+
+          | 7| 6| 5| 4| 3| 2| 1| 0|   | 7| 6| 5| 4| 3| 2| 1| 0|
+	      +--+--+--+--+--+--+--+--+   +--+--+--+--+--+--+--+--+
+SCR bits  | 4| 3| 2| 1| 0|f1|e8|e7|   |e6|e5|e4|e3|e2|f1|e0|c1|
+          +--+--+--+--+--+--+--+--+   +--+--+--+--+--+--+--+--+
+
+  fx =3D bit value fixed to x
+  ex =3D bit x of scr_ext
+*/
+
+	uint8_t byte4, byte5, byte6, byte7, byte8, byte9;
+	byte4 =3D GetNext8Bits();	byte5 =3D GetNext8Bits();
+	byte6 =3D GetNext8Bits();	byte7 =3D GetNext8Bits();
+	byte8 =3D GetNext8Bits();	byte9 =3D GetNext8Bits();
+
+	assert((byte4 & 0xc4) =3D=3D 0x44);
+	assert(byte6 & 0x04);
+	assert(byte8 & 0x04);
+	assert(byte9 & 0x01);
+	=09
+	uint64_t scr =3D 0;
+	scr |=3D ((((byte4 & 0x38) >> 1) | (byte4 & 0x03)) << 28);
+	scr |=3D (byte5 << 20);
+	scr |=3D ((((byte6 & 0xf8) >> 1) | (byte6 & 0x03)) << 13);
+	scr |=3D (byte7 << 5);
+	scr |=3D ((byte8 & 0xf8) >> 3);
+
+	uint16_t scr_ext =3D 0;
+	scr_ext |=3D ((byte8 & 0x03) << 7);
+	scr_ext |=3D ((byte9 & 0xfe) >> 1);
+
+	pktinfo.scr =3D scr;
+	pktinfo.scr_ext =3D scr_ext;
+}
+
+// ---------------------------------------------------------------------=
-------
+
+void VobParser::ParseNavPacket()
+{
+	uint32_t endStreamIndex =3D 0;
+	uint32_t position =3D m_index;
+	uint16_t length =3D GetNext16Bits();
+	endStreamIndex =3D m_index + length;
+	uint8_t substreamID =3D GetNext8Bits();
+=09
+	switch(substreamID)
+	{
+	case SUBSTREAM_PCI:
+		debug("PCI {\n");
+		inc_lvl();
+		ParsePCI();
+		m_pci_position =3D position-4; // keep the Private Stream 2 header
+		m_pci_size =3D length+4;
+		dec_lvl();
+		debug("}\n");
+		break;
+	case SUBSTREAM_DSI:
+		debug("DSI {\n");
+		inc_lvl();
+		ParseDSI();
+		dec_lvl();
+		debug("}\n");
+		break;
+	default:
+	  debug(QString("ParseNavPacket: unknown substream id @LBA=3D%1\n").arg=
(m_pktindex));
+	}
+=09
+	m_index =3D endStreamIndex;
+}
+
+// ---------------------------------------------------------------------=
-------
+
+void VobParser::ParsePCI()
+{
+	int i,j;
+	uint8_t onebyte;
+
+	// PCI General Information
+	m_pci.nv_pck_lbn =3D GetNext32Bits();
+	m_pci.vobu_cat =3D GetNext16Bits();
+	m_pci.reserved1 =3D GetNext16Bits();
+	m_pci.vobu_uop_ctl =3D GetNext32Bits();
+	m_pci.vobu_s_ptm =3D GetNext32Bits();
+	m_pci.vobu_e_ptm =3D GetNext32Bits();
+	m_pci.vobu_se_e_ptm =3D GetNext32Bits();
+	m_pci.c_eltm =3D GetNext32Bits();
+	memcpy(m_pci.vobu_isrc, &m_buff[m_index],32*1);=09
+	SkipNBytes(32*1);
+
+	// Non Seamless Angle Information
+	memcpy(m_pci.nsml_agli_dsta, &m_buff[m_index], 9*4);
+	SkipNBytes(9*4);
+
+	// Highlight General Information=20
+	m_pci.hli_ss =3D GetNext16Bits();
+	m_pci.hli_s_ptm =3D GetNext32Bits();
+	m_pci.hli_e_ptm =3D GetNext32Bits();
+	m_pci.btn_sl_e_ptm =3D GetNext32Bits();
+	m_pci.btn_md =3D GetNext16Bits();
+	m_pci.btn_sn =3D GetNext8Bits();
+	m_pci.btn_ns =3D GetNext8Bits();
+	m_pci.nsl_btn_ns =3D GetNext8Bits();
+	m_pci.reserved1 =3D GetNext8Bits();
+	m_pci.fosl_btnn =3D GetNext8Bits();
+	m_pci.foac_btnn =3D GetNext8Bits();
+=09
+	// Button Color Information Table=20
+	for(i =3D 0; i < 3; i++)
+		for(j =3D 0; j < 2; j++)
+			m_pci.btn_coli[i][j] =3D GetNext32Bits();
+
+	// Button Information
+	for(i =3D 0; i < 36; i++)
+	{
+		onebyte =3D GetNext8Bits();
+		m_pci.btnit[i].btn_coln =3D (onebyte & 0xC0) >> 6;
+		m_pci.btnit[i].start_x =3D (onebyte & 0x3F) << 4;
+
+		onebyte =3D GetNext8Bits();
+		m_pci.btnit[i].start_x |=3D (onebyte & 0xF0) >> 4;
+		m_pci.btnit[i].end_x =3D (onebyte & 0x03) << 8;
+
+		onebyte =3D GetNext8Bits();
+		m_pci.btnit[i].end_x |=3D onebyte;
+
+		onebyte =3D GetNext8Bits();
+		m_pci.btnit[i].auto_action_flag =3D (onebyte & 0xC0) >> 6;
+		m_pci.btnit[i].start_y =3D (onebyte & 0x3F) << 4;
+	=09
+		onebyte =3D GetNext8Bits();
+		m_pci.btnit[i].start_y |=3D (onebyte & 0xF0) >> 4;
+		m_pci.btnit[i].end_y =3D (onebyte & 0x03) << 8;
+	=09
+		onebyte =3D GetNext8Bits();
+		m_pci.btnit[i].end_y |=3D onebyte;
+
+		m_pci.btnit[i].up =3D GetNext8Bits() & 0x3F;
+		m_pci.btnit[i].down =3D GetNext8Bits() & 0x3F;
+		m_pci.btnit[i].left =3D GetNext8Bits() & 0x3F;
+		m_pci.btnit[i].right =3D GetNext8Bits() & 0x3F;
+	=09
+		memcpy(m_pci.btnit[i].vm_cmd, &m_buff[m_index],8*1);
+		SkipNBytes(8*1);
+	}
+
+	debug(QString("nv_pck_lbn: %1\n").arg(m_pci.nv_pck_lbn));
+	debug(QString("vobu_cat: %1\n").arg(m_pci.vobu_cat));
+	debug(QString("reserved1: %1\n").arg(m_pci.reserved1));
+	debug(QString("vobu_uop_ctl: %1\n").arg(m_pci.vobu_uop_ctl));
+	debug(QString("vobu_s_ptm: %1\n").arg(m_pci.vobu_s_ptm));
+	debug(QString("vobu_e_ptm: %1\n").arg(m_pci.vobu_e_ptm));
+	debug(QString("vobu_se_e_ptm: %1\n").arg(m_pci.vobu_se_e_ptm));
+	debug(QString("e_eltm: %1\n").arg(m_pci.c_eltm));
+	debug(QString("vobu_isrc: ...\n").toAscii());
+	debug(QString("nsml_agli_dsta: ...\n").toAscii());
+	debug(QString("hli_ss: %1\n").arg(m_pci.hli_ss));
+}
+
+// ---------------------------------------------------------------------=
-------
+
+void VobParser::ParseDSI()
+{
+	m_dsi.nv_pck_scr =3D GetNext32Bits();
+	m_dsi.nv_pck_lbn =3D GetNext32Bits();
+	m_dsi.vobu_ea =3D GetNext32Bits();
+	m_dsi.vobu_1stref_ea =3D GetNext32Bits();
+	m_dsi.vobu_2ndref_ea =3D GetNext32Bits();
+	m_dsi.vobu_3rdref_ea =3D GetNext32Bits();
+	m_dsi.vobu_vob_idn =3D GetNext16Bits();
+	m_dsi.reserved =3D GetNext8Bits();
+	m_dsi.vobu_c_idn =3D GetNext8Bits();
+	m_dsi.c_eltm =3D GetNext32Bits();
+
+	debug(QString("nv_pck_scr: %1\n").arg(m_dsi.nv_pck_scr));
+	debug(QString("nv_pck_lbn: %1\n").arg(m_dsi.nv_pck_lbn));
+	debug(QString("vobu_ea: %1\n").arg(m_dsi.vobu_ea));
+	debug(QString("vobu_1stref_ea: %1\n").arg(m_dsi.vobu_1stref_ea));
+	debug(QString("vobu_2ndref_ea: %1\n").arg(m_dsi.vobu_2ndref_ea));
+	debug(QString("vobu_3rdref_ea: %1\n").arg(m_dsi.vobu_3rdref_ea));
+	debug(QString("vobu_vob_idn: %1\n").arg(m_dsi.vobu_vob_idn));
+	debug(QString("reserved: %1\n").arg(m_dsi.reserved));
+	debug(QString("vobu_c_idn: %1\n").arg(m_dsi.vobu_c_idn));
+	debug(QString("c_eltm: %1\n").arg(m_dsi.c_eltm));
+}
+
+// ---------------------------------------------------------------------=
-------
+
+uint8_t GetBit(uint32_t data, uint8_t n)
+{
+	return ((data >> n) & 0x01);
+}
+
+// ---------------------------------------------------------------------=
-------
+
+void VobParser::ParsePESHeaderDataContentFlag()
+{=09
+	uint8_t byte6 =3D GetNext8Bits();
+	assert((byte6 & 0xC0) =3D=3D 0x80);
+	pes_header_data_content.PES_scrambling_control =3D (byte6 & 0x30) >> 4;
+	pes_header_data_content.PES_priority =3D GetBit(byte6,3);
+	pes_header_data_content.data_alignment_indicator =3D GetBit(byte6,2);
+	pes_header_data_content.copyright =3D GetBit(byte6,1);
+	pes_header_data_content.original_or_copy =3D GetBit(byte6,0);
+
+	uint8_t byte7 =3D GetNext8Bits();
+	pes_header_data_content.PTS_flag =3D GetBit(byte7,7);
+	pes_header_data_content.DTS_flag =3D GetBit(byte7,6);
+	pes_header_data_content.ESCR_flag =3D GetBit(byte7,5);
+	pes_header_data_content.ES_rate_flag =3D GetBit(byte7,4);
+	pes_header_data_content.DSM_trick_mode_flag =3D GetBit(byte7,3);
+	pes_header_data_content.additionnal_copy_info_flag =3D GetBit(byte7,2);
+	pes_header_data_content.PES_CRC_flag =3D GetBit(byte7,1);
+	pes_header_data_content.PES_extension_flag =3D GetBit(byte7,0);
+=09
+	pes_header_data_content.PES_header_data_len =3D GetNext8Bits();
+}
+
+// ---------------------------------------------------------------------=
-------
+
+uint64_t VobParser::ParsePTS_DTS()
+{
+	// PTS and DTS have same format
+	uint64_t result =3D 0;
+
+	uint8_t byte0 =3D GetNext8Bits();
+	uint16_t word0 =3D GetNext16Bits();
+	uint16_t word1 =3D GetNext16Bits();
+
+	assert(word0 & 0x01);
+	assert(word1 & 0x01);
+
+	result |=3D (((byte0 & 0x0E) >> 1) << 30);
+	result |=3D ((word0 >> 1) << 15);
+	result |=3D (word1 >> 1);
+
+	return result;
+}
+
+// ---------------------------------------------------------------------=
-------
+
+void VobParser::ParsePESHeaderData()
+{
+	uint8_t bytesLeft =3D pes_header_data_content.PES_header_data_len;
+	if(pes_header_data_content.PTS_flag)
+	{
+		// PTS : Presentation Time Stamp
+		pktinfo.pts =3D ParsePTS_DTS();
+		bytesLeft -=3D 5;
+		if (m_bFirstPacket)
+		{
+			m_startpts =3D pktinfo.pts;
+		}
+		pktinfo.pts -=3D m_startpts;
+	}
+	if(pes_header_data_content.DTS_flag)
+	{
+		// DTS : Decoding Time Stamp
+		pktinfo.dts =3D ParsePTS_DTS();
+		bytesLeft -=3D 5;
+		if (m_bFirstPacket)
+		{
+			m_startdts =3D pktinfo.dts;
+		}
+		pktinfo.dts -=3D m_startdts;
+	}
+	m_bFirstPacket =3D false;
+
+	// Skip the rest
+	SkipNBytes(bytesLeft);
+}
+
+// ---------------------------------------------------------------------=
-------
+
+void VobParser::ParseVideoPacket()
+{
+	uint16_t length =3D GetNext16Bits();
+	ParsePESHeaderDataContentFlag();
+	ParsePESHeaderData();
+
+	m_demuxer.ProcessStream(VIDEO_STREAM, &m_buff[m_index],
+		length - 3 - pes_header_data_content.PES_header_data_len, pktinfo.dts/=
90, pktinfo.pts/90,
+		QString("DTS %1 PTS %2 - %3 %4\n").arg(m_startdts/90).arg(m_startpts/9=
0).arg(pktinfo.dts/90).arg(pktinfo.pts/90));
+}
+
+void VobParser::ParseAudioPacket(int StreamID)
+{
+	uint16_t length =3D GetNext16Bits();
+	ParsePESHeaderDataContentFlag();
+	ParsePESHeaderData();
+
+	m_demuxer.ProcessStream(StreamID, &m_buff[m_index],
+		length - 3 - pes_header_data_content.PES_header_data_len, pktinfo.pts/=
90, pktinfo.dts/90,
+		QString("DTS %1 PTS %2 - %3 %4\n").arg(m_startdts/90).arg(m_startpts/9=
0).arg(pktinfo.dts/90).arg(pktinfo.pts/90));
+}
+
+// ---------------------------------------------------------------------=
-------
+
+void VobParser::ParsePrivateStream1()
+{
+	uint16_t length =3D GetNext16Bits();=09
+	uint16_t dataStartIndex =3D m_index;
+	// PES : Packetized Elementary Stream
+	ParsePESHeaderDataContentFlag();
+	ParsePESHeaderData();
+	uint8_t substreamID =3D GetNext8Bits();
+
+	uint32_t t3 =3D m_pci.vobu_s_ptm/90 - m_pci_vob_timecode_offset;
+	uint32_t t4 =3D m_pci.vobu_e_ptm/90 - m_pci_vob_timecode_offset;
+	if(substreamID >=3D SUBSTREAM_SUB_LOW && substreamID < SUBSTREAM_SUB_HI=
GH)
+	{
+		debug(QString("Subtitles streamID =3D 0x%1\n").arg(substreamID, 0, 16)=
);
+
+		// .sub files the VobSub way (includes the whole packet)
+		m_demuxer.ProcessStream(substreamID, m_buff, DVD_VIDEO_LB_LEN, t3, t4,=
=20
+		    QString("DTS %1 PTS %2 - %3 %4\n").arg(m_startdts/90).arg(m_startp=
ts/90).arg(pktinfo.dts/90).arg(pktinfo.pts/90));
+	}
+	else if(substreamID >=3D SUBSTREAM_AC3_LOW && substreamID < SUBSTREAM_A=
C3_HIGH)
+	{
+		debug(QString("AC3 streamID =3D 0x%1\n").arg(substreamID, 0, 16));
+
+		// Skip frame header number
+		SkipNBytes(1);
+		// Skip first access unit pointer
+		SkipNBytes(2);
+
+		uint16_t ac3DataLen =3D length - (m_index - dataStartIndex);
+		m_demuxer.ProcessStream(substreamID, &m_buff[m_index], ac3DataLen, t3,=
 t4,=20
+		    QString("DTS %1 PTS %2 - %3 %4\n").arg(m_startdts/90).arg(m_startp=
ts/90).arg(pktinfo.dts/90).arg(pktinfo.pts/90));
+	}
+	else if(substreamID >=3D SUBSTREAM_DTS_LOW && substreamID < SUBSTREAM_D=
TS_HIGH)
+	{
+		debug(QString("DTS streamID =3D 0x%1\n").arg(substreamID, 0, 16));
+	=09
+		// Skip frame header number
+		SkipNBytes(1);
+		// Skip first access unit pointer
+		SkipNBytes(2);
+
+		uint16_t ac3DataLen =3D length - (m_index - dataStartIndex);
+		m_demuxer.ProcessStream(substreamID, &m_buff[m_index], ac3DataLen, t3,=
 t4,=20
+		    QString("DTS %1 PTS %2 - %3 %4\n").arg(m_startdts/90).arg(m_startp=
ts/90).arg(pktinfo.dts/90).arg(pktinfo.pts/90));
+	}
+	else if(substreamID >=3D SUBSTREAM_PCM_LOW && substreamID < SUBSTREAM_P=
CM_HIGH)
+	{
+		debug(QString("LPCM streamID =3D 0x%1\n").arg(substreamID, 0, 16));
+
+		// Skip unknown data
+		SkipNBytes(6);
+
+		uint16_t ac3DataLen =3D length - (m_index - dataStartIndex);
+		m_demuxer.ProcessStream(substreamID, &m_buff[m_index], ac3DataLen, t3,=
 t4,=20
+			QString("DTS %1 PTS %2 - %3 %4\n").arg(m_startdts/90).arg(m_startpts/=
90).arg(pktinfo.dts/90).arg(pktinfo.pts/90));
+	}
+	else
+	{
+		debug("Unknown\n");
+	}
+}
+
+// ---------------------------------------------------------------------=
-------
+
+void VobParser::Reset()
+{
+	memset(&m_dsi, 0, sizeof(m_dsi));
+	memset(&pktinfo, 0, sizeof(pktinfo));
+	memset(&pes_header_data_content, 0, sizeof(pes_header_data_content));
+	previous_vobid =3D -1;
+	previous_cellid =3D -1;
+	m_index =3D 0;
+	m_pktindex =3D 0;
+	DVDFileSeek(m_stream,0);
+}
+
+// ---------------------------------------------------------------------=
-------
+
+bool VobParser::IsNewCell()
+{
+	bool result =3D (GetVobID() !=3D previous_vobid ||
+					GetCellID() !=3D previous_cellid);
+=09
+    previous_vobid =3D GetVobID();
+    previous_cellid =3D GetCellID();
+	if (result)
+		m_bFirstPacket =3D true;
+
+	return result;
+}
+
+// ---------------------------------------------------------------------=
-------
+
+inline uint8_t VobParser::GetVobID() const
+{
+	return m_dsi.vobu_vob_idn;
+}
+
+// ---------------------------------------------------------------------=
-------
+
+inline uint8_t VobParser::GetCellID() const
+{
+	return m_dsi.vobu_c_idn;
+}
+
+// ---------------------------------------------------------------------=
-------
+
+uint32_t VobParser::GetCellSCR() const
+{
+	return m_dsi.nv_pck_scr;
+}
+
+// ---------------------------------------------------------------------=
-------
+=20
+void SubDemuxWriter::WriteTimecodeInfo(uint32_t start_time, uint32_t end=
_time, uint64_t filepos, const QString& debug)
+{
+	int i;
+
+	if (!m_TimecodeFile)
+	{
+		QString m_filename (m_Filename);
+		m_filename +=3D ".idx";
+		m_TimecodeFile =3D fopen(QFile::encodeName(m_filename),"w");
+
+		fwrite("# VobSub index file, v7 (do not modify this line!)\n#\n", 1, 5=
3, m_TimecodeFile);
+		fwrite("# Settings\n\n# Original frame size\nsize: ", 1, 40, m_Timecod=
eFile);
+		fprintf(m_TimecodeFile, "%dx%d\n\n", m_width, m_height);
+		fwrite("# Origin, relative to the upper-left corner, can be overloaded=
 by aligment\n"
+		       "org: 0, 0\n\n"
+		       "# Image scaling (hor,ver), origin is at the upper-left corner =
or at the alignment coord (x, y)\n"
+		       "scale: 100%, 100%\n\n"
+		       "# Alpha blending\n"
+		       "alpha: 100%\n\n"
+		       "# Smoothing for very blocky images (use OLD for no filtering)\=
n"
+		       "smooth: OFF\n\n"
+		       "# In millisecs\n"
+		       "fadein/out: 50, 50\n\n"
+		       "# Force subtitle placement relative to (org.x, org.y)\n"
+		       "align: OFF at LEFT TOP\n\n"
+		       "# For correcting non-progressive desync. (in millisecs or hh:m=
m:ss:ms)\n"
+		       "# Note: Not effective in DirectVobSub, use \"delay: ... \" ins=
tead.\n"
+		       "time offset: 0\n\n"
+		       "# ON: displays only forced subtitles, OFF: shows everything\n"
+               "forced subs: OFF\n\n"
+               "# The original palette of the DVD\n"
+			   "palette: ", 1, 692, m_TimecodeFile);
+		for (i=3D0; i<15; i++)
+		{
+			fprintf(m_TimecodeFile, "%06x, ", m_palette[i]);
+		}
+		fprintf(m_TimecodeFile, "%06x\n\n", m_palette[i]);
+		fwrite("# Custom colors (transp idxs and the four colors)\n"
+		       "custom colors: OFF, tridx: 0000, colors: 000000, 000000, 00000=
0, 000000\n\n"
+		       "# Language index in use\n"
+		       "langidx: 0\n\n"
+		       "id: ", 1, 163, m_TimecodeFile);
+		if (m_language)
+			fprintf(m_TimecodeFile, "%c%c", m_language >> 8, m_language);
+		else
+			fwrite("un", 1, 2, m_TimecodeFile);
+		fwrite(", index: 0\n"
+		       "# Decomment next line to activate alternative name in DirectVo=
bSub / Windows Media Player 6.x\n"
+		       "# alt: ", 1, 112, m_TimecodeFile);
+        fprintf(m_TimecodeFile, "%s\n\n", DecodeLanguage(m_language));
+	}
+	int32_t delay =3D start_time + m_start_timecode;
+	int millisecond =3D delay % 1000;
+	delay /=3D 1000;
+	int second =3D delay % 60;
+	delay /=3D 60;
+	int minute =3D delay % 60;
+	delay /=3D 60;
+	fprintf(m_TimecodeFile, "timestamp: %02d:%02d:%02d:%03d, filepos: %09x\=
n", delay,minute,second,millisecond,filepos);
+}
+
+void BtnDemuxWriter::WriteTimecodeInfo(uint32_t start_time, uint32_t end=
_time, uint64_t filepos, const QString& debug)
+{
+//static uint32_t time =3D0;
+	m_TimecodeFile =3D GetTimecodeFile();
+
+	if (start_time > m_last_end_timecode)
+	{
+		if (m_last_end_timecode > m_start_timecode)
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_last_start_t=
imecode) / 1000.0);
+		fprintf(m_TimecodeFile, "gap,%lf\n", (start_time - m_last_end_timecode=
) / 1000.0);
+		m_start_timecode =3D start_time;
+	}
+//fwrite(debug.c_str(), debug.size(), 1, m_TimecodeFile);
+//fprintf(m_TimecodeFile, "# %d =3D> %d\n",time, time + end_time - start=
_time);
+//time +=3D end_time - start_time;
+	m_last_start_timecode =3D start_time;
+	m_last_end_timecode =3D end_time;
+}
+
+void DTSDemuxWriter::WriteTimecodeInfo(uint32_t start_time, uint32_t end=
_time, uint64_t filepos, const QString& debug)
+{
+	m_TimecodeFile =3D GetTimecodeFile();
+
+	if (start_time > m_last_end_timecode)
+	{
+		if (m_last_end_timecode > m_start_timecode)
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_last_start_t=
imecode) / 1000.0);
+		fprintf(m_TimecodeFile, "gap,%lf\n", (start_time - m_last_end_timecode=
) / 1000.0);
+		m_start_timecode =3D start_time;
+	}
+	m_last_start_timecode =3D start_time;
+	m_last_end_timecode =3D end_time;
+}
+
+void LPCMDemuxWriter::WriteTimecodeInfo(uint32_t start_time, uint32_t en=
d_time, uint64_t filepos, const QString& debug)
+{
+	m_TimecodeFile =3D GetTimecodeFile();
+
+	if (start_time > m_last_end_timecode)
+	{
+		if (m_last_end_timecode > m_start_timecode)
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timeco=
de) / 1000.0);
+		fprintf(m_TimecodeFile, "gap,%lf\n", (start_time - m_last_end_timecode=
) / 1000.0);
+		m_start_timecode =3D start_time;
+	}
+	m_last_start_timecode =3D start_time;
+	m_last_end_timecode =3D end_time;
+}
+
+void MPADemuxWriter::WriteTimecodeInfo(uint32_t start_time, uint32_t end=
_time, uint64_t filepos, const QString& debug)
+{
+	m_TimecodeFile =3D GetTimecodeFile();
+}
+
+void AC3DemuxWriter::WriteTimecodeInfo(uint32_t start_time, uint32_t end=
_time, uint64_t filepos, const QString& debug)
+{
+	m_TimecodeFile =3D GetTimecodeFile();
+
+	if (start_time > m_last_end_timecode)
+	{
+		if (m_last_end_timecode > m_start_timecode)
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_last_start_t=
imecode) / 1000.0);
+		fprintf(m_TimecodeFile, "gap,%lf\n", (start_time - m_last_end_timecode=
) / 1000.0);
+		m_start_timecode =3D start_time;
+	}
+	m_last_start_timecode =3D start_time;
+	m_last_end_timecode =3D end_time;
+}
+
+void VideoDemuxWriter::WriteTimecodeInfo(uint32_t start_time, uint32_t e=
nd_time, uint64_t filepos, const QString& debug)
+{
+	// TODO detect gaps in the stream
+}
+
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+
+void VideoDemuxWriter::ProcessStream(uint8_t* buff, uint32_t size, uint3=
2_t start_time, uint32_t end_time, const QString& debug)
+{
+	if (m_parser =3D=3D NULL)
+		m_parser =3D new M2VParser;
+=09
+	m_parser->WriteData(buff, size);
+
+	MPEG2ParserState state =3D m_parser->GetState();
+
+	while (state =3D=3D MPV_PARSER_STATE_FRAME)=20
+	{
+		delete m_parser->ReadFrame();
+		state =3D m_parser->GetState();
+	}
+
+	Write(buff, size, start_time, end_time, debug);=20
+}
+
+void VideoDemuxWriter::SetBoundary(uint32_t start_timecode, uint32_t dur=
ation, const CellListElem *cell)
+{
+	if (m_parser !=3D NULL)
+	{
+		m_parser->SetEOS();
+
+		MPEG2ParserState state =3D m_parser->GetState();
+
+		while (state =3D=3D MPV_PARSER_STATE_FRAME)=20
+		{
+			MPEGFrame* current_frame =3D m_parser->ReadFrame();
+			if ((current_frame->timecode + current_frame->duration) / 1000000 > m=
_last_end_timecode)
+			{
+				m_last_start_timecode =3D current_frame->timecode / 1000000;
+				m_last_end_timecode =3D (current_frame->timecode + current_frame->du=
ration) / 1000000;
+			}
+			delete current_frame;
+
+			state =3D m_parser->GetState();
+		}
+	=09
+		delete m_parser;
+	}
+=09
+	m_parser =3D new M2VParser();
+
+	m_TimecodeFile =3D GetTimecodeFile();
+
+	if (m_end_timecode !=3D 0)
+	{
+		if (m_is_still) {
+			fwrite(" (Still)\n", 1, 9, m_TimecodeFile);
+			fprintf(m_TimecodeFile, "%lf,%lf\n", (m_end_timecode - m_start_timeco=
de) / 1000.0, 1000.0 / (m_end_timecode - m_start_timecode));
+		}
+		else if (m_last_end_timecode < m_end_timecode)
+		{
+			fprintf(m_TimecodeFile, "\n%lf\n", (m_last_end_timecode - m_start_tim=
ecode) / 1000.0);
+			fprintf(m_TimecodeFile, "gap,%lf\n", (m_end_timecode - m_last_end_tim=
ecode) / 1000.0);
+		}
+		else
+		{
+			if (m_last_end_timecode > m_end_timecode)
+				qWarning("There is more video that indicated in the cell.");
+			fprintf(m_TimecodeFile, "\n%lf\n", (m_last_end_timecode - m_start_tim=
ecode) / 1000.0);
+		}
+	}
+
+	m_start_timecode =3D start_timecode;
+	m_end_timecode =3D start_timecode + duration;
+	m_last_end_timecode =3D start_timecode;
+	m_is_still =3D cell->isStill;
+
+	fprintf(m_TimecodeFile, "\n# VOB %d Cell %d", cell->vobid, cell->cellid=
);
+}
+
+void AC3DemuxWriter::SetBoundary(uint32_t start_timecode, uint32_t durat=
ion, const CellListElem *cell)
+{
+	m_TimecodeFile =3D GetTimecodeFile();
+
+	// handle ending of the previous cell
+	if (m_last_end_timecode < m_end_timecode)
+	{
+		if (m_last_end_timecode > m_start_timecode)
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		fprintf(m_TimecodeFile, "gap,%lf\n", (m_end_timecode - m_last_end_time=
code) / 1000.0);
+	}
+	else
+	{
+		if (m_end_timecode !=3D 0)
+		{
+			if (m_last_end_timecode > m_end_timecode)
+				qWarning("There is more AC3 audio that indicated in the cell.");
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		}
+	}
+
+	m_start_timecode =3D start_timecode;
+	m_end_timecode =3D start_timecode + duration;
+	m_last_end_timecode =3D start_timecode;
+	m_last_start_timecode =3D start_timecode;
+
+	fprintf(m_TimecodeFile, "\n# VOB %d Cell %d\n", cell->vobid, cell->cell=
id);
+}
+
+void DTSDemuxWriter::SetBoundary(uint32_t start_timecode, uint32_t durat=
ion, const CellListElem *cell)
+{
+	m_TimecodeFile =3D GetTimecodeFile();
+
+	// handle ending of the previous cell
+	if (m_last_end_timecode < m_end_timecode)
+	{
+		if (m_last_end_timecode > m_start_timecode)
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		fprintf(m_TimecodeFile, "gap,%lf\n", (m_end_timecode - m_last_end_time=
code) / 1000.0);
+	}
+	else
+	{
+		if (m_end_timecode !=3D 0)
+		{
+			if (m_last_end_timecode > m_end_timecode)
+				qWarning("There is more DTS audio that indicated in the cell.");
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		}
+	}
+
+	m_start_timecode =3D start_timecode;
+	m_end_timecode =3D start_timecode + duration;
+	m_last_end_timecode =3D start_timecode;
+	m_last_start_timecode =3D start_timecode;
+
+	fprintf(m_TimecodeFile, "\n# VOB %d Cell %d\n", cell->vobid, cell->cell=
id);
+}
+
+void LPCMDemuxWriter::SetBoundary(uint32_t start_timecode, uint32_t dura=
tion, const CellListElem *cell)
+{
+	m_TimecodeFile =3D GetTimecodeFile();
+
+	// handle ending of the previous cell
+	if (m_last_end_timecode < m_end_timecode)
+	{
+		if (m_last_end_timecode > m_start_timecode)
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		fprintf(m_TimecodeFile, "gap,%lf\n", (m_end_timecode - m_last_end_time=
code) / 1000.0);
+	}
+	else
+	{
+		if (m_end_timecode !=3D 0)
+		{
+			if (m_last_end_timecode > m_end_timecode)
+				qWarning("There is more PCM audio that indicated in the cell.");
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		}
+	}
+
+	m_start_timecode =3D start_timecode;
+	m_end_timecode =3D start_timecode + duration;
+	m_last_end_timecode =3D start_timecode;
+	m_last_start_timecode =3D start_timecode;
+
+	fprintf(m_TimecodeFile, "\n# VOB %d Cell %d\n", cell->vobid, cell->cell=
id);
+}
+
+void MPADemuxWriter::SetBoundary(uint32_t start_timecode, uint32_t durat=
ion, const CellListElem *cell)
+{
+}
+
+void SubDemuxWriter::SetBoundary(uint32_t start_timecode, uint32_t durat=
ion, const CellListElem *cell)
+{
+	if (start_timecode =3D=3D 0)
+		m_start_timecode =3D m_end_timecode;
+	m_end_timecode +=3D duration;
+}
+
+void BtnDemuxWriter::SetBoundary(uint32_t start_timecode, uint32_t durat=
ion, const CellListElem *cell)
+{
+	m_TimecodeFile =3D GetTimecodeFile();
+
+	// handle ending of the previous cell
+	if (m_last_end_timecode < m_end_timecode)
+	{
+		if (m_last_end_timecode > m_start_timecode)
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		fprintf(m_TimecodeFile, "gap,%lf\n", (m_end_timecode - m_last_end_time=
code) / 1000.0);
+	}
+	else
+	{
+		if (m_end_timecode !=3D 0)
+		{
+			if (m_last_end_timecode > m_end_timecode)
+				qWarning("There is more Button data that indicated in the cell.");
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		}
+	}
+
+	m_start_timecode =3D start_timecode;
+	m_end_timecode =3D start_timecode + duration;
+	m_last_end_timecode =3D start_timecode;
+	m_last_start_timecode =3D start_timecode;
+
+	fprintf(m_TimecodeFile, "\n# VOB %d Cell %d\n", cell->vobid, cell->cell=
id);
+}
+
+VideoDemuxWriter::~VideoDemuxWriter()
+{
+	try
+	{
+		m_TimecodeFile =3D GetTimecodeFile();
+	}
+	catch (VobParserException&)
+	{
+		m_TimecodeFile =3D 0;
+	}
+=09
+	if (m_parser !=3D NULL)
+	{
+		m_parser->SetEOS();
+
+		MPEG2ParserState state =3D m_parser->GetState();
+
+		while (state =3D=3D MPV_PARSER_STATE_FRAME)=20
+		{
+			MPEGFrame* current_frame =3D m_parser->ReadFrame();
+			if ((current_frame->timecode + current_frame->duration) / 1000000 > m=
_last_end_timecode)
+			{
+				m_last_start_timecode =3D current_frame->timecode / 1000000;
+				m_last_end_timecode =3D (current_frame->timecode + current_frame->du=
ration) / 1000000;
+			}
+			delete current_frame;
+
+			state =3D m_parser->GetState();
+		}
+		delete m_parser;
+	}
+
+
+	if ((m_end_timecode !=3D 0) && m_TimecodeFile)
+	{
+		if (m_is_still) {
+			fwrite(" (Still)\n", 1, 9, m_TimecodeFile);
+			fprintf(m_TimecodeFile, "%lf,%lf\n", (m_end_timecode - m_start_timeco=
de) / 1000.0, 1000.0 / (m_end_timecode - m_start_timecode));
+		}
+		else if (m_last_end_timecode < m_end_timecode)
+		{
+			fprintf(m_TimecodeFile, "\n%lf\n", (m_last_end_timecode - m_start_tim=
ecode) / 1000.0);
+			fprintf(m_TimecodeFile, "gap,%lf\n", (m_end_timecode - m_last_end_tim=
ecode) / 1000.0);
+		}
+		else
+			fprintf(m_TimecodeFile, "\n%lf\n", (m_end_timecode - m_start_timecode=
) / 1000.0);
+	}
+}
+
+AC3DemuxWriter::~AC3DemuxWriter()
+{
+	try
+	{
+		m_TimecodeFile =3D GetTimecodeFile();
+	}
+	catch (VobParserException&)
+	{
+		return;
+	}
+
+	// handle ending of the previous cell
+	if (m_last_end_timecode < m_end_timecode)
+	{
+		if (m_last_end_timecode > m_start_timecode)
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		fprintf(m_TimecodeFile, "gap,%lf\n", (m_end_timecode - m_last_end_time=
code) / 1000.0);
+	}
+	else
+	{
+		if (m_end_timecode !=3D 0)
+			fprintf(m_TimecodeFile, "%lf\n", (m_end_timecode - m_start_timecode) =
/ 1000.0);
+	}
+}
+
+DTSDemuxWriter::~DTSDemuxWriter()
+{
+	try
+	{
+		m_TimecodeFile =3D GetTimecodeFile();
+	}
+	catch (VobParserException&)
+	{
+		return;
+	}
+
+	// handle ending of the previous cell
+	if (m_last_end_timecode < m_end_timecode)
+	{
+		if (m_last_end_timecode > m_start_timecode)
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		fprintf(m_TimecodeFile, "gap,%lf\n", (m_end_timecode - m_last_end_time=
code) / 1000.0);
+	}
+	else
+	{
+		if (m_end_timecode !=3D 0)
+			fprintf(m_TimecodeFile, "%lf\n", (m_end_timecode - m_start_timecode) =
/ 1000.0);
+	}
+}
+
+LPCMDemuxWriter::~LPCMDemuxWriter()
+{
+	try
+	{
+		m_TimecodeFile =3D GetTimecodeFile();
+	}
+	catch (VobParserException&)
+	{
+		return;
+	}
+
+	// handle ending of the previous cell
+	if (m_last_end_timecode < m_end_timecode)
+	{
+		if (m_last_end_timecode > m_start_timecode)
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		fprintf(m_TimecodeFile, "gap,%lf\n", (m_end_timecode - m_last_end_time=
code) / 1000.0);
+	}
+	else
+	{
+		if (m_end_timecode !=3D 0)
+			fprintf(m_TimecodeFile, "%lf\n", (m_end_timecode - m_start_timecode) =
/ 1000.0);
+	}
+}
+
+BtnDemuxWriter::~BtnDemuxWriter()
+{
+	try
+	{
+		m_TimecodeFile =3D GetTimecodeFile();
+	}
+	catch (VobParserException&)
+	{
+		return;
+	}
+
+	// handle ending of the previous cell
+	if (m_last_end_timecode < m_end_timecode)
+	{
+		if (m_last_end_timecode > m_start_timecode)
+			fprintf(m_TimecodeFile, "%lf\n", (m_last_end_timecode - m_start_timec=
ode) / 1000.0);
+		fprintf(m_TimecodeFile, "gap,%lf\n", (m_end_timecode - m_last_end_time=
code) / 1000.0);
+	}
+	else
+	{
+		if (m_end_timecode !=3D 0)
+			fprintf(m_TimecodeFile, "%lf\n", (m_end_timecode - m_start_timecode) =
/ 1000.0);
+	}
+}
+
+WavWriter::~WavWriter()
+{
+	if (m_file)
+	{
+		uint8_t _tinteger[4];
+
+		fseek(m_file, m_size_position2, SEEK_SET);
+		_tinteger[0] =3D m_size & 0xFF;
+		_tinteger[1] =3D (m_size >> 8) & 0xFF;
+		_tinteger[2] =3D (m_size >> 16) & 0xFF;
+		_tinteger[3] =3D (m_size >> 24) & 0xFF;
+		fwrite(_tinteger,4,1, m_file);
+	=09
+		m_size +=3D 36;
+		fseek(m_file, m_size_position1, SEEK_SET);
+		_tinteger[0] =3D m_size & 0xFF;
+		_tinteger[1] =3D (m_size >> 8) & 0xFF;
+		_tinteger[2] =3D (m_size >> 16) & 0xFF;
+		_tinteger[3] =3D (m_size >> 24) & 0xFF;
+		fwrite(_tinteger,4,1, m_file);
+	}
+}
+
+void WavWriter::Write(uint8_t* buff, uint32_t size, uint32_t start_time,=
 uint32_t end_time, const QString& debug)
+{
+	if (m_bit_depth !=3D 16) // not supported
+		return;
+	if (m_file =3D=3D NULL)
+	{
+		uint8_t _tinteger[4];
+		m_file =3D OpenOuputFile();
+
+		// create the WAV header
+		//   RIFF head
+		fwrite("RIFF",4,1, m_file);
+		m_size_position1 =3D ftell(m_file);
+		fwrite("0000",4,1, m_file);
+		fwrite("WAVE",4,1, m_file);
+	=09
+		//   Format head
+		fwrite("fmt ",4,1, m_file);
+		_tinteger[0] =3D 16;
+		_tinteger[1] =3D 0;
+		_tinteger[2] =3D 0;
+		_tinteger[3] =3D 0;
+		fwrite(_tinteger,4,1, m_file);
+	=09
+		_tinteger[0] =3D 1;
+		fwrite(_tinteger,2,1, m_file); // PCM
+	=09
+		_tinteger[0] =3D m_channel_nb;
+		_tinteger[1] =3D 0;
+		fwrite(_tinteger,2,1, m_file); // Channels
+	=09
+		_tinteger[0] =3D m_sample_rate & 0xFF;
+		_tinteger[1] =3D (m_sample_rate >> 8) & 0xFF;
+		_tinteger[2] =3D (m_sample_rate >> 16) & 0xFF;
+		_tinteger[3] =3D (m_sample_rate >> 24) & 0xFF;
+		fwrite(_tinteger,4,1, m_file); // Sampling freq
+	=09
+		uint32_t _byte_rate =3D (m_sample_rate * m_channel_nb * m_bit_depth) >=
> 3;
+		_tinteger[0] =3D _byte_rate & 0xFF;
+		_tinteger[1] =3D (_byte_rate >> 8) & 0xFF;
+		_tinteger[2] =3D (_byte_rate >> 16) & 0xFF;
+		_tinteger[3] =3D (_byte_rate >> 24) & 0xFF;
+		fwrite(_tinteger,4,1, m_file); // Byte Rate
+	=09
+		uint16_t _block_align =3D (m_channel_nb * m_bit_depth) >> 3;
+		_tinteger[0] =3D _block_align & 0xFF;
+		_tinteger[1] =3D (_block_align >> 8) & 0xFF;
+		fwrite(_tinteger,2,1, m_file); // Block Align
+	=09
+		_tinteger[0] =3D m_bit_depth;
+		_tinteger[1] =3D 0;
+		fwrite(_tinteger,2,1, m_file); // Block Align
+	=09
+		//   Data head
+		fwrite("data",4,1, m_file);
+		m_size_position2 =3D ftell(m_file);
+		fwrite("0000",4,1, m_file);
+		m_size =3D 0;
+	}
+	uint16_t _tmp;
+	for (size_t i=3D0; i < size; i+=3D2) {
+		_tmp =3D buff[i];
+		_tmp <<=3D 8;
+		_tmp +=3D buff[i+1];
+		buff[i] =3D _tmp & 0xFF;
+		buff[i+1] =3D _tmp >> 8;
+	}
+	Writer::Write(buff, size, start_time, end_time, debug);
+	m_size +=3D size;
+}

Added: trunk/DvdMenuXtractor/dmx/vobparser/VobParser.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/DvdMenuXtractor/dmx/vobparser/VobParser.h	2007-03-10 21:45:28 U=
TC (rev 1291)
+++ trunk/DvdMenuXtractor/dmx/vobparser/VobParser.h	2007-03-10 21:46:03 U=
TC (rev 1292)
@@ -0,0 +1,621 @@
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+// VOBParser class
+// Copyright =A9 2002 : Christophe PARIS (christophe.paris at free.fr)
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+#ifndef _VOB_PARSER_H_
+#define _VOB_PARSER_H_
+// ---------------------------------------------------------------------=
-------
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdexcept>
+
+#include "dvdread/ifo_read.h"
+#include "mpegparser/M2VParser.h"
+
+#include <QList>
+#include <QFile>
+#include <QString>
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+
+#define VIDEO_STREAM_TYPE		0x01
+#define AUDIO_STREAM_TYPE		0x02
+#define SUB_STREAM_TYPE			0x04
+
+#define AC3_STREAM_TYPE			(AUDIO_STREAM_TYPE | 0x08)
+#define DTS_STREAM_TYPE			(AUDIO_STREAM_TYPE | 0x10)
+#define PCM_STREAM_TYPE			(AUDIO_STREAM_TYPE | 0x20)
+
+
+#define AUDIO_STREAM		0xC0
+#define VIDEO_STREAM		0xE0
+
+#define SUBSTREAM_PCI       0x00
+#define SUBSTREAM_DSI       0x01
+
+#define SUBSTREAM_SUB_LOW		0x20
+#define SUBSTREAM_SUB_HIGH		(SUBSTREAM_SUB_LOW + 32)
+
+#define SUBSTREAM_AC3_LOW		0x80
+#define SUBSTREAM_AC3_HIGH		(SUBSTREAM_AC3_LOW + 8)
+
+#define SUBSTREAM_DTS_LOW		0x88
+#define SUBSTREAM_DTS_HIGH		(SUBSTREAM_DTS_LOW + 8)
+
+#define SUBSTREAM_PCM_LOW		0xA0
+#define SUBSTREAM_PCM_HIGH		(SUBSTREAM_PCM_LOW + 8)
+
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+// Type
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+
+typedef struct=20
+{
+	unsigned int vobid;
+	unsigned int cellid;
+	unsigned int start_frame;
+	unsigned int end_frame;
+	unsigned int nb_frames;
+	uint32_t start_sector;
+	uint32_t last_sector;
+	double frame_dur;
+	uint64_t start_time;
+	uint64_t duration;
+	bool isStill;
+	bool selected;
+	bool found;
+	//ButtonsListType btt_list;
+} CellListElem;
+
+typedef struct {
+	uint16_t start_x;				// Starting X position
+	uint16_t start_y;				// Starting Y position
+	uint16_t end_x;					// Ending X position
+	uint16_t end_y;					// Ending Y position
+	uint8_t btn_coln;				// Button color table number, 0=3Dnone
+	uint8_t auto_action_flag;		// Auto Action flag 0=3Dno, 1=3Dyes
+	uint8_t up;						// Button number to select if "Up" is pressed
+	uint8_t down;					// Button number to select if "Down" is pressed
+	uint8_t left;					// Button number to select if "Left" is pressed
+	uint8_t right;					// Button number to select if "Right" is pressed
+	uint8_t vm_cmd[8];				// One vm command to be executed on "action" of t=
his button
+} btni;
+
+typedef struct {
+	uint32_t nv_pck_lbn		: 32;	// Logical Block Number (sector) of this blo=
ck
+	uint16_t vobu_cat		: 16;	// Flags, including APS (Analog Protection Sys=
tem)
+	uint16_t reserved1		: 16;	// Reserved
+	uint32_t vobu_uop_ctl	: 32;	// bitmask for prohibited user operations
+	uint32_t vobu_s_ptm		: 32;	// Vobu Start Presentation Time (90KHz clk)
+	uint32_t vobu_e_ptm		: 32;	// Vobu End Presentation Time (PTM)
+	uint32_t vobu_se_e_ptm	: 32;	// End PTM of VOBU if Sequence_End_Code
+	uint32_t c_eltm			: 32;	// Cell elapsed time (BCD)
+	uint8_t  vobu_isrc[32];			// International Standard Recording Code (roy=
alty management)
+	uint32_t nsml_agli_dsta[9];		// Non-seamless angle 1 relative offset to=
 VOBU for CURRENT ILVU=20
+	uint16_t hli_ss;				// Highlight status (lower 2 bits only)
+	uint32_t hli_s_ptm;				// Highlight start time
+	uint32_t hli_e_ptm;				// Highlight end time
+	uint32_t btn_sl_e_ptm;			// Button selection end time (ignore user afte=
r this)
+	uint16_t btn_md;				// 4 nibbles which describe the grouping of the but=
tons
+	uint8_t  btn_sn;				// Starting button number
+	uint8_t  btn_ns;				// Number of buttons
+	uint8_t  nsl_btn_ns;			// Number of numerically selected buttons
+	uint8_t  reserved2;				// Reserved
+	uint8_t  fosl_btnn;				// Force select button number
+	uint8_t  foac_btnn;				// Force action button number
+	uint32_t btn_coli[3][2];		// Selection and action color and contrast va=
lues
+	btni     btnit[36];
+} nav_pci_gi;
+
+typedef struct {
+	uint32_t nv_pck_scr		: 32;	// System clock reference
+	uint32_t nv_pck_lbn		: 32;	// Logical Block Number (sector) of this blo=
ck
+	uint32_t vobu_ea		: 32;	// VOBU end address - relative offset to last s=
ector of VOBU
+	uint32_t vobu_1stref_ea	: 32;	// First reference frame end block, relat=
ive - used for fast playing
+	uint32_t vobu_2ndref_ea	: 32;	// Second reference frame end block, rela=
tive - used for fast playing
+	uint32_t vobu_3rdref_ea	: 32;	// Third reference frame end block, relat=
ive - used for fast playing
+	uint16_t vobu_vob_idn	: 16;	// VOB number
+	uint8_t  reserved		: 8;	// Reserved
+	uint8_t  vobu_c_idn		: 8;	// CELL number within VOB
+	uint32_t c_eltm			: 32;	// Cell elapsed time (BCD)
+} nav_dsi_gi;
+
+typedef struct {
+	uint8_t PES_scrambling_control : 2;
+	uint8_t PES_priority : 1;
+	uint8_t data_alignment_indicator : 1;
+	uint8_t copyright : 1;
+	uint8_t original_or_copy : 1;
+	uint8_t PTS_flag : 1;
+	uint8_t DTS_flag : 1;
+	uint8_t ESCR_flag : 1;
+	uint8_t ES_rate_flag : 1;
+	uint8_t DSM_trick_mode_flag : 1;
+	uint8_t additionnal_copy_info_flag : 1;
+	uint8_t PES_CRC_flag : 1;
+	uint8_t PES_extension_flag : 1;
+	uint8_t PES_header_data_len;
+} PES_header_data_content;
+
+typedef struct {
+	uint32_t identifier;
+	uint64_t scr;
+	uint16_t scr_ext;
+	uint32_t program_mux_rate;
+	int64_t pts;
+	int64_t dts;
+} packet_info;
+
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+// Exception
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+
+class VobParserException : public std::runtime_error
+{
+public:
+	VobParserException(const char* message) : std::runtime_error(message) {=
}
+	virtual ~VobParserException() throw() {}
+};
+
+class VobParserFileNotFoundException : public VobParserException
+{
+public:
+	VobParserFileNotFoundException(const char* filename)
+		: VobParserException(qPrintable(QString("File not found exception : %1=
").arg(filename)))
+	{
+	}
+};
+
+class VobParserFileOpenException : public VobParserException
+{
+public:
+	VobParserFileOpenException(const char* filename)
+		: VobParserException(qPrintable(QString("Could not open/create file: %=
1").arg(filename)))
+	{
+	}
+};
+
+class VobParserInvalidPacketException : public VobParserException
+{
+public:
+	VobParserInvalidPacketException(int offset)
+		: VobParserException(qPrintable(QString("Invalid packet exception @LBA=
 %1").arg(offset)))
+	{
+	}
+};
+
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+// Demuxer class
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+
+class Demuxer
+{
+public:
+	virtual ~Demuxer() {}
+	virtual void ProcessStream(uint8_t* buff, uint32_t size, uint32_t start=
_time, uint32_t end_time, const QString & debug) =3D 0;
+	virtual void SetBoundary(uint32_t start_timecode, uint32_t duration, co=
nst CellListElem *cell) =3D 0;
+};
+
+// ---------------------------------------------------------------------=
-------
+
+class Writer : public Demuxer
+{
+public:
+	Writer(const QString& filenamePrefix, const QString& extension, double =
fps)
+		:m_Filename(filenamePrefix)
+		,m_fileExtension(extension)
+		,m_file(NULL)
+		,m_TimecodeFile(NULL)
+		,m_fps(fps)
+	{
+	}
+
+	virtual ~Writer()
+	{
+		if(m_file)
+		{
+			fclose(m_file);
+		}
+		if (m_TimecodeFile)
+			fclose(m_TimecodeFile);
+	}
+
+	virtual void Write(uint8_t* buff, uint32_t size, uint32_t start_time, u=
int32_t end_time, const QString& debug)
+	{
+		m_file =3D OpenOuputFile();
+		WriteTimecodeInfo(start_time, end_time, ftell(m_file), debug);
+		fwrite(buff, 1, size, m_file);
+	}
+
+	bool FileExists() const {
+		return m_file !=3D NULL;
+	}
+
+protected:
+	inline FILE* GetTimecodeFile()
+	{
+		if (!m_TimecodeFile)
+		{
+			QString m_filename =3D QString("%1_%2.tmc").arg(m_Filename).arg(m_fil=
eExtension);
+			m_TimecodeFile =3D fopen(QFile::encodeName(m_filename),"w");
+		=09
+			if (!m_TimecodeFile)
+				throw VobParserFileOpenException(QFile::encodeName(m_filename));
+		=09
+			fwrite("# timecode format v3\n", 1, 21, m_TimecodeFile);
+			fprintf(m_TimecodeFile, "assume %lf\n", m_fps);
+		}
+		return m_TimecodeFile;
+	}
+
+	inline FILE* OpenOuputFile()
+	{
+		if(!m_file)
+		{
+			QString m_filename =3D QString("%1.%2").arg(m_Filename).arg(m_fileExt=
ension);
+			m_file =3D fopen(QFile::encodeName(m_filename),"wb");
+
+			if (!m_file)
+				throw VobParserFileOpenException(QFile::encodeName(m_filename));
+		}
+		return m_file;
+	}
+
+	QString m_Filename;
+	QString m_fileExtension;
+	FILE* m_file;
+	FILE* m_TimecodeFile;
+	double m_fps;
+
+	virtual void WriteTimecodeInfo(uint32_t start_time, uint32_t end_time, =
uint64_t filepos, const QString& debug) =3D 0;
+};
+
+// ---------------------------------------------------------------------=
-------
+
+class VideoDemuxWriter : public Writer
+{
+public:
+	VideoDemuxWriter(const QString& filenamePrefix, double fps)
+		:Writer(filenamePrefix, "m2v", fps)=20
+		,m_end_timecode(0)
+		,m_last_start_timecode(0)
+		,m_last_end_timecode(0)
+		,m_is_still(false)
+		,m_parser(NULL)
+	{}
+	void ProcessStream(uint8_t* buff, uint32_t size, uint32_t start_time, u=
int32_t end_time, const QString& debug);
+	void SetBoundary(uint32_t start_timecode, uint32_t duration, const Cell=
ListElem *cell);
+	~VideoDemuxWriter();
+protected:
+	void WriteTimecodeInfo(uint32_t start_time, uint32_t end_time, uint64_t=
 filepos, const QString& debug);
+	uint32_t m_start_timecode;
+	uint32_t m_end_timecode;
+	uint32_t m_last_start_timecode;
+	uint32_t m_last_end_timecode;
+	bool m_is_still;
+
+	M2VParser * m_parser;
+};
+
+// ---------------------------------------------------------------------=
-------
+
+class AC3DemuxWriter : public Writer
+{
+public:
+	AC3DemuxWriter(const QString& filenamePrefix, const uint8_t streamID)
+		:Writer(filenamePrefix, "ac3", 0.0)
+		,m_streamID(streamID)
+		,m_end_timecode(0)
+		,m_last_start_timecode(0)
+		,m_last_end_timecode(0)
+	{}
+	~AC3DemuxWriter();
+	void ProcessStream(uint8_t* buff, uint32_t size, uint32_t start_time, u=
int32_t end_time, const QString& debug)
+	{
+		Write(buff,size, start_time, end_time, debug);
+	}
+	void SetBoundary(uint32_t start_timecode, uint32_t duration, const Cell=
ListElem *cell);
+private:
+	uint8_t m_streamID;
+protected:
+	void WriteTimecodeInfo(uint32_t start_time, uint32_t end_time, uint64_t=
 filepos, const QString& debug);
+	uint32_t m_start_timecode;
+	uint32_t m_end_timecode;
+	uint32_t m_last_start_timecode;
+	uint32_t m_last_end_timecode;
+};
+
+// ---------------------------------------------------------------------=
-------
+
+class DTSDemuxWriter : public Writer
+{
+public:
+	DTSDemuxWriter(const QString& filenamePrefix, const uint8_t streamID)
+		:Writer(filenamePrefix, "dts",0.0)
+		,m_streamID(streamID)
+		,m_end_timecode(0)
+		,m_last_start_timecode(0)
+		,m_last_end_timecode(0)
+	{}
+	~DTSDemuxWriter();
+	void ProcessStream(uint8_t* buff, uint32_t size, uint32_t start_time, u=
int32_t end_time, const QString& debug)
+	{
+		Write(buff,size, start_time, end_time, debug);
+	}
+	void SetBoundary(uint32_t start_timecode, uint32_t duration, const Cell=
ListElem *cell);
+private:
+	uint8_t m_streamID;
+protected:
+	void WriteTimecodeInfo(uint32_t start_time, uint32_t end_time, uint64_t=
 filepos, const QString& debug);
+	uint32_t m_start_timecode;
+	uint32_t m_end_timecode;
+	uint32_t m_last_start_timecode;
+	uint32_t m_last_end_timecode;
+};
+
+// ---------------------------------------------------------------------=
-------
+
+class WavWriter : public Writer
+{
+	public:
+		WavWriter(const QString& filenamePrefix, double fps, uint32_t sample_r=
ate, uint8_t bit_depth, uint8_t channel_nb)
+			:Writer(filenamePrefix, "wav", fps)
+			,m_sample_rate(sample_rate)
+			,m_bit_depth(bit_depth)
+			,m_channel_nb(channel_nb)
+		{}
+		~WavWriter();
+		void Write(uint8_t* buff, uint32_t size, uint32_t start_time, uint32_t=
 end_time, const QString& debug);
+	protected:
+		uint32_t m_sample_rate;
+		uint8_t m_bit_depth, m_channel_nb;
+		size_t m_size_position1,m_size_position2, m_size;
+};
+
+class LPCMDemuxWriter : public WavWriter
+{
+public:
+	LPCMDemuxWriter(const QString& filenamePrefix, const uint8_t streamID, =
uint32_t sample_rate, uint8_t bit_depth, uint8_t channel_nb)
+		:WavWriter(filenamePrefix,0.0, sample_rate, bit_depth, channel_nb)
+		,m_streamID(streamID)
+		,m_end_timecode(0)
+		,m_last_start_timecode(0)
+		,m_last_end_timecode(0)
+	{}
+	~LPCMDemuxWriter();
+	void ProcessStream(uint8_t* buff, uint32_t size, uint32_t start_time, u=
int32_t end_time, const QString& debug)
+	{
+		Write(buff,size, start_time, end_time, debug);
+	}
+	void SetBoundary(uint32_t start_timecode, uint32_t duration, const Cell=
ListElem *cell);
+private:
+	uint8_t m_streamID;
+protected:
+	void WriteTimecodeInfo(uint32_t start_time, uint32_t end_time, uint64_t=
 filepos, const QString& debug);
+	uint32_t m_start_timecode;
+	uint32_t m_end_timecode;
+	uint32_t m_last_start_timecode;
+	uint32_t m_last_end_timecode;
+};
+
+// ---------------------------------------------------------------------=
-------
+
+class MPADemuxWriter : public Writer
+{
+public:
+	MPADemuxWriter(const QString& filenamePrefix, const uint8_t streamID) :
+	  Writer(filenamePrefix, "mpa",0.0), m_streamID(streamID) {}
+	void ProcessStream(uint8_t* buff, uint32_t size, uint32_t start_time, u=
int32_t end_time, const QString& debug)
+	{
+		Write(buff,size, start_time, end_time, debug);
+	}
+	void SetBoundary(uint32_t start_timecode, uint32_t duration, const Cell=
ListElem *cell);
+private:
+	uint8_t m_streamID;
+protected:
+	void WriteTimecodeInfo(uint32_t start_time, uint32_t end_time, uint64_t=
 filepos, const QString& debug);
+};
+
+// ---------------------------------------------------------------------=
-------
+
+class SubDemuxWriter : public Writer
+{
+public:
+	SubDemuxWriter(const QString& filenamePrefix, const uint8_t streamID, u=
int16_t width, uint16_t height, const uint32_t * palette, uint16_t langua=
ge, bool forced)
+		:Writer(filenamePrefix, "sub",0.0)
+		,m_width(width)
+		,m_height(height)
+		,m_forced(forced)
+		,m_palette(palette)
+		,m_language(language)
+		,m_start_timecode(0)
+		,m_end_timecode(0)
+	{}
+	void ProcessStream(uint8_t* buff, uint32_t size, uint32_t start_time, u=
int32_t end_time, const QString& debug)
+	{
+		Write(buff,size, start_time, end_time, debug);
+	}
+	void SetBoundary(uint32_t start_timecode, uint32_t duration, const Cell=
ListElem *cell);
+protected:
+	void WriteTimecodeInfo(uint32_t start_time, uint32_t end_time, uint64_t=
 filepos, const QString& debug);
+private:
+	uint16_t m_width;
+	uint16_t m_height;
+	bool m_forced;
+	const uint32_t * m_palette;
+	uint16_t m_language;
+	uint32_t m_start_timecode;
+	uint32_t m_end_timecode;
+};
+
+// ---------------------------------------------------------------------=
-------
+
+class BtnDemuxWriter : public Writer
+{
+public:
+	BtnDemuxWriter(const QString& filenamePrefix, uint16_t width, uint16_t =
height)
+		:Writer(filenamePrefix, "btn",0.0)
+		,m_width(width)
+		,m_height(height)
+		,m_end_timecode(0)
+		,m_last_start_timecode(0)
+		,m_last_end_timecode(0)
+	{}
+	void ProcessStream(uint8_t* buff, uint32_t size, uint32_t start_time, u=
int32_t end_time, const QString& debug)
+	{
+		if (!m_file) {
+			m_file =3D OpenOuputFile();
+			fwrite("butonDVD", 8, 1, m_file);
+			uint8_t _tmp[4];
+			// width & height
+			_tmp[0] =3D m_width >> 8;
+			_tmp[1] =3D m_width & 0xFF;
+			_tmp[2] =3D m_height >> 8;
+			_tmp[3] =3D m_height & 0xFF;
+			fwrite(_tmp, 4, 1, m_file);
+			// pad to 16 bytes
+			_tmp[0] =3D 0;
+			_tmp[1] =3D 0;
+			_tmp[2] =3D 0;
+			_tmp[3] =3D 0;
+			fwrite(_tmp, 4, 1, m_file);
+		}
+		Write(buff,size, start_time, end_time, debug);
+	}
+	void SetBoundary(uint32_t start_timecode, uint32_t duration, const Cell=
ListElem *cell);
+	~BtnDemuxWriter();
+protected:
+	void WriteTimecodeInfo(uint32_t start_time, uint32_t end_time, uint64_t=
 filepos, const QString& debug);
+	uint16_t m_width, m_height;
+	uint32_t m_start_timecode;
+	uint32_t m_end_timecode;
+	uint32_t m_last_start_timecode;
+	uint32_t m_last_end_timecode;
+};
+
+// ---------------------------------------------------------------------=
-------
+
+class CompositeDemuxWriter
+{
+public:
+	CompositeDemuxWriter();
+	~CompositeDemuxWriter();
+	bool AddDemuxer(uint8_t streamID, Writer * demuxer, QString& CommandLin=
e);
+	void ProcessStream(int streamID, uint8_t* buff, uint32_t size, int32_t =
start_time, int32_t end_time, const QString& debug);
+	void Reset();
+	void SetBoundary(uint32_t start_timecode, uint32_t duration, const Cell=
ListElem *cell);
+
+	bool FileExists(uint8_t streamID) const {
+		return (m_muxers[streamID] !=3D NULL && m_muxers[streamID]->FileExists=
());
+	}
+
+	const QString& GetString(uint8_t streamID) const {
+		return m_strings[streamID];
+	}
+
+protected:
+	Writer * m_muxers[256];
+	QString m_strings[256];
+};
+
+// ---------------------------------------------------------------------=
-------
+
+struct stream_info_node
+{
+	uint8_t id;
+	uint32_t type;
+	stream_info_node* next;
+};
+
+
+// ---------------------------------------------------------------------=
-------
+
+typedef struct=20
+{
+	int x1;
+	int y1;
+	int x2;
+	int y2;
+} ButtonListElem;
+
+typedef QList<ButtonListElem *> ButtonListType;
+
+
+// ---------------------------------------------------------------------=
-------
+
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+// Main class
+// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
+
+class IFOFile;
+class CellsListType;
+
+class VobParser
+{
+public:
+	VobParser(const char* dirname, int16_t title, bool menu);
+	void Reset();
+	bool ParseNextPacket(const CellsListType & Cells);
+	uint32_t GetPacketCount() const;
+	uint32_t GetPacketIndex() const;
+	char* GetCurrentPacketData() const;
+	inline uint8_t GetVobID() const;
+	inline uint8_t GetCellID() const;
+	bool IsNewCell();
+	virtual ~VobParser();
+	inline CompositeDemuxWriter & GetDemuxer()
+	{
+		return m_demuxer;
+	}
+	uint32_t GetCellSCR() const;
+
+	nav_dsi_gi m_dsi;
+	nav_pci_gi m_pci;
+	packet_info pktinfo;
+	PES_header_data_content pes_header_data_content;
+protected:
+	void ParseNavPacket();
+	void ParseAudioPacket(int StreamID);
+	void ParseVideoPacket();
+	void ParsePrivateStream1();
+
+	void ParseSCR();
+	void ParsePCI();
+	void ParseDSI();
+	void ParsePESHeaderDataContentFlag();
+	void ParsePESHeaderData();
+	uint64_t ParsePTS_DTS();
+
+	// Buffer management
+	bool AvailablePacketData() const;
+	bool GetNextPacket();
+	uint32_t GetNext32Bits();
+	uint16_t GetNext16Bits();
+	uint8_t GetNext8Bits();
+	void SkipNBytes(int n);
+
+private:
+	int16_t m_title;
+	dvd_reader_t *m_dvdhandle;
+	dvd_file_t *m_stream;
+	bool m_language;
+	uint8_t m_buff[DVD_VIDEO_LB_LEN];
+	uint32_t m_index;
+	uint32_t m_pktindex;
+	uint32_t m_pktcount;
+	bool m_bFirstPacket;
+	int64_t m_startpts;
+	int64_t m_startdts;
+	uint16_t m_pci_position;
+	uint16_t m_pci_size;
+	uint32_t m_pci_vob_timecode_offset;
+=09
+	CompositeDemuxWriter m_demuxer;
+
+	int previous_vobid, previous_cellid;
+};
+
+// ---------------------------------------------------------------------=
-------
+#endif
+// ---------------------------------------------------------------------=
-------

Added: trunk/DvdMenuXtractor/dmx/vobparser/iso/iso-639.def
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/DvdMenuXtractor/dmx/vobparser/iso/iso-639.def	2007-03-10 21:45:=
28 UTC (rev 1291)
+++ trunk/DvdMenuXtractor/dmx/vobparser/iso/iso-639.def	2007-03-10 21:46:=
03 UTC (rev 1292)
@@ -0,0 +1,173 @@
+/*
+ * Defines the languages codes and abbreviations according to ISO 639-[1=
2].
+ * This is used in iso_lang.cpp and is taken from the GNU glibc 2.2.5 ta=
rball.
+ * It has been partially completed with native language name.
+ *
+ * Format is: ("English name", 639-1-code, 639-2/T-code, 639-2/B-code)
+ * If you find something missing or wrong contact <bug-glibc at gnu.org>
+ */
+
+DEFINE_LANGUAGE_CODE ("Afar", "", aa, aar, aar)
+DEFINE_LANGUAGE_CODE ("Abkhazian", "", ab, abk, abk)
+DEFINE_LANGUAGE_CODE ("Afrikaans", "", af, afr, afr)
+DEFINE_LANGUAGE_CODE ("Albanian", "", sq, sqi, alb)
+DEFINE_LANGUAGE_CODE ("Amharic", "", am, amh, amh)
+DEFINE_LANGUAGE_CODE ("Arabic", "", ar, ara, ara)
+DEFINE_LANGUAGE_CODE ("Armenian", "", hy, hye, arm)
+DEFINE_LANGUAGE_CODE ("Assamese", "", as, asm, asm)
+DEFINE_LANGUAGE_CODE ("Avestan", "", ae, ave, ave)
+DEFINE_LANGUAGE_CODE ("Aymara", "", ay, aym, aym)
+DEFINE_LANGUAGE_CODE ("Azerbaijani", "", az, aze, aze)
+DEFINE_LANGUAGE_CODE ("Bashkir", "", ba, bak, bak)
+DEFINE_LANGUAGE_CODE ("Basque", "", eu, eus, baq)
+DEFINE_LANGUAGE_CODE ("Belarusian", "", be, bel, bel)
+DEFINE_LANGUAGE_CODE ("Bengali", "", bn, ben, ben)
+DEFINE_LANGUAGE_CODE ("Bihari", "", bh, bih, bih)
+DEFINE_LANGUAGE_CODE ("Bislama", "", bi, bis, bis)
+DEFINE_LANGUAGE_CODE ("Bosnian", "", bs, bos, bos)
+DEFINE_LANGUAGE_CODE ("Breton", "", br, bre, bre)
+DEFINE_LANGUAGE_CODE ("Bulgarian", "", bg, bul, bul)
+DEFINE_LANGUAGE_CODE ("Burmese", "", my, mya, bur)
+DEFINE_LANGUAGE_CODE ("Catalan", "", ca, cat, cat)
+DEFINE_LANGUAGE_CODE ("Chamorro", "", ch, cha, cha)
+DEFINE_LANGUAGE_CODE ("Chechen", "", ce, che, che)
+DEFINE_LANGUAGE_CODE ("Chinese", "", zh, zho, chi)
+DEFINE_LANGUAGE_CODE ("Church Slavic", "", cu, chu, chu)
+DEFINE_LANGUAGE_CODE ("Chuvash", "", cv, chv, chv)
+DEFINE_LANGUAGE_CODE ("Cornish", "", kw, cor, cor)
+DEFINE_LANGUAGE_CODE ("Corsican", "", co, cos, cos)
+DEFINE_LANGUAGE_CODE ("Czech", "", cs, ces, cze)
+DEFINE_LANGUAGE_CODE ("Danish", "Dansk", da, dan, dan)
+DEFINE_LANGUAGE_CODE ("Dutch", "Nederlands", nl, nld, dut)
+DEFINE_LANGUAGE_CODE ("Dzongkha", "", dz, dzo, dzo)
+DEFINE_LANGUAGE_CODE ("English", "English", en, eng, eng)
+DEFINE_LANGUAGE_CODE ("Esperanto", "", eo, epo, epo)
+DEFINE_LANGUAGE_CODE ("Estonian", "", et, est, est)
+DEFINE_LANGUAGE_CODE ("Faroese", "", fo, fao, fao)
+DEFINE_LANGUAGE_CODE ("Fijian", "", fj, fij, fij)
+DEFINE_LANGUAGE_CODE ("Finnish", "Suomi", fi, fin, fin)
+DEFINE_LANGUAGE_CODE ("French", "Francais", fr, fra, fre)
+DEFINE_LANGUAGE_CODE ("Frisian", "", fy, fry, fry)
+DEFINE_LANGUAGE_CODE ("Georgian", "", ka, kat, geo)
+DEFINE_LANGUAGE_CODE ("German", "Deutsch", de, deu, ger)
+DEFINE_LANGUAGE_CODE ("Gaelic (Scots)", "", gd, gla, gla)
+DEFINE_LANGUAGE_CODE ("Irish", "", ga, gle, gle)
+DEFINE_LANGUAGE_CODE ("Gallegan", "", gl, glg, glg)
+DEFINE_LANGUAGE_CODE ("Manx", "", gv, glv, glv)
+DEFINE_LANGUAGE_CODE ("Greek, Modern ()", "", el, gre, ell)
+DEFINE_LANGUAGE_CODE ("Guarani", "", gn, grn, grn)
+DEFINE_LANGUAGE_CODE ("Gujarati", "", gu, guj, guj)
+DEFINE_LANGUAGE_CODE ("Hebrew", "", he, heb, heb)
+DEFINE_LANGUAGE_CODE ("Herero", "", hz, her, her)
+DEFINE_LANGUAGE_CODE ("Hindi", "", hi, hin, hin)
+DEFINE_LANGUAGE_CODE ("Hiri Motu", "", ho, hmo, hmo)
+DEFINE_LANGUAGE_CODE ("Hungarian", "Magyar", hu, hun, hun)
+DEFINE_LANGUAGE_CODE ("Icelandic", "Islenska", is, isl, ice)
+DEFINE_LANGUAGE_CODE ("Inuktitut", "", iu, iku, iku)
+DEFINE_LANGUAGE_CODE ("Interlingue", "", ie, ile, ile)
+DEFINE_LANGUAGE_CODE ("Interlingua", "", ia, ina, ina)
+DEFINE_LANGUAGE_CODE ("Indonesian", "", id, ind, ind)
+DEFINE_LANGUAGE_CODE ("Inupiaq", "", ik, ipk, ipk)
+DEFINE_LANGUAGE_CODE ("Italian", "Italiano", it, ita, ita)
+DEFINE_LANGUAGE_CODE ("Javanese", "", jv, jaw, jav)
+DEFINE_LANGUAGE_CODE ("Japanese", "", ja, jpn, jpn)
+DEFINE_LANGUAGE_CODE ("Kalaallisut (Greenlandic)", "", kl, kal, kal)
+DEFINE_LANGUAGE_CODE ("Kannada", "", kn, kan, kan)
+DEFINE_LANGUAGE_CODE ("Kashmiri", "", ks, kas, kas)
+DEFINE_LANGUAGE_CODE ("Kazakh", "", kk, kaz, kaz)
+DEFINE_LANGUAGE_CODE ("Khmer", "", km, khm, khm)
+DEFINE_LANGUAGE_CODE ("Kikuyu", "", ki, kik, kik)
+DEFINE_LANGUAGE_CODE ("Kinyarwanda", "", rw, kin, kin)
+DEFINE_LANGUAGE_CODE ("Kirghiz", "", ky, kir, kir)
+DEFINE_LANGUAGE_CODE ("Komi", "", kv, kom, kom)
+DEFINE_LANGUAGE_CODE ("Korean", "", ko, kor, kor)
+DEFINE_LANGUAGE_CODE ("Kuanyama", "", kj, kua, kua)
+DEFINE_LANGUAGE_CODE ("Kurdish", "", ku, kur, kur)
+DEFINE_LANGUAGE_CODE ("Lao", "", lo, lao, lao)
+DEFINE_LANGUAGE_CODE ("Latin", "", la, lat, lat)
+DEFINE_LANGUAGE_CODE ("Latvian", "", lv, lav, lav)
+DEFINE_LANGUAGE_CODE ("Lingala", "", ln, lin, lin)
+DEFINE_LANGUAGE_CODE ("Lithuanian", "", lt, lit, lit)
+DEFINE_LANGUAGE_CODE ("Letzeburgesch", "", lb, ltz, ltz)
+DEFINE_LANGUAGE_CODE ("Macedonian", "", mk, mkd, mac)
+DEFINE_LANGUAGE_CODE ("Marshall", "", mh, mah, mah)
+DEFINE_LANGUAGE_CODE ("Malayalam", "", ml, mal, mal)
+DEFINE_LANGUAGE_CODE ("Maori", "", mi, mri, mao)
+DEFINE_LANGUAGE_CODE ("Marathi", "", mr, mar, mar)
+DEFINE_LANGUAGE_CODE ("Malay", "", ms, msa, may)
+DEFINE_LANGUAGE_CODE ("Malagasy", "", mg, mlg, mlg)
+DEFINE_LANGUAGE_CODE ("Maltese", "", mt, mlt, mlt)
+DEFINE_LANGUAGE_CODE ("Moldavian", "", mo, mol, mol)
+DEFINE_LANGUAGE_CODE ("Mongolian", "", mn, mon, mon)
+DEFINE_LANGUAGE_CODE ("Nauru", "", na, nau, nau)
+DEFINE_LANGUAGE_CODE ("Navajo", "", nv, nav, nav)
+DEFINE_LANGUAGE_CODE ("Ndebele, South", "", nr, nbl, nbl)
+DEFINE_LANGUAGE_CODE ("Ndebele, North", "", nd, nde, nde)
+DEFINE_LANGUAGE_CODE ("Ndonga", "", ng, ndo, ndo)
+DEFINE_LANGUAGE_CODE ("Nepali", "", ne, nep, nep)
+DEFINE_LANGUAGE_CODE ("Norwegian", "Norsk", no, nor, nor)
+DEFINE_LANGUAGE_CODE ("Norwegian Nynorsk", "", nn, nno, nno)
+DEFINE_LANGUAGE_CODE ("Norwegian Bokm=E5l", "", nb, nob, nob)
+DEFINE_LANGUAGE_CODE ("Chichewa; Nyanja", "", ny, nya, nya)
+DEFINE_LANGUAGE_CODE ("Occitan (post 1500); Proven=E7al", "", oc, oci, o=
ci)
+DEFINE_LANGUAGE_CODE ("Oriya", "", or, ori, ori)
+DEFINE_LANGUAGE_CODE ("Oromo", "", om, orm, orm)
+DEFINE_LANGUAGE_CODE ("Ossetian; Ossetic", "", os, oss, oss)
+DEFINE_LANGUAGE_CODE ("Panjabi", "", pa, pan, pan)
+DEFINE_LANGUAGE_CODE ("Persian", "", fa, fas, per)
+DEFINE_LANGUAGE_CODE ("Pali", "", pi, pli, pli)
+DEFINE_LANGUAGE_CODE ("Polish", "", pl, pol, pol)
+DEFINE_LANGUAGE_CODE ("Portuguese", "Portugues", pt, por, por)
+DEFINE_LANGUAGE_CODE ("Pushto", "", ps, pus, pus)
+DEFINE_LANGUAGE_CODE ("Quechua", "", qu, que, que)
+DEFINE_LANGUAGE_CODE ("Raeto-Romance", "", rm, roh, roh)
+DEFINE_LANGUAGE_CODE ("Romanian", "", ro, ron, rum)
+DEFINE_LANGUAGE_CODE ("Rundi", "", rn, run, run)
+DEFINE_LANGUAGE_CODE ("Russian", "", ru, rus, rus)
+DEFINE_LANGUAGE_CODE ("Sango", "", sg, sag, sag)
+DEFINE_LANGUAGE_CODE ("Sanskrit", "", sa, san, san)
+DEFINE_LANGUAGE_CODE ("Serbian", "", sr, srp, scc)
+DEFINE_LANGUAGE_CODE ("Croatian", "Hrvatski", hr, hrv, scr)
+DEFINE_LANGUAGE_CODE ("Sinhalese", "", si, sin, sin)
+DEFINE_LANGUAGE_CODE ("Slovak", "", sk, slk, slo)
+DEFINE_LANGUAGE_CODE ("Slovenian", "", sl, slv, slv)
+DEFINE_LANGUAGE_CODE ("Northern Sami", "", se, sme, sme)
+DEFINE_LANGUAGE_CODE ("Samoan", "", sm, smo, smo)
+DEFINE_LANGUAGE_CODE ("Shona", "", sn, sna, sna)
+DEFINE_LANGUAGE_CODE ("Sindhi", "", sd, snd, snd)
+DEFINE_LANGUAGE_CODE ("Somali", "", so, som, som)
+DEFINE_LANGUAGE_CODE ("Sotho, Southern", "", st, sot, sot)
+DEFINE_LANGUAGE_CODE ("Spanish", "Espanol", es, spa, spa)
+DEFINE_LANGUAGE_CODE ("Sardinian", "", sc, srd, srd)
+DEFINE_LANGUAGE_CODE ("Swati", "", ss, ssw, ssw)
+DEFINE_LANGUAGE_CODE ("Sundanese", "", su, sun, sun)
+DEFINE_LANGUAGE_CODE ("Swahili", "", sw, swa, swa)
+DEFINE_LANGUAGE_CODE ("Swedish", "Svenska", sv, swe, swe)
+DEFINE_LANGUAGE_CODE ("Tahitian", "", ty, tah, tah)
+DEFINE_LANGUAGE_CODE ("Tamil", "", ta, tam, tam)
+DEFINE_LANGUAGE_CODE ("Tatar", "", tt, tat, tat)
+DEFINE_LANGUAGE_CODE ("Telugu", "", te, tel, tel)
+DEFINE_LANGUAGE_CODE ("Tajik", "", tg, tgk, tgk)
+DEFINE_LANGUAGE_CODE ("Tagalog", "", tl, tgl, tgl)
+DEFINE_LANGUAGE_CODE ("Thai", "", th, tha, tha)
+DEFINE_LANGUAGE_CODE ("Tibetan", "", bo, bod, tib)
+DEFINE_LANGUAGE_CODE ("Tigrinya", "", ti, tir, tir)
+DEFINE_LANGUAGE_CODE ("Tonga (Tonga Islands)", "", to, ton, ton)
+DEFINE_LANGUAGE_CODE ("Tswana", "", tn, tsn, tsn)
+DEFINE_LANGUAGE_CODE ("Tsonga", "", ts, tso, tso)
+DEFINE_LANGUAGE_CODE ("Turkish", "", tr, tur, tur)
+DEFINE_LANGUAGE_CODE ("Turkmen", "", tk, tuk, tuk)
+DEFINE_LANGUAGE_CODE ("Twi", "", tw, twi, twi)
+DEFINE_LANGUAGE_CODE ("Uighur", "", ug, uig, uig)
+DEFINE_LANGUAGE_CODE ("Ukrainian", "", uk, ukr, ukr)
+DEFINE_LANGUAGE_CODE ("Urdu", "", ur, urd, urd)
+DEFINE_LANGUAGE_CODE ("Uzbek", "", uz, uzb, uzb)
+DEFINE_LANGUAGE_CODE ("Vietnamese", "", vi, vie, vie)
+DEFINE_LANGUAGE_CODE ("Volap=FCk", "", vo, vol, vol)
+DEFINE_LANGUAGE_CODE ("Welsh", "", cy, cym, wel)
+DEFINE_LANGUAGE_CODE ("Wolof", "", wo, wol, wol)
+DEFINE_LANGUAGE_CODE ("Xhosa", "", xh, xho, xho)
+DEFINE_LANGUAGE_CODE ("Yiddish", "", yi, yid, yid)
+DEFINE_LANGUAGE_CODE ("Yoruba", "", yo, yor, yor)
+DEFINE_LANGUAGE_CODE ("Zhuang", "", za, zha, zha)
+DEFINE_LANGUAGE_CODE ("Zulu", "", zu, zul, zul)

Added: trunk/DvdMenuXtractor/dmx/vobparser/iso/iso_lang.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/DvdMenuXtractor/dmx/vobparser/iso/iso_lang.c	2007-03-10 21:45:2=
8 UTC (rev 1291)
+++ trunk/DvdMenuXtractor/dmx/vobparser/iso/iso_lang.c	2007-03-10 21:46:0=
3 UTC (rev 1292)
@@ -0,0 +1,113 @@
+/***********************************************************************=
******
+ * iso_lang.c: function to decode language code (in dvd or a52 for insta=
nce).
+ ***********************************************************************=
******
+ * Copyright (C) 1998-2001 VideoLAN
+ * $Id: iso_lang.c,v 1.6 2002/06/01 12:32:01 sam Exp $
+ *
+ * Author: St=E9phane Borel <stef at via.ecp.fr>
+ *         Arnaud de Bossoreille de Ribou <bozo at via.ecp.fr>
+ *
+ * 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.
+ *=20
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA=
.
+ ***********************************************************************=
******/
+
+/***********************************************************************=
******
+ * Preamble
+ ***********************************************************************=
******/
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include "iso_lang.h"
+
+/***********************************************************************=
******
+ * Local tables
+ ***********************************************************************=
******/
+
+#define DEFINE_LANGUAGE_CODE(engName, nativeName, iso1, iso2T, iso2B) \
+          { engName, nativeName, #iso1, #iso2T, #iso2B },
+
+static const iso639_lang_t p_languages[] =3D
+{
+#include "iso-639.def"
+    { NULL, NULL, NULL, NULL, NULL }
+};
+
+static const iso639_lang_t unknown_language =3D
+    { "Unknown", "Unknown", "??", "???", "???" };
+
+/***********************************************************************=
******
+ * DecodeLanguage: gives the long language name from the two-letter
+ *                 ISO-639 code
+ ***********************************************************************=
******/
+const char * DecodeLanguage( uint16_t i_code )
+{
+    const iso639_lang_t * p_lang;
+    uint8_t psz_code[3];
+
+	if (i_code !=3D 0)
+	{
+		psz_code[0] =3D (uint8_t)(i_code >> 8);
+		psz_code[1] =3D (uint8_t)i_code;
+		psz_code[2] =3D '\0';
+
+		for( p_lang =3D p_languages; p_lang->psz_eng_name; p_lang++ )
+		{
+			if( !strncmp( p_lang->psz_iso639_1, psz_code, 2 ) )
+			{
+				if( *p_lang->psz_native_name )
+				{
+					return p_lang->psz_native_name;
+				}
+
+				return p_lang->psz_eng_name;
+			}
+		}
+	}
+
+    return "Unknown";
+}
+
+const iso639_lang_t * GetLang_1( const char * psz_code )
+{
+    const iso639_lang_t *p_lang;
+
+    for( p_lang =3D p_languages; p_lang->psz_eng_name; p_lang++ )
+        if( !strncmp( p_lang->psz_iso639_1, psz_code, 2 ) )
+            return p_lang;
+
+    return &unknown_language;
+}
+
+const iso639_lang_t * GetLang_2T( const char * psz_code )
+{
+    const iso639_lang_t *p_lang;
+   =20
+    for( p_lang =3D p_languages; p_lang->psz_eng_name; p_lang++ )
+        if( !strncmp( p_lang->psz_iso639_2T, psz_code, 3 ) )
+            return p_lang;
+
+    return &unknown_language;
+}
+
+const iso639_lang_t * GetLang_2B( const char * psz_code )
+{
+    const iso639_lang_t *p_lang;
+
+    for( p_lang =3D p_languages; p_lang->psz_eng_name; p_lang++ )
+        if( !strncmp( p_lang->psz_iso639_2B, psz_code, 3 ) )
+            return p_lang;
+
+    return &unknown_language;
+}
+

Added: trunk/DvdMenuXtractor/dmx/vobparser/iso/iso_lang.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/DvdMenuXtractor/dmx/vobparser/iso/iso_lang.h	2007-03-10 21:45:2=
8 UTC (rev 1291)
+++ trunk/DvdMenuXtractor/dmx/vobparser/iso/iso_lang.h	2007-03-10 21:46:0=
3 UTC (rev 1292)
@@ -0,0 +1,51 @@
+/***********************************************************************=
******
+ * iso_lang.h: function to decode language code (in dvd or a52 for insta=
nce).
+ ***********************************************************************=
******
+ * Copyright (C) 1998-2001 VideoLAN
+ * $Id: iso_lang.h,v 1.5 2002/05/20 22:36:42 sam Exp $
+ *
+ * Author: St=E9phane Borel <stef at via.ecp.fr>
+ *         Arnaud de Bossoreille de Ribou <bozo at via.ecp.fr>
+ *
+ * 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.
+ *=20
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA=
.
+ ***********************************************************************=
******/
+
+#ifndef _ISO_LANG_H_
+#define _ISO_LANG_H_
+
+struct iso639_lang_s
+{
+    char * psz_eng_name;        /* Description in English */
+    char * psz_native_name;     /* Description in native language */
+    char * psz_iso639_1;        /* ISO-639-1 (2 characters) code */
+    char * psz_iso639_2T;       /* ISO-639-2/T (3 characters) English co=
de */
+    char * psz_iso639_2B;       /* ISO-639-2/B (3 characters) native cod=
e */
+};
+
+typedef struct iso639_lang_s iso639_lang_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const iso639_lang_t * GetLang_1( const char * psz_iso639_1 );
+const iso639_lang_t * GetLang_2T( const char * psz_iso639_2T );
+const iso639_lang_t * GetLang_2B( const char * psz_iso639_2B );
+const char * DecodeLanguage( uint16_t );
+
+#ifdef __cplusplus
+};
+#endif
+#endif // _ISO_LANG_H_

Added: trunk/DvdMenuXtractor/dmx/vobparser/vobparser.proj
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/DvdMenuXtractor/dmx/vobparser/vobparser.proj	2007-03-10 21:45:2=
8 UTC (rev 1291)
+++ trunk/DvdMenuXtractor/dmx/vobparser/vobparser.proj	2007-03-10 21:46:0=
3 UTC (rev 1292)
@@ -0,0 +1,14 @@
+GROUP vobparser
+{
+  SOURCE IFOContent.cpp
+  SOURCE IFOFile.cpp
+  SOURCE VobParser.cpp
+  SOURCE iso/iso_lang.c
+
+  HEADER IFOContent.h
+  HEADER IFOFile.h
+  HEADER VobParser.h
+  HEADER iso/iso_lang.h
+ =20
+  INCLUDE ..
+}



More information about the Matroska-cvs mailing list