You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
k3b/libk3b/videodvd/k3bvideodvd.cpp

328 lines
11 KiB

/*
*
* $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
* Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
*
* This file is part of the K3b project.
* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* See the file "COPYING" for the exact licensing terms.
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS // needed for *_MAX macros in dvdread headers
#endif
#include "k3bvideodvd.h"
#include <k3bdevice.h>
#include <tqfile.h>
#include <klocale.h>
#include <inttypes.h> // needed by dvdreads headers
#include <dvdread/dvd_reader.h>
#include <dvdread/ifo_types.h>
#include <dvdread/ifo_read.h>
// I don't get this stuff, I should read something about VideoDVD some day...
#define CONVERT_TIME(x) (((x & 0xf0) >> 3) * 5 + (x & 0x0f))
#define CONVERT_FRAME(x) (((x & 0x30) >> 3) * 5 + (x & 0x0f))
K3bVideoDVD::VideoDVD::VideoDVD()
{
}
K3bVideoDVD::VideoDVD::~VideoDVD()
{
}
bool K3bVideoDVD::VideoDVD::valid() const
{
return ( m_device != 0 );
}
bool K3bVideoDVD::VideoDVD::open( K3bDevice::Device* dev )
{
m_device = 0;
m_titles.clear();
//
// Initialize libdvdread
//
dvd_reader_t* dvdReaderT = DVDOpen( TQFile::encodeName(dev->blockDeviceName()) );
if( !dvdReaderT ) {
kdDebug() << "(K3bVideoDVD) Could not open device " << dev->blockDeviceName() << endl;
return false;
}
//
// Read volume id
//
char v[33];
if( DVDUDFVolumeInfo( dvdReaderT, v, 33, 0, 0 ) != 0 &&
DVDISOVolumeInfo( dvdReaderT, v, 33, 0, 0 ) != 0 ) {
kdDebug() << "(K3bVideoDVD) Could not read volume info." << endl;
DVDClose( dvdReaderT );
return false;
}
m_volumeIdentifier = TQString::fromLatin1( v, 32 );
//
// Open the VMG info
//
ifo_handle_t* vmg = ifoOpen( dvdReaderT, 0 );
if( !vmg ) {
kdDebug() << "(K3bVideoDVD) Can't open VMG info." << endl;
DVDClose( dvdReaderT );
return false;
}
//
// parse titles
//
m_titles.resize( vmg->tt_srpt->nr_of_srpts );
for( unsigned int i = 0; i < vmg->tt_srpt->nr_of_srpts; ++i ) {
title_info_t& title = vmg->tt_srpt->title[i];
// m_titles[i].m_videoDVD = this;
//
// general title info
//
m_titles[i].m_titleNum = i+1;
m_titles[i].m_numPTTs = title.nr_of_ptts;
m_titles[i].m_numAngles = title.nr_of_angles;
m_titles[i].m_titleSet = title.title_set_nr;
m_titles[i].m_ttn = title.vts_ttn;
//
// Open the title set the current title is a part of
//
ifo_handle_t* titleIfo = ifoOpen( dvdReaderT, vmg->tt_srpt->title[i].title_set_nr );
if( !titleIfo ) {
kdDebug() << "(K3bVideoDVD) Can't open Title ifo." << endl;
ifoClose( vmg );
DVDClose( dvdReaderT );
return false;
}
//
// Length of this title
//
// the program chain number of the first partoftitle of the current title (FIXME: but a title may contain multiple pgcs)
int pgc_id = titleIfo->vts_ptt_srpt->title[ m_titles[i].ttn() - 1 ].ptt[0].pgcn;
// (first?) program chain of the first partoftitle of the current title
pgc_t* cur_pgc = titleIfo->vts_pgcit->pgci_srp[ pgc_id - 1 ].pgc;
m_titles[i].m_playbackTime = Time( CONVERT_TIME(cur_pgc->playback_time.hour),
CONVERT_TIME(cur_pgc->playback_time.minute),
CONVERT_TIME(cur_pgc->playback_time.second),
CONVERT_FRAME(cur_pgc->playback_time.frame_u) );
//
// Video stream information
//
m_titles[i].m_videoStream.m_permittedDf = titleIfo->vtsi_mat->vts_video_attr.permitted_df;
m_titles[i].m_videoStream.m_displayAspectRatio = titleIfo->vtsi_mat->vts_video_attr.display_aspect_ratio;
m_titles[i].m_videoStream.m_videoFormat = titleIfo->vtsi_mat->vts_video_attr.video_format;
m_titles[i].m_videoStream.m_mpegVersion = titleIfo->vtsi_mat->vts_video_attr.mpeg_version;
m_titles[i].m_videoStream.m_filmMode = titleIfo->vtsi_mat->vts_video_attr.film_mode;
m_titles[i].m_videoStream.m_letterboxed = titleIfo->vtsi_mat->vts_video_attr.letterboxed;
m_titles[i].m_videoStream.m_pictureSize = titleIfo->vtsi_mat->vts_video_attr.picture_size;
m_titles[i].m_videoStream.m_bitRate = titleIfo->vtsi_mat->vts_video_attr.bit_rate;
//
// Audio stream information
//
m_titles[i].m_audioStreams.resize( titleIfo->vtsi_mat->nr_of_vts_audio_streams );
for( unsigned int j = 0; j < titleIfo->vtsi_mat->nr_of_vts_audio_streams; ++j ) {
m_titles[i].m_audioStreams[j].m_format = titleIfo->vtsi_mat->vts_audio_attr[j].audio_format;
m_titles[i].m_audioStreams[j].m_applicationMode = titleIfo->vtsi_mat->vts_audio_attr[j].application_mode;
m_titles[i].m_audioStreams[j].m_quantization = titleIfo->vtsi_mat->vts_audio_attr[j].quantization;
m_titles[i].m_audioStreams[j].m_sampleFrequency = titleIfo->vtsi_mat->vts_audio_attr[j].sample_frequency;
m_titles[i].m_audioStreams[j].m_codeExtension = titleIfo->vtsi_mat->vts_audio_attr[j].code_extension;
m_titles[i].m_audioStreams[j].m_multiChannelExt = titleIfo->vtsi_mat->vts_audio_attr[j].multichannel_extension;
m_titles[i].m_audioStreams[j].m_channels = titleIfo->vtsi_mat->vts_audio_attr[j].channels+1;
if( titleIfo->vtsi_mat->vts_audio_attr[j].lang_type == 1 )
m_titles[i].m_audioStreams[j].m_langCode.sprintf( "%c%c",
titleIfo->vtsi_mat->vts_audio_attr[j].lang_code>>8,
titleIfo->vtsi_mat->vts_audio_attr[j].lang_code & 0xff );
else
m_titles[i].m_audioStreams[j].m_langCode = TQString();
}
//
// SubPicture stream information
//
m_titles[i].m_subPictureStreams.resize( titleIfo->vtsi_mat->nr_of_vts_subp_streams );
for( unsigned int j = 0; j < titleIfo->vtsi_mat->nr_of_vts_subp_streams; ++j ) {
m_titles[i].m_subPictureStreams[j].m_codeMode = titleIfo->vtsi_mat->vts_subp_attr[j].code_mode;
m_titles[i].m_subPictureStreams[j].m_codeExtension = titleIfo->vtsi_mat->vts_subp_attr[j].code_extension;
if( titleIfo->vtsi_mat->vts_subp_attr[j].type == 1 )
m_titles[i].m_subPictureStreams[j].m_langCode.sprintf( "%c%c",
titleIfo->vtsi_mat->vts_subp_attr[j].lang_code>>8,
titleIfo->vtsi_mat->vts_subp_attr[j].lang_code & 0xff );
else
m_titles[i].m_subPictureStreams[j].m_langCode = TQString();
}
//
// add chapter info
//
m_titles[i].m_ptts.resize( m_titles[i].numPTTs() );
for( unsigned int j = 0; j < m_titles[i].numPTTs(); ++j ) {
m_titles[i].m_ptts[j].m_pttNum = j+1;
m_titles[i].m_ptts[j].m_playbackTime = Time( CONVERT_TIME(cur_pgc->cell_playback[j].playback_time.hour),
CONVERT_TIME(cur_pgc->cell_playback[j].playback_time.minute),
CONVERT_TIME(cur_pgc->cell_playback[j].playback_time.second),
CONVERT_FRAME(cur_pgc->cell_playback[j].playback_time.frame_u) );
m_titles[i].m_ptts[j].m_firstSector = cur_pgc->cell_playback[j].first_sector;
m_titles[i].m_ptts[j].m_lastSector = cur_pgc->cell_playback[j].last_sector;
}
ifoClose( titleIfo );
}
ifoClose( vmg );
DVDClose( dvdReaderT );
//
// Setting the device makes this a valid instance
//
m_device = dev;
return true;
}
const K3bVideoDVD::Title& K3bVideoDVD::VideoDVD::title( unsigned int num ) const
{
return m_titles[num];
}
const K3bVideoDVD::Title& K3bVideoDVD::VideoDVD::operator[]( unsigned int num ) const
{
return title( num );
}
void K3bVideoDVD::VideoDVD::debug() const
{
kdDebug() << "VideoDVD information:" << endl
<< "=====================" << endl
<< "Volume ID: " << volumeIdentifier() << endl << endl;
for( unsigned int i = 0; i < numTitles(); ++i ) {
kdDebug() << "Title " << title(i).titleNumber() << " (" << title(i).playbackTime().toString() << ")" << endl
<< " Chapters: " << title(i).numPTTs() << endl
<< " Angles: " << title(i).numAngles() << endl
<< " VTS,TTN: " << title(i).titleSet() << "," << title(i).ttn() << endl
<< " Audio Streams:" << endl;
for( unsigned int j = 0; j < title(i).numAudioStreams(); ++j )
kdDebug() << " " << title(i).audioStream(j).langCode() << ": "
<< audioFormatString( title(i).audioStream(j).format() ) << ", "
<< audioCodeExtensionString( title(i).audioStream(j).codeExtension() ) << endl;
kdDebug() << " SubPicture Streams:" << endl;
for( unsigned int j = 0; j < title(i).numSubPictureStreams(); ++j )
kdDebug() << " " << title(i).subPictureStream(j).langCode() << ": "
<< subPictureCodeModeString( title(i).subPictureStream(j).codeMode() ) << ", "
<< subPictureCodeExtensionString( title(i).subPictureStream(j).codeExtension() ) << endl;
}
}
TQString K3bVideoDVD::audioFormatString( int format )
{
switch( format ) {
case AUDIO_FORMAT_AC3:
return i18n("AC3");
case AUDIO_FORMAT_MPEG1:
return i18n("MPEG1");
case AUDIO_FORMAT_MPEG2EXT:
return i18n("MPEG2 Extended");
case AUDIO_FORMAT_LPCM:
return i18n("LPCM");
case AUDIO_FORMAT_DTS:
return i18n("DTS");
default:
return i18n("unknown audio format");
}
}
TQString K3bVideoDVD::audioCodeExtensionString( int ext )
{
switch( ext ) {
case AUDIO_CODE_EXT_UNSPECIFIED:
return i18n("Unspecified");
case AUDIO_CODE_EXT_NORMAL:
return i18n("Normal");
case AUDIO_CODE_EXT_VISUALLY_IMPAIRED:
return i18n("For the visually impaired");
case AUDIO_CODE_EXT_DIR_COMMENTS_1:
return i18n("Director's comments 1");
case AUDIO_CODE_EXT_DIR_COMMENTS_2:
return i18n("Director's comments 2");
default:
return i18n("unknown audio code extension");
}
}
TQString K3bVideoDVD::subPictureCodeModeString( int mode )
{
switch( mode ) {
case SUBPIC_CODE_MODE_RLE:
return i18n("RLE");
case SUBPIC_CODE_MODE_EXT:
return i18n("Extended");
default:
return i18n("unknown coding mode");
}
}
TQString K3bVideoDVD::subPictureCodeExtensionString( int ext )
{
switch( ext ) {
case SUBPIC_CODE_EXT_UNSPECIFIED:
return i18n("Unspecified");
case SUBPIC_CODE_EXT_CAPTION_NORMAL_SIZE:
return i18n("Caption with normal size character");
case SUBPIC_CODE_EXT_CAPTION_BIGGER_SIZE:
return i18n("Caption with bigger size character");
case SUBPIC_CODE_EXT_CAPTION_FOR_CHILDREN:
return i18n("Caption for children");
case SUBPIC_CODE_EXT_CLOSED_CAPTION_NORMAL_SIZE:
return i18n("Closed caption with normal size character");
case SUBPIC_CODE_EXT_CLOSED_CAPTION_BIGGER_SIZE:
return i18n("Closed caption with bigger size character");
case SUBPIC_CODE_EXT_CLOSED_CAPTION_FOR_CHILDREN:
return i18n("Closed caption for children");
case SUBPIC_CODE_EXT_FORCED_CAPTION:
return i18n("Forced caption");
case SUBPIC_CODE_EXT_DIR_COMMENTS_NORMAL_SIZE:
return i18n("Director's comments with normal size characters");
case SUBPIC_CODE_EXT_DIR_COMMENTS_BIGGER_SIZE:
return i18n("Director's comments with bigger size characters");
case SUBPIC_CODE_EXT_DIR_COMMENTS_FOR_CHILDREN:
return i18n("Director's comments for children");
default:
return i18n("unknown code extension");
}
}