📄 vobsub.cpp
字号:
/*
* Some code freely inspired from VobSub <URL:http://vobsub.edensrising.com>,
* with kind permission from Gabest <gabest@freemail.hu>
*
* to ffdshow imported from mplayer
*/
#include "stdafx.h"
#include "ffdebug.h"
#include "Tstream.h"
#include "vobsub.h"
#include "spudec.h"
#include "IffdshowBase.h"
#include "Tsubreader.h"
/**********************************************************************/
Tstream* Tvobsub::rar_open(const char_t *flnm)
{
if (fileexists(flnm))
return new TstreamFile(flnm,true,false);
else
{
char_t dsk[MAX_PATH],dir[MAX_PATH],name[MAX_PATH],ext[MAX_PATH];
_splitpath(flnm,dsk,dir,name,ext);
char_t flnmrar[MAX_PATH];
_makepath(flnmrar,dsk,dir,name,_l("rar"));
char_t flnmrarsub[MAX_PATH];
_makepath(flnmrarsub,NULL,NULL,name,ext);
return new TstreamRAR(flnmrar,flnmrarsub,config);
}
}
/**********************************************************************
* MPEG parsing
**********************************************************************/
Tvobsub::mpeg_t* Tvobsub::mpeg_open(const char_t *filename)
{
mpeg_t *res = (mpeg_t*)malloc(sizeof(mpeg_t));
int err = res == NULL;
if (!err) {
res->pts = 0;
res->aid = -1;
res->packet = NULL;
res->packet_size = 0;
res->packet_reserve = 0;
res->stream = rar_open(filename);
err = res->stream == NULL;
if (err)
perror("fopen Vobsub file failed");
if (err)
free(res);
}
return err ? NULL : res;
}
void Tvobsub::mpeg_free(mpeg_t *mpeg)
{
if (mpeg->packet)
free(mpeg->packet);
if (mpeg->stream)
delete mpeg->stream;
free(mpeg);
}
int Tvobsub::mpeg_eof(mpeg_t *mpeg)
{
return mpeg->stream->eof();
}
long Tvobsub::mpeg_tell(mpeg_t *mpeg)
{
return mpeg->stream->tell();
}
int Tvobsub::mpeg_run(mpeg_t *mpeg)
{
unsigned int len, idx, version;
int c;
/* Goto start of a packet, it starts with 0x000001?? */
const unsigned char wanted[] = { 0, 0, 1 };
unsigned char buf[5];
mpeg->aid = -1;
mpeg->packet_size = 0;
if (mpeg->stream->read(buf, 4, 1) != 1)
return -1;
while (memcmp(buf, wanted, sizeof(wanted)) != 0) {
c = mpeg->stream->getc();
if (c < 0)
return -1;
memmove(buf, buf + 1, 3);
buf[3] = (unsigned char)c;
}
switch (buf[3]) {
case 0xb9: /* System End Code */
break;
case 0xba: /* Packet start code */
c = mpeg->stream->getc();
if (c < 0)
return -1;
if ((c & 0xc0) == 0x40)
version = 4;
else if ((c & 0xf0) == 0x20)
version = 2;
else {
DPRINTF(_l("VobSub: Unsupported MPEG version: 0x%02x"), c);
return -1;
}
if (version == 4) {
if (mpeg->stream->seek(9, SEEK_CUR))
return -1;
}
else if (version == 2) {
if (mpeg->stream->seek(7, SEEK_CUR))
return -1;
}
else
return -1;
break;
case 0xbd: /* packet */
if (mpeg->stream->read(buf, 2, 1) != 1)
return -1;
len = buf[0] << 8 | buf[1];
idx = mpeg_tell(mpeg);
c = mpeg->stream->getc();
if (c < 0)
return -1;
if ((c & 0xC0) == 0x40) { /* skip STD scale & size */
if (mpeg->stream->getc() < 0)
return -1;
c = mpeg->stream->getc();
if (c < 0)
return -1;
}
if ((c & 0xf0) == 0x20) { /* System-1 stream timestamp */
/* Do we need this? */
return -1;
}
else if ((c & 0xf0) == 0x30) {
/* Do we need thid? */
return -1;
}
else if ((c & 0xc0) == 0x80) { /* System-2 (.VOB) stream */
unsigned int pts_flags, hdrlen, dataidx;
c = mpeg->stream->getc();
if (c < 0)
return -1;
pts_flags = c;
c = mpeg->stream->getc();
if (c < 0)
return -1;
hdrlen = c;
dataidx = mpeg_tell(mpeg) + hdrlen;
if (dataidx > idx + len) {
DPRINTF( _l("Invalid header length: %d (total length: %d, idx: %d, dataidx: %d)"), hdrlen, len, idx, dataidx);
return -1;
}
if ((pts_flags & 0xc0) == 0x80) {
if (mpeg->stream->read(buf, 5, 1) != 1)
return -1;
if (!(((buf[0] & 0xf0) == 0x20) && (buf[0] & 1) && (buf[2] & 1) && (buf[4] & 1))) {
DPRINTF( _l("vobsub PTS error: 0x%02x %02x%02x %02x%02x "),buf[0], buf[1], buf[2], buf[3], buf[4]);
mpeg->pts = 0;
}
else
mpeg->pts = ((buf[0] & 0x0e) << 29 | buf[1] << 22 | (buf[2] & 0xfe) << 14
| buf[3] << 7 | (buf[4] >> 1));
}
else /* if ((pts_flags & 0xc0) == 0xc0) */ {
/* what's this? */
/* abort(); */
}
mpeg->stream->seek(dataidx, SEEK_SET);
mpeg->aid = mpeg->stream->getc();
if (mpeg->aid < 0) {
DPRINTF( _l("Bogus aid %d"), mpeg->aid);
return -1;
}
mpeg->packet_size = len - ((unsigned int) mpeg_tell(mpeg) - idx);
if (mpeg->packet_reserve < mpeg->packet_size) {
if (mpeg->packet)
free(mpeg->packet);
mpeg->packet = (unsigned char*)malloc(mpeg->packet_size);
if (mpeg->packet)
mpeg->packet_reserve = mpeg->packet_size;
}
if (mpeg->packet == NULL) {
DPRINTF(_l("malloc failure"));
mpeg->packet_reserve = 0;
mpeg->packet_size = 0;
return -1;
}
if (mpeg->stream->read(mpeg->packet, mpeg->packet_size, 1) != 1) {
DPRINTF(_l("fread failure"));
mpeg->packet_size = 0;
return -1;
}
idx = len;
}
break;
case 0xbe: /* Padding */
if (mpeg->stream->read(buf, 2, 1) != 1)
return -1;
len = buf[0] << 8 | buf[1];
if (len > 0 && mpeg->stream->seek(len, SEEK_CUR))
return -1;
break;
default:
if (0xc0 <= buf[3] && buf[3] < 0xf0) {
/* MPEG audio or video */
if (mpeg->stream->read(buf, 2, 1) != 1)
return -1;
len = buf[0] << 8 | buf[1];
if (len > 0 && mpeg->stream->seek(len, SEEK_CUR))
return -1;
}
else {
DPRINTF(_l("unknown header 0x%02X%02X%02X%02X"),buf[0], buf[1], buf[2], buf[3]);
return -1;
}
}
return 0;
}
/**********************************************************************
* Packet queue
**********************************************************************/
void Tvobsub::packet_t::packet_construct(void)
{
pts100 = 0;
filepos = 0;
size = 0;
data = NULL;
}
void Tvobsub::packet_t::packet_destroy(void)
{
if (data)
free(data);
}
void Tvobsub::packet_queue_t::packet_queue_construct(void)
{
id = NULL;
altid = NULL;
packets = NULL;
packets_reserve = 0;
packets_size = 0;
current_index = 0;
}
void Tvobsub::packet_queue_t::packet_queue_destroy(void)
{
if (packets) {
while (packets_size--)
(packets + packets_size)->packet_destroy();
free(packets);
}
if (id) free(id);id=NULL;
if (altid) free(altid);altid=NULL;
return;
}
/* Make sure there is enough room for needed_size packets in the
packet queue. */
int Tvobsub::packet_queue_t::packet_queue_ensure(unsigned int needed_size)
{
if (packets_reserve < needed_size) {
if (packets) {
packet_t *tmp = (packet_t*)realloc(packets, 2 * packets_reserve * sizeof(packet_t));
packets = tmp;
packets_reserve *= 2;
}
else {
packets = (packet_t*)malloc(sizeof(packet_t));
packets_reserve = 1;
}
}
return 0;
}
/* add one more packet */
int Tvobsub::packet_queue_t::packet_queue_grow(void)
{
if (packet_queue_ensure(packets_size + 1) < 0)
return -1;
(packets + packets_size)->packet_construct();
++packets_size;
return 0;
}
/* insert a new packet, duplicating pts from the current one */
int Tvobsub::packet_queue_t::packet_queue_insert(void)
{
packet_t *pkts;
if (packet_queue_ensure(packets_size + 1) < 0)
return -1;
/* XXX packet_size does not reflect the real thing here, it will be updated a bit later */
memmove(packets + current_index + 2,
packets + current_index + 1,
sizeof(packet_t) * (packets_size - current_index - 1));
pkts = packets + current_index;
++packets_size;
++current_index;
(pkts + 1)->packet_construct();
pkts[1].pts100 = pkts[0].pts100;
pkts[1].filepos = pkts[0].filepos;
return 0;
}
/**********************************************************************
* Vobsub
**********************************************************************/
/* Make sure that the spu stream idx exists. */
int Tvobsub::vobsub_ensure_spu_stream(unsigned int index)
{
if (index >= spu_streams_size) {
/* This is a new stream */
if (spu_streams) {
packet_queue_t *tmp = (packet_queue_t*)realloc(spu_streams, (index + 1) * sizeof(packet_queue_t));
if (tmp == NULL) {
DPRINTF(_l("vobsub_ensure_spu_stream: realloc failure"));
return -1;
}
spu_streams = tmp;
}
else {
spu_streams = (packet_queue_t*)malloc((index + 1) * sizeof(packet_queue_t));
if (spu_streams == NULL) {
DPRINTF(_l("vobsub_ensure_spu_stream: malloc failure"));
return -1;
}
}
while (spu_streams_size <= index) {
(spu_streams + spu_streams_size)->packet_queue_construct();
++spu_streams_size;
}
}
return 0;
}
Tvobsub::PARSE_RES Tvobsub::vobsub_add_id( const char *id, size_t idlen, const unsigned int index)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -