⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vobsub.cpp

📁 从FFMPEG转换而来的H264解码程序,VC下编译..
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
 * 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 + -