📄 mpeg3ifo.c
字号:
#include <mpeg4ip.h>
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#endif
#include <mpeg4ip_byteswap.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "ifo.h"
#include "mpeg3private.h"
#include "mpeg3protos.h"
typedef struct
{
int64_t start_byte;
int64_t end_byte;
// Used in final table
int program;
// Used in cell play info
int cell_type;
// Used in cell addresses
int vob_id;
int cell_id;
} mpeg3ifo_cell_t;
typedef struct
{
mpeg3ifo_cell_t *cells;
long total_cells;
long cells_allocated;
} mpeg3ifo_celltable_t;
#define CADDR_HDR_LEN 8
typedef struct {
u_short num : 16; // Number of Video Objects
u_short unknown : 16; // don't know
u_int len : 32; // length of table
} cell_addr_hdr_t;
typedef struct {
u_int foo : 16; // ???
u_int num : 16; // number of subchannels
} audio_hdr_t;
#define AUDIO_HDR_LEN 4
typedef struct {
u_short id : 16; // Language
u_short : 16; // don't know
u_int start : 32; // Start of unit
} pgci_sub_t;
#define PGCI_SUB_LEN 8
#define PGCI_COLOR_LEN 4
static u_int get4bytes(u_char *buf)
{
return B2N_32(*((u_int32_t *)buf));
}
static u_int get2bytes(u_char *buf)
{
return B2N_16(*((u_int16_t *)buf));
}
static int ifo_read(int fd, long pos, long count, unsigned char *data)
{
if((pos = lseek(fd, pos, SEEK_SET)) < 0)
{
perror("ifo_read");
return -1;
}
return read(fd, data, count);
}
#define OFF_PTT get4bytes (ifo->data[ID_MAT] + 0xC8)
#define OFF_TITLE_PGCI get4bytes (ifo->data[ID_MAT] + 0xCC)
#define OFF_MENU_PGCI get4bytes (ifo->data[ID_MAT] + 0xD0)
#define OFF_TMT get4bytes (ifo->data[ID_MAT] + 0xD4)
#define OFF_MENU_CELL_ADDR get4bytes (ifo->data[ID_MAT] + 0xD8)
#define OFF_MENU_VOBU_ADDR_MAP get4bytes (ifo->data[ID_MAT] + 0xDC)
#define OFF_TITLE_CELL_ADDR get4bytes (ifo->data[ID_MAT] + 0xE0)
#define OFF_TITLE_VOBU_ADDR_MAP get4bytes (ifo->data[ID_MAT] + 0xE4)
#define OFF_VMG_TSP get4bytes (ifo->data[ID_MAT] + 0xC4)
#define OFF_VMG_MENU_PGCI get4bytes (ifo->data[ID_MAT] + 0xC8)
#define OFF_VMG_TMT get4bytes (ifo->data[ID_MAT] + 0xD0)
static int ifo_vts(ifo_t *ifo)
{
if(!strncmp((char*)ifo->data[ID_MAT], "DVDVIDEO-VTS", 12))
return 0;
return -1;
}
static int ifo_vmg(ifo_t *ifo)
{
if(!strncmp((char*)ifo->data[ID_MAT], "DVDVIDEO-VMG", 12))
return 0;
return -1;
}
static int ifo_table(ifo_t *ifo, unsigned long offset, unsigned long tbl_id)
{
unsigned char *data;
unsigned long len = 0;
int i;
u_int32_t *ptr;
if(!offset) return -1;
data = (u_char *)calloc(1, DVD_VIDEO_LB_LEN);
if(ifo_read(ifo->fd, ifo->pos + offset * DVD_VIDEO_LB_LEN, DVD_VIDEO_LB_LEN, data) <= 0)
{
perror("ifo_table");
return -1;
}
switch(tbl_id)
{
case ID_TITLE_VOBU_ADDR_MAP:
case ID_MENU_VOBU_ADDR_MAP:
len = get4bytes(data) + 1;
break;
default:
{
ifo_hdr_t *hdr = (ifo_hdr_t *)data;
len = B2N_32(hdr->len) + 1;
}
}
if(len > DVD_VIDEO_LB_LEN)
{
data = (u_char *)realloc((void *)data, len);
bzero(data, len);
ifo_read(ifo->fd, ifo->pos + offset * DVD_VIDEO_LB_LEN, len, data);
}
ifo->data[tbl_id] = data;
ptr = (u_int32_t*)data;
len /= 4;
if(tbl_id == ID_TMT)
for (i = 0; i < len; i++)
ptr[i] = B2N_32(ptr[i]);
return 0;
}
static ifo_t* ifo_open(int fd, long pos)
{
ifo_t *ifo;
ifo = (ifo_t *)calloc(sizeof(ifo_t), 1);
ifo->data[ID_MAT] = (unsigned char *)calloc(DVD_VIDEO_LB_LEN, 1);
ifo->pos = pos;
ifo->fd = fd;
if(ifo_read(fd, pos, DVD_VIDEO_LB_LEN, ifo->data[ID_MAT]) < 0)
{
perror("ifo_open");
free(ifo->data[ID_MAT]);
free(ifo);
return NULL;
}
ifo->num_menu_vobs = get4bytes(ifo->data[ID_MAT] + 0xC0);
ifo->vob_start = get4bytes(ifo->data[ID_MAT] + 0xC4);
#ifdef DEBUG
printf ("num of vobs: %x vob_start %x\n", ifo->num_menu_vobs, ifo->vob_start);
#endif
if(!ifo_vts(ifo))
{
ifo_table(ifo, OFF_PTT, ID_PTT);
ifo_table(ifo, OFF_TITLE_PGCI, ID_TITLE_PGCI);
ifo_table(ifo, OFF_MENU_PGCI, ID_MENU_PGCI);
ifo_table(ifo, OFF_TMT, ID_TMT);
ifo_table(ifo, OFF_MENU_CELL_ADDR, ID_MENU_CELL_ADDR);
ifo_table(ifo, OFF_MENU_VOBU_ADDR_MAP, ID_MENU_VOBU_ADDR_MAP);
ifo_table(ifo, OFF_TITLE_CELL_ADDR, ID_TITLE_CELL_ADDR);
ifo_table(ifo, OFF_TITLE_VOBU_ADDR_MAP, ID_TITLE_VOBU_ADDR_MAP);
}
else
if(!ifo_vmg(ifo))
{
ifo_table(ifo, OFF_VMG_TSP, ID_TSP);
ifo_table(ifo, OFF_VMG_MENU_PGCI, ID_MENU_PGCI);
ifo_table(ifo, OFF_VMG_TMT, ID_TMT);
ifo_table(ifo, OFF_TITLE_CELL_ADDR, ID_TITLE_CELL_ADDR);
ifo_table(ifo, OFF_TITLE_VOBU_ADDR_MAP, ID_TITLE_VOBU_ADDR_MAP);
}
return ifo;
}
static int ifo_close(ifo_t *ifo)
{
if(ifo->data[ID_MAT]) free(ifo->data[ID_MAT]);
if(ifo->data[ID_PTT]) free(ifo->data[ID_PTT]);
if(ifo->data[ID_TITLE_PGCI]) free(ifo->data[ID_TITLE_PGCI]);
if(ifo->data[ID_MENU_PGCI]) free(ifo->data[ID_MENU_PGCI]);
if(ifo->data[ID_TMT]) free(ifo->data[ID_TMT]);
if(ifo->data[ID_MENU_CELL_ADDR]) free(ifo->data[ID_MENU_CELL_ADDR]);
if(ifo->data[ID_MENU_VOBU_ADDR_MAP]) free(ifo->data[ID_MENU_VOBU_ADDR_MAP]);
if(ifo->data[ID_TITLE_CELL_ADDR]) free(ifo->data[ID_TITLE_CELL_ADDR]);
if(ifo->data[ID_TITLE_VOBU_ADDR_MAP]) free(ifo->data[ID_TITLE_VOBU_ADDR_MAP]);
free(ifo);
return 0;
}
static int ifo_audio(char *_hdr, char **ptr)
{
audio_hdr_t *hdr = (audio_hdr_t *)_hdr;
if(!_hdr) return -1;
*ptr = _hdr + AUDIO_HDR_LEN;
return B2N_16(hdr->num);
}
static int pgci(ifo_hdr_t *hdr, int title, char **ptr)
{
pgci_sub_t *pgci_sub;
uint32_t temp;
*ptr = (char *) hdr;
if(!*ptr) return -1;
if(title > hdr->num) return -1;
*ptr += IFO_HDR_LEN;
pgci_sub = (pgci_sub_t *)*ptr + title;
temp = pgci_sub->start;
temp = B2N_32(temp);
*ptr = (char *)hdr + temp;
return 0;
}
static int program_map(char *pgc, char **ptr)
{
int num;
*ptr = pgc;
if (!pgc)
return -1;
*ptr += 2;
num = **ptr;
*ptr += 10;
*ptr += 8 * 2; // AUDIO
*ptr += 32 * 4; // SUBPICTURE
*ptr += 8;
*ptr += 16 * PGCI_COLOR_LEN; // CLUT
*ptr += 2;
*ptr = get2bytes((unsigned char*)*ptr) + pgc;
return num;
}
static u_int get_cellplayinfo(u_char *pgc, u_char **ptr)
{
u_int num;
*ptr = pgc;
if (!pgc)
return -1;
*ptr += 3;
num = **ptr;
*ptr += 9;
*ptr += 8 * 2; // AUDIO
*ptr += 32 * 4; // SUBPICTURE
*ptr += 8;
*ptr += 16 * PGCI_COLOR_LEN; // CLUT
*ptr += 4;
*ptr = get2bytes(*ptr) + pgc;
return num;
}
static void get_ifo_playlist(mpeg3_t *file, mpeg3_demuxer_t *demuxer)
{
DIR *dirstream;
char directory[MPEG3_STRLEN];
char filename[MPEG3_STRLEN];
char complete_path[MPEG3_STRLEN];
char title_path[MPEG3_STRLEN];
char vob_prefix[MPEG3_STRLEN];
struct dirent *new_filename;
char *ptr;
int64_t total_bytes = 0;
int done = 0, i;
// Get titles matching ifo file
mpeg3io_complete_path(complete_path, file->fs->path);
mpeg3io_get_directory(directory, complete_path);
mpeg3io_get_filename(filename, complete_path);
strncpy(vob_prefix, filename, 6);
dirstream = opendir(directory);
while(new_filename = readdir(dirstream))
{
if(!strncasecmp(new_filename->d_name, vob_prefix, 6))
{
ptr = strrchr(new_filename->d_name, '.');
if(ptr && !strncasecmp(ptr, ".vob", 4))
{
// Got a title
if(atol(&new_filename->d_name[7]) > 0)
{
mpeg3_title_t *title;
mpeg3io_joinpath(title_path, directory, new_filename->d_name);
title = demuxer->titles[demuxer->total_titles++] = mpeg3_new_title(file, title_path);
title->total_bytes = mpeg3io_path_total_bytes(title_path);
total_bytes += title->total_bytes;
//printf("%s\n", title_path);
}
}
}
}
// Alphabetize titles. Only problematic for guys who rip entire DVD's
// to their hard drives while retaining the file structure.
while(!done)
{
done = 1;
for(i = 0; i < demuxer->total_titles - 1; i++)
{
if(strcmp(demuxer->titles[i]->fs->path, demuxer->titles[i + 1]->fs->path) > 0)
{
mpeg3_title_t *temp = demuxer->titles[i];
demuxer->titles[i] = demuxer->titles[i + 1];
demuxer->titles[i + 1] = temp;
done = 0;
}
}
}
}
// IFO parsing
static void get_ifo_header(mpeg3_demuxer_t *demuxer, ifo_t *ifo)
{
int i;
// Video header
demuxer->vstream_table[0] = 1;
// Audio header
if(!ifo_vts(ifo))
{
ifo_audio_t *audio;
int result = 0;
// Doesn't detect number of tracks.
int atracks = ifo_audio((char*)ifo->data[ID_MAT] + IFO_OFFSET_AUDIO, (char**)&audio);
int atracks_empirical = 0;
// Construct audio stream id's
#define TEST_START 0x600000
#define TEST_LEN 0x100000
mpeg3demux_open_title(demuxer, 0);
mpeg3demux_seek_byte(demuxer, TEST_START);
while(!result &&
!mpeg3demux_eof(demuxer) &&
mpeg3demux_tell(demuxer) < TEST_START + TEST_LEN)
{
result = mpeg3_read_next_packet(demuxer);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -