[MPlayer-users] Problematic DVD [SOLVED]
jezz at hkfree.org
jezz at hkfree.org
Sat Sep 27 09:01:13 CEST 2008
Hi,
should I send this patch to mplayer devel mailing list in order to get it into
libdvdread?
On Pá 19.zář, jezz at hkfree.org wrote:
> Hi,
> according to UDF spec this DVD is broken. I tried to discover, why some players
> are ok (totem-xine on my system). Totem mounts the DVD and then plays files
> directly. From mplayer I can play VOB directly, but there is garbage in video
> (CSS?). DVDNav is not working. Kernel reads this DVD as ISO 9660 filesystem. So
> can libdvdread. I have implemented ISOFindFile(...) function from this spec:
> http://alumnus.caltech.edu/~pje/iso9660.html
> When file can't be located with UDF functions, then we can try ISO. This fix
> conforms with standards and plays my disks :)
> ISOFindFile is used as fallback - may be we can allow user to change the order
> with environment variable?
> Any comments are welcome.
>
> On Pá 5.zář, Nico Sabbi wrote:
> > On Friday 05 September 2008 17:58:31 jezz at hkfree.org wrote:
> > > Hi,
> > > I have found the problem. It is in UDF structure. In ICB for
> > > /VIDEO_TS/VTS_37_0.VOB there is Tag Identifier 262 (Extended
> > > Attribute Header Descriptor) instead of common 261 (File Entry). I
> > > don't read UDF spec, so I don't know if this is correct, but with
> > > attached patch I can play this DVD.
> > >
> > > Jezz
> > >
> > > On So 30.srp, jezz at hkfree.org wrote:
> > > > Hi,
> > > > I have one DVD, that I can't play with mplayer. Some players are
> > > > fine. This dvd contains movie and boring tracks with
> > > > advertisments, etc. But I can't play track with movie (track 37).
> >
> > interesting. Is there any publicly available spec regarding UDF?
> > Thanks for the patch, but before committing it I have to verify that
> > it's correct
> > _______________________________________________
> > MPlayer-users mailing list
> > MPlayer-users at mplayerhq.hu
> > https://lists.mplayerhq.hu/mailman/listinfo/mplayer-users
>
> --
> Jezz
> mail: jezz at hkfree.org
> jabber: jezz at njs.netlab.cz
> Index: src/dvd_reader.c
> ===================================================================
> --- src/dvd_reader.c (revision 1148)
> +++ src/dvd_reader.c (working copy)
> @@ -66,6 +66,7 @@
> #endif
>
> #include "dvd_udf.h"
> +#include "dvd_iso9660.h"
> #include "dvd_input.h"
> #include "dvd_reader.h"
> #include "md5.h"
> @@ -152,7 +153,16 @@
> }
>
>
> +/* Find file on UDF first or try it on ISO9660 FS */
> +uint32_t DVDFindFile( dvd_reader_t *device, char *filename, uint32_t *size )
> +{
> + uint32_t result;
> + result = UDFFindFile(device, filename, size);
> + if (result > 0) return result;
> + return ISOFindFile(device, filename, size);
> +}
>
> +
> /* Loop over all titles and call dvdcss_title to crack the keys. */
> static int initAllCSSKeys( dvd_reader_t *dvd )
> {
> @@ -180,7 +190,7 @@
> } else {
> sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 0 );
> }
> - start = UDFFindFile( dvd, filename, &len );
> + start = DVDFindFile( dvd, filename, &len );
> if( start != 0 && len != 0 ) {
> /* Perform CSS key cracking for this title. */
> fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n",
> @@ -197,7 +207,7 @@
>
> gettimeofday( &t_s, NULL );
> sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 1 );
> - start = UDFFindFile( dvd, filename, &len );
> + start = DVDFindFile( dvd, filename, &len );
> if( start == 0 || len == 0 ) break;
>
> /* Perform CSS key cracking for this title. */
> @@ -569,9 +579,9 @@
> uint32_t start, len;
> dvd_file_t *dvd_file;
>
> - start = UDFFindFile( dvd, filename, &len );
> + start = DVDFindFile( dvd, filename, &len );
> if( !start ) {
> - fprintf( stderr, "libdvdnav:DVDOpenFileUDF:UDFFindFile %s failed\n", filename );
> + fprintf( stderr, "libdvdnav:DVDOpenFileUDF:DVDFindFile %s failed\n", filename );
> return NULL;
> }
>
> @@ -707,7 +717,7 @@
> } else {
> sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 );
> }
> - start = UDFFindFile( dvd, filename, &len );
> + start = DVDFindFile( dvd, filename, &len );
> if( start == 0 ) return NULL;
>
> dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
> @@ -726,7 +736,7 @@
>
> for( cur = 2; cur < 10; cur++ ) {
> sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur );
> - if( !UDFFindFile( dvd, filename, &len ) ) break;
> + if( !DVDFindFile( dvd, filename, &len ) ) break;
> dvd_file->filesize += len / DVD_VIDEO_LB_LEN;
> }
> }
> Index: src/dvd_iso9660.c
> ===================================================================
> --- src/dvd_iso9660.c (revision 0)
> +++ src/dvd_iso9660.c (revision 0)
> @@ -0,0 +1,357 @@
> +/* vim:ts=4:sw=4:et
> + *
> + * Some parts taken from dvd_udf.c
> + *
> + * Miroslav Jezbera <jezz at hkfree.org>
> + *
> + * dvd_iso9660: parse and read the ISO9660 filesystem (hybrid ISO+UDF DVD disks)
> + *
> + * 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.
> + *
> + * 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-1307, USA. Or, point your browser to
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +
> +#include "config.h"
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <strings.h>
> +#include <ctype.h>
> +#include <inttypes.h>
> +#include <assert.h>
> +
> +#include "dvd_reader.h"
> +#include "dvd_iso9660.h"
> +
> +/* Private but located in/shared with dvd_reader.c */
> +extern int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number,
> + size_t block_count, unsigned char *data,
> + int encrypted );
> +
> +/* Macros */
> +#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) && !defined(WORDS_BIGENDIAN)
> +# define LITTLE_ENDIAN
> +#endif /* LITTLE_ENDIAN */
> +
> +/*
> +#define ISO_DEBUG 1
> +*/
> +
> +#define FAILURE 0
> +#define SUCCESS 1
> +
> +#define ISO_SECTOR_SIZE DVD_VIDEO_LB_LEN
> +#define ISO_TBL_REC_NAME_MAX 31
> +#define ISO_MAX_PATH_NESTING 8
> +
> +#define ISO_FIRST_VOL_DESC_SECTOR 16
> +#define ISO_LAST_VOL_DESC_SECTOR 17
> +#define ISO_VOL_DESC_HEADER "\01CD001\01"
> +
> +#define READ_WORD_LE(ptr) (uint16_t)(((uint8_t *)ptr)[0] | ((uint8_t *)ptr)[1] << 8)
> +#define READ_DWORD_LE(ptr) (uint32_t)(((uint8_t *)ptr)[0] | ((uint8_t *)ptr)[1] << 8 | \
> + ((uint8_t *)ptr)[2] << 16 | ((uint8_t *)ptr)[3] << 24)
> +
> +#define IS_DIRECTORY(flags) (((flags)&2)!=0)
> +
> +#ifdef LITTLE_ENDIAN
> +# define ISO_DIR_REC_FILE_POS 2
> +# define ISO_DIR_REC_FILE_SIZE 10
> +#else /* !LITTLE_ENDIAN */
> +# define ISO_DIR_REC_FILE_POS 6
> +# define ISO_DIR_REC_FILE_SIZE 14
> +#endif /* !LITTLE_ENDIAN */
> +#define ISO_DIR_REC_FILE_FLAGS 25
> +#define ISO_DIR_REC_NAME_LEN 32
> +
> +/* Types */
> +typedef uint8_t iso_sector_t[ISO_SECTOR_SIZE];
> +
> +struct iso_volume_desc_t
> + {
> + char mSysId[33];
> + char mVolId[33];
> + uint32_t mSectorsCnt;
> + uint32_t mPathTblLen;
> + uint32_t mFirstPathTblStart;
> + uint32_t mSecondPathTblStart;
> + };
> +
> +struct iso_path_table_record_t
> + {
> + uint8_t mRecordIdx;
> + uint8_t mNameLen;
> + uint32_t mDirectoryFirstSector;
> + uint16_t mParentDirRecordIdx;
> + char mName[ISO_TBL_REC_NAME_MAX+1];
> + struct iso_path_table_record_t *next;
> + };
> +
> +/* Common functions */
> +char *Rtrim(char *str)
> + {
> + char *ptr;
> + if (str == NULL) return NULL;
> + ptr = str + strlen(str) - 1;
> + while (ptr >= str && isspace(ptr[0])) --ptr;
> + ptr[1] = '\0';
> + return str;
> + }
> +
> +/* Functions for ISO FS */
> +int
> +iso_read_volume_descriptor(dvd_reader_t *aDevice, struct iso_volume_desc_t *aVolumeDesc)
> + {
> + iso_sector_t content;
> + uint32_t sector;
> + int result = FAILURE;
> +
> + for (sector = ISO_FIRST_VOL_DESC_SECTOR; sector <= ISO_LAST_VOL_DESC_SECTOR; ++sector)
> + {
> + if (UDFReadBlocksRaw(aDevice, sector, 1, content, 0) <= 0) continue;
> + if (strcmp((char *)content, ISO_VOL_DESC_HEADER) == 0)
> + {
> + result = SUCCESS;
> + break;
> + }
> + }
> + if (result != SUCCESS) return result;
> + memset((void *)aVolumeDesc, 0, sizeof(struct iso_volume_desc_t));
> + memcpy((void *)aVolumeDesc->mSysId, (void *)&content[8], 32);
> + memcpy((void *)aVolumeDesc->mVolId, (void *)&content[40], 32);
> + Rtrim((char *)aVolumeDesc->mSysId);
> + Rtrim((char *)aVolumeDesc->mVolId);
> +#ifdef LITTLE_ENDIAN
> + aVolumeDesc->mSectorsCnt = *(uint32_t *)&content[80];
> + assert(*(uint16_t *)&content[128] == 2048);
> + aVolumeDesc->mPathTblLen = *(uint32_t *)&content[132];
> + aVolumeDesc->mFirstPathTblStart = *(uint32_t *)&content[140];
> + aVolumeDesc->mSecondPathTblStart = *(uint32_t *)&content[144];
> +#else /* !LITTLE_ENDIAN */
> + aVolumeDesc->mSectorsCnt = *(uint32_t *)&content[84];
> + assert(*(uint16_t *)&content[130] == 2048);
> + aVolumeDesc->mPathTblLen = *(uint32_t *)&content[136];
> + aVolumeDesc->mFirstPathTblStart = *(uint32_t *)&content[148];
> + aVolumeDesc->mSecondPathTblStart = *(uint32_t *)&content[152];
> +#endif /* !LITTLE_ENDIAN */
> + return SUCCESS;
> + }
> +
> +void
> +iso_path_table_free(struct iso_path_table_record_t *list)
> + {
> + struct iso_path_table_record_t *ptr;
> + while (list != NULL)
> + {
> + ptr = list;
> + list = list->next;
> + free(ptr);
> + }
> + }
> +
> +int
> +iso_read_path_table(dvd_reader_t *aDevice, struct iso_volume_desc_t *aVolumeDesc, struct iso_path_table_record_t **aRecords)
> + {
> + uint8_t *content, *ptr;
> + uint32_t sector, last_sector;
> + struct iso_path_table_record_t head, *current = &head;
> + uint8_t recordIdx = 0;
> +
> + assert(aRecords != NULL);
> + if (aVolumeDesc->mPathTblLen == 0) return FAILURE;
> + sector = aVolumeDesc->mFirstPathTblStart;
> + last_sector = sector + (aVolumeDesc->mPathTblLen - 1) / ISO_SECTOR_SIZE;
> + content = (uint8_t *)malloc(ISO_SECTOR_SIZE * (last_sector - sector + 1));
> + if (content == NULL) return FAILURE;
> + for (ptr = content; sector <= last_sector; ++sector, ptr += ISO_SECTOR_SIZE)
> + {
> + if (UDFReadBlocksRaw(aDevice, sector, 1, ptr, 0) <= 0)
> + {
> + free(content);
> + return FAILURE;
> + }
> + }
> + for (ptr = content; ptr < content + aVolumeDesc->mPathTblLen;)
> + {
> + current->next = (struct iso_path_table_record_t *)malloc(sizeof(struct iso_path_table_record_t));
> + if (current->next == NULL)
> + {
> + free(content);
> + iso_path_table_free(head.next);
> + return FAILURE;
> + }
> + current = current->next;
> + memset((void *)current, 0, sizeof(struct iso_path_table_record_t));
> + current->mRecordIdx = ++recordIdx;
> + current->mNameLen = *ptr;
> + assert(current->mNameLen > 0 && current->mNameLen <= ISO_TBL_REC_NAME_MAX);
> + current->mDirectoryFirstSector = READ_DWORD_LE(ptr + 2);
> + current->mParentDirRecordIdx = READ_WORD_LE(ptr + 6);
> + memcpy((void *)current->mName, ptr + 8, current->mNameLen);
> + ptr += 8 + ((current->mNameLen + 1) & ~1);
> +#ifdef ISO_DEBUG
> + fprintf(stderr,
> + "Name length: %u\n"
> + "Directory first sector: %u\n"
> + "Parent directory record: %hu\n"
> + "Name: \"%s\"\n"
> + , (int)current->mNameLen, current->mDirectoryFirstSector,
> + current->mParentDirRecordIdx, current->mName);
> +#endif /* ISO_DEBUG */
> + }
> + assert(content + aVolumeDesc->mPathTblLen == ptr);
> + free(content);
> + *aRecords = head.next;
> +
> + return SUCCESS;
> + }
> +
> +uint32_t
> +iso_search_directory(dvd_reader_t *aDevice, uint32_t aDirectorySector, char *aFilename, uint32_t *aFileSize)
> + {
> + uint32_t directorySize = ISO_SECTOR_SIZE, position, filePosition, fileSize;
> + uint8_t recordSize, identifierSize, flags;
> + iso_sector_t content;
> + char identifier[256];
> + int filenameLen;
> +
> + *aFileSize = 0;
> + filenameLen = strlen(aFilename);
> + if (UDFReadBlocksRaw(aDevice, aDirectorySector, 1, content, 0) <= 0)
> + {
> + return 0;
> + }
> + for (position = 0; position < directorySize; position += recordSize)
> + {
> + if (position >= ISO_SECTOR_SIZE || content[position] == 0)
> + {
> + if (directorySize <= ISO_SECTOR_SIZE) return 0;
> + if (UDFReadBlocksRaw(aDevice, ++aDirectorySector, 1, content, 0) <= 0)
> + {
> + return 0;
> + }
> + position = 0;
> + directorySize -= ISO_SECTOR_SIZE;
> + }
> + recordSize = content[position];
> + if (recordSize == 0) break;
> + filePosition = READ_DWORD_LE(&content[position + ISO_DIR_REC_FILE_POS]);
> + fileSize = READ_DWORD_LE(&content[position + ISO_DIR_REC_FILE_SIZE]);
> + flags = content[position + ISO_DIR_REC_FILE_FLAGS];
> + identifierSize = content[position + ISO_DIR_REC_NAME_LEN];
> + memcpy((void *)identifier, (void *)&content[position + ISO_DIR_REC_NAME_LEN + 1], identifierSize);
> + identifier[identifierSize] = '\0';
> + if (identifierSize == 1 && identifier[0] == 0) /* current directory */
> + {
> + assert(IS_DIRECTORY(flags));
> + directorySize = fileSize;
> + }
> +#ifdef ISO_DEBUG
> + fprintf(stderr,
> + "record size: %u\n"
> + "file position: %u\n"
> + "file size: %u\n"
> + "directory: %d\n"
> + "name size: %u\n"
> + "name: \"%s\"\n"
> + , (int)recordSize, filePosition, fileSize, (int)IS_DIRECTORY(flags),
> + (int)identifierSize, identifier);
> +#endif /* ISO_DEBUG */
> + if (!IS_DIRECTORY(flags) && (filenameLen == identifierSize ||
> + (filenameLen < identifierSize && identifier[filenameLen] == ';')) &&
> + strncasecmp(aFilename, identifier, filenameLen) == 0)
> + {
> + return filePosition;
> + *aFileSize = fileSize;
> + }
> + }
> +
> + return 0;
> + }
> +
> +/* Public interface */
> +uint32_t ISOFindFile(dvd_reader_t *aDevice, char *aFilename, uint32_t *aFileSize)
> + {
> + struct iso_volume_desc_t volumeDesc;
> + struct iso_path_table_record_t *directories, *current;
> + char *path, *rest, *part, *file, last;
> + int parentIdx;
> + uint32_t directoryPosition;
> +
> + *aFileSize = 0;
> + if (aFilename == NULL || aFilename[0] == '\0') return 0;
> + if (iso_read_volume_descriptor(aDevice, &volumeDesc) != SUCCESS)
> + {
> + return 0;
> + }
> +#ifdef ISO_DEBUG
> + fprintf(stderr,
> + "System identifier: \"%s\"\n"
> + "Volume identifier: \"%s\"\n"
> + "Sectors count: %u\n"
> + "Path table length: %u\n"
> + "First path table: %u\n"
> + "Second path table: %u\n"
> + , volumeDesc.mSysId, volumeDesc.mVolId, volumeDesc.mSectorsCnt, volumeDesc.mPathTblLen,
> + volumeDesc.mFirstPathTblStart, volumeDesc.mSecondPathTblStart);
> +#endif /* ISO_DEBUG */
> + if (iso_read_path_table(aDevice, &volumeDesc, &directories) != SUCCESS)
> + {
> + return 0;
> + }
> +
> + parentIdx = 1; /* root directory */
> + current = directories;
> + path = rest = strdup(aFilename);
> + file = strrchr(path, '/');
> + if (file != NULL)
> + {
> + *file = '\0';
> + file = aFilename + (file - path + 1);
> + last = '/';
> + }
> + else
> + {
> + file = path;
> + last = '\0';
> + }
> + while (last != '\0' && *rest != '\0' && current != NULL)
> + {
> + while (*rest == '/') rest++;
> + part = rest;
> + while (*rest != '/' && *rest != '\0') rest++;
> + last = *rest;
> + *rest++ = '\0';
> + /* compare part of path with ISO path table entries */
> + while (current != NULL && (parentIdx != current->mParentDirRecordIdx ||
> + strcasecmp(current->mName, part) != 0)) current = current->next;
> + if (current != NULL)
> + {
> + parentIdx = current->mRecordIdx;
> + }
> + }
> +
> + if (current == NULL)
> + {
> + iso_path_table_free(directories);
> + free(path);
> + return 0;
> + }
> + directoryPosition = current->mDirectoryFirstSector;
> + iso_path_table_free(directories);
> + free(path);
> + return iso_search_directory(aDevice, directoryPosition, file, aFileSize);
> + }
> Index: src/dvd_iso9660.h
> ===================================================================
> --- src/dvd_iso9660.h (revision 0)
> +++ src/dvd_iso9660.h (revision 0)
> @@ -0,0 +1,47 @@
> +/*
> + *
> + * Miroslav Jezbera <jezz at hkfree.org>
> + *
> + * dvd_iso9660: parse and read the ISO9660 filesystem (hybrid ISO+UDF DVD disks)
> + *
> + * 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.
> + *
> + * 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-1307, USA. Or, point your browser to
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +#ifndef DVD_ISO9660_H
> +#define DVD_ISO9660_H 1
> +
> +#include <inttypes.h>
> +
> +#include "dvd_reader.h"
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif /* __cplusplus */
> +
> +/**
> + * Looks for a file on the hybrid ISO9660/mini-UDF disc/imagefile and returns
> + * the block number where it begins, or 0 if it is not found. The filename
> + * should be an absolute pathname on the UDF filesystem, starting with '/'.
> + * For example '/VIDEO_TS/VTS_01_1.IFO'. On success, filesize will be set to
> + * the size of the file in bytes.
> + */
> +uint32_t ISOFindFile(dvd_reader_t *aDevice, char *aFilename, uint32_t *aFileSize);
> +
> +#ifdef __cplusplus
> +}
> +#endif /* __cplusplus */
> +
> +#endif /* DVD_ISO9660_H */
> Index: src/Makefile.am
> ===================================================================
> --- src/Makefile.am (revision 1148)
> +++ src/Makefile.am (working copy)
> @@ -8,7 +8,8 @@
>
> libdvdread_la_SOURCES = dvd_reader.c nav_read.c ifo_read.c \
> dvd_input.c dvd_udf.c md5.c nav_print.c ifo_print.c bitreader.c \
> - bswap.h dvd_input.h dvdread_internal.h dvd_udf.h md5.h bitreader.h
> + bswap.h dvd_input.h dvdread_internal.h dvd_udf.h md5.h bitreader.h \
> + dvd_iso9660.c dvd_iso9660.h
>
> libdvdread_la_LIBADD = $(DYNAMIC_LD_LIBS)
>
--
Jezz
mail: jezz at hkfree.org
jabber: jezz at njs.netlab.cz
More information about the MPlayer-users
mailing list