📄 matroskaparser.c
字号:
/*
* Copyright (c) 2004-2005 Mike Matsnev. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Absolutely no warranty of function or purpose is made by the author
* Mike Matsnev.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: MatroskaParser.c,v 1.47 2005/07/06 18:44:40 mike Exp $
*
*/
/* modified for TCPMP by Picard 14/08/2005 */
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
//Picard
#if !defined(__palmos__) || !defined(ARM)
#include <setjmp.h>
#else
#ifndef EOF
#define EOF -1
#endif
typedef int jmp_buf[16];
int setjmp(jmp_buf jp);
int longjmp(jmp_buf jp, int ret);
#define alloca(size) __builtin_alloca(size)
#endif
#ifdef _WIN32
// MS names some functions differently
#define alloca _alloca
#define inline __inline
#include <tchar.h>
#endif
#ifndef EVCBUG
#define EVCBUG
#endif
#include "MatroskaParser.h"
#ifdef MATROSKA_COMPRESSION_SUPPORT
#include "../../common/zlib/zlib.h" //Picard
//#include <zlib.h>
#endif
#define EBML_VERSION 1
#define EBML_MAX_ID_LENGTH 4
#define EBML_MAX_SIZE_LENGTH 8
#define MATROSKA_VERSION 1
#define MATROSKA_DOCTYPE "matroska"
#define MAX_STRING_LEN 1023
#define QSEGSIZE 512
#define MAX_TRACKS 32
#define MAX_READAHEAD (512*1024)
#define MAXCLUSTER (64*1048576)
#define MAXFRAME (4*1048576)
#ifdef WIN32
#define LL(x) x##i64
#define ULL(x) x##ui64
#else
#define LL(x) x##ll
#define ULL(x) x##ull
#endif
#define MAXU64 ULL(0xffffffffffffffff)
#define ONE ULL(1)
// compatibility
static char *mystrdup(struct InputStream *is,const char *src) {
size_t len;
char *dst;
if (src==NULL)
return NULL;
len = strlen(src);
dst = is->memalloc(is,len+1);
if (dst==NULL)
return NULL;
memcpy(dst,src,len+1);
return dst;
}
#if defined(_WIN32) || defined(__palmos__) //Picard
static void strlcpy(char *dst,const char *src,unsigned size) {
unsigned i;
for (i=0;i+1<size && src[i];++i)
dst[i] = src[i];
if (i<size)
dst[i] = 0;
}
#endif
struct Cue {
ulonglong Time;
ulonglong Position;
ulonglong Block;
unsigned char Track;
};
struct QueueEntry {
struct QueueEntry *next;
unsigned int Length;
ulonglong Start;
ulonglong End;
ulonglong Position;
void *Ref; //Picard
unsigned int flags;
};
struct Queue {
struct QueueEntry *head;
struct QueueEntry *tail;
};
#define MPF_ERROR 0x10000
#define IBSZ 1024
#define RBRESYNC 1
struct MatroskaFile {
// parser config
unsigned flags;
// input
InputStream *cache;
// internal buffering
char inbuf[IBSZ];
ulonglong bufbase; // file offset of the first byte in buffer
int bufpos; // current read position in buffer
int buflen; // valid bytes in buffer
// error reporting
char errmsg[128];
jmp_buf jb;
// pointers to key elements
ulonglong pSegment;
ulonglong pSeekHead;
ulonglong pSegmentInfo;
ulonglong pCluster;
ulonglong pTracks;
ulonglong pCues;
ulonglong pAttachments;
ulonglong pChapters;
ulonglong pTags;
// flags for key elements
struct {
unsigned int SegmentInfo:1;
unsigned int Cluster:1;
unsigned int Tracks:1;
unsigned int Cues:1;
unsigned int Attachments:1;
unsigned int Chapters:1;
unsigned int Tags:1;
} seen;
// file info
ulonglong firstTimecode;
// SegmentInfo
struct SegmentInfo Seg;
// Tracks
unsigned int nTracks,nTracksSize;
struct TrackInfo **Tracks;
// Queues
struct QueueEntry *QFreeList;
unsigned int nQBlocks,nQBlocksSize;
struct QueueEntry **QBlocks;
struct Queue *Queues;
ulonglong readPosition;
unsigned int trackMask;
ulonglong pSegmentTop; // offset of next byte after the segment
ulonglong tcCluster; // current cluster timecode
// Cues
unsigned int nCues,nCuesSize;
struct Cue *Cues;
// Attachments
unsigned int nAttachments,nAttachmentsSize;
struct Attachment *Attachments;
// Chapters
unsigned int nChapters,nChaptersSize;
struct Chapter *Chapters;
// Tags
unsigned int nTags,nTagsSize;
struct Tag *Tags;
};
///////////////////////////////////////////////////////////////////////////
// error reporting
static void myvsnprintf_string(char **pdest,char *de,const char *str) {
char *dest = *pdest;
while (dest < de && *str)
*dest++ = *str++;
*pdest = dest;
}
static void myvsnprintf_uint_impl(char **pdest,char *de,int width,int zero,
int neg,unsigned base,int letter,
int ms,ulonglong val)
{
char *dest = *pdest;
char tmp[21]; /* enough for 64 bit ints */
char *np = tmp + sizeof(tmp);
int rw,pad,trail;
char pc = zero ? '0' : ' ';
*--np = '\0';
while (val != 0) {
int rem = (int)(val % base);
val = val / base;
*--np = rem < 10 ? rem + '0' : rem - 10 + letter;
}
rw = (int)(tmp - np + sizeof(tmp) - 1);
if (ms)
++rw;
pad = trail = 0;
if (rw < width)
pad = width - rw;
if (neg)
trail = pad, pad = 0;
if (dest < de && ms)
*dest++ = '-';
while (dest < de && pad--)
*dest++ = pc;
while (dest < de && *np)
*dest++ = *np++;
while (dest < de && trail--)
*dest++ = ' ';
*pdest = dest;
}
static void myvsnprintf_uint(char **pdest,char *de,int width,int zero,
int neg,unsigned base,int letter,
ulonglong val)
{
myvsnprintf_uint_impl(pdest,de,width,zero,neg,base,letter,0,val);
}
static void myvsnprintf_int(char **pdest,char *de,int width,int zero,
int neg,unsigned base,int letter,
longlong val)
{
if (val < 0)
myvsnprintf_uint_impl(pdest,de,width,zero,neg,base,letter,1,-val);
else
myvsnprintf_uint_impl(pdest,de,width,zero,neg,base,letter,0,val);
}
static void myvsnprintf(char *dest,unsigned dsize,const char *fmt,va_list ap) {
// s,d,x,u,ll
char *de = dest + dsize - 1;
int state = 0, width=0, zero=0, neg=0, ll=0; //Picard
if (dsize <= 1) {
if (dsize > 0)
*dest = '\0';
return;
}
while (*fmt && dest < de)
switch (state) {
case 0:
if (*fmt == '%') {
++fmt;
state = 1;
width = zero = neg = ll = 0;
} else
*dest++ = *fmt++;
break;
case 1:
if (*fmt == '-') {
neg = 1;
++fmt;
state = 2;
break;
}
state = 2;
case 2:
if (*fmt >= '0' && *fmt <= '9') {
width = width * 10 + *fmt++ - '0';
break;
}
state = 3;
case 3:
if (*fmt == 'l') {
++ll;
++fmt;
break;
}
state = 4;
case 4:
switch (*fmt) {
case 's':
myvsnprintf_string(&dest,de,va_arg(ap,const char *));
break;
case 'd':
switch (ll) {
case 0:
myvsnprintf_int(&dest,de,width,zero,neg,10,'a',va_arg(ap,int));
break;
case 1:
myvsnprintf_int(&dest,de,width,zero,neg,10,'a',va_arg(ap,long));
break;
case 2:
myvsnprintf_int(&dest,de,width,zero,neg,10,'a',va_arg(ap,longlong));
break;
}
break;
case 'u':
switch (ll) {
case 0:
myvsnprintf_uint(&dest,de,width,zero,neg,10,'a',va_arg(ap,unsigned int));
break;
case 1:
myvsnprintf_uint(&dest,de,width,zero,neg,10,'a',va_arg(ap,unsigned long));
break;
case 2:
myvsnprintf_uint(&dest,de,width,zero,neg,10,'a',va_arg(ap,ulonglong));
break;
}
break;
case 'x':
switch (ll) {
case 0:
myvsnprintf_uint(&dest,de,width,zero,neg,16,'a',va_arg(ap,unsigned int));
break;
case 1:
myvsnprintf_uint(&dest,de,width,zero,neg,16,'a',va_arg(ap,unsigned long));
break;
case 2:
myvsnprintf_uint(&dest,de,width,zero,neg,16,'a',va_arg(ap,ulonglong));
break;
}
break;
case 'X':
switch (ll) {
case 0:
myvsnprintf_uint(&dest,de,width,zero,neg,16,'A',va_arg(ap,unsigned int));
break;
case 1:
myvsnprintf_uint(&dest,de,width,zero,neg,16,'A',va_arg(ap,unsigned long));
break;
case 2:
myvsnprintf_uint(&dest,de,width,zero,neg,16,'A',va_arg(ap,ulonglong));
break;
}
break;
default:
break;
}
++fmt;
state = 0;
break;
default:
state = 0;
break;
}
*dest = '\0';
}
static void errorjmp(MatroskaFile *mf,const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
myvsnprintf(mf->errmsg,sizeof(mf->errmsg),fmt,ap);
va_end(ap);
mf->flags |= MPF_ERROR;
longjmp(mf->jb,1);
}
///////////////////////////////////////////////////////////////////////////
// arrays
static void *ArrayAlloc(MatroskaFile *mf,void **base,
unsigned *cur,unsigned *max,unsigned elem_size)
{
if (*cur>=*max) {
void *np;
unsigned newsize = *max * 2;
if (newsize==0)
newsize = 1;
np = mf->cache->memrealloc(mf->cache,*base,newsize*elem_size);
if (np==NULL)
errorjmp(mf,"Out of memory in ArrayAlloc");
*base = np;
*max = newsize;
}
return (char*)*base + elem_size * (*cur)++;
}
static void ArrayReleaseMemory(MatroskaFile *mf,void **base,
unsigned cur,unsigned *max,unsigned elem_size)
{
if (cur<*max) {
void *np = mf->cache->memrealloc(mf->cache,*base,cur*elem_size);
*base = np;
*max = cur;
}
}
#define ASGET(f,s,name) ArrayAlloc((f),(void**)&(s)->name,&(s)->n##name,&(s)->n##name##Size,sizeof(*((s)->name)))
#define AGET(f,name) ArrayAlloc((f),(void**)&(f)->name,&(f)->n##name,&(f)->n##name##Size,sizeof(*((f)->name)))
#define ARELEASE(f,s,name) ArrayReleaseMemory((f),(void**)&(s)->name,(s)->n##name,&(s)->n##name##Size,sizeof(*((s)->name)))
///////////////////////////////////////////////////////////////////////////
// queues
static struct QueueEntry *QPut(struct Queue *q,struct QueueEntry *qe) {
if (q->tail)
q->tail->next = qe;
qe->next = NULL;
q->tail = qe;
if (q->head==NULL)
q->head = qe;
return qe;
}
static struct QueueEntry *QGet(struct Queue *q) {
struct QueueEntry *qe = q->head;
if (qe == NULL)
return NULL;
q->head = qe->next;
if (q->tail == qe)
q->tail = NULL;
return qe;
}
static struct QueueEntry *QAlloc(MatroskaFile *mf) {
struct QueueEntry *qe,**qep;
if (mf->QFreeList == NULL) {
unsigned i;
qep = AGET(mf,QBlocks);
*qep = mf->cache->memalloc(mf->cache,QSEGSIZE * sizeof(*qe));
if (*qep == NULL)
errorjmp(mf,"Ouf of memory");
qe = *qep;
for (i=0;i<QSEGSIZE-1;++i)
qe[i].next = qe+i+1;
qe[QSEGSIZE-1].next = NULL;
mf->QFreeList = qe;
}
qe = mf->QFreeList;
mf->QFreeList = qe->next;
return qe;
}
static inline void QFree(MatroskaFile *mf,struct QueueEntry *qe) {
if (qe->Ref) mf->cache->releaseref(mf->cache,qe->Ref); //Picard
qe->next = mf->QFreeList;
mf->QFreeList = qe;
}
//Picard
/*
// fill the buffer at current position
static void fillbuf(MatroskaFile *mf) {
int rd;
// advance buffer pointers
mf->bufbase += mf->buflen;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -