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

📄 matroskaparser.c

📁 大名鼎鼎的CE下播放软件,TCPPMP的源代码!!!2410下可以流畅的解QVGA的H264,MPEG4等格式.
💻 C
📖 第 1 页 / 共 5 页
字号:
  mf->buflen = mf->bufpos = 0;

  // get the relevant page
  rd = mf->cache->read(mf->cache, mf->bufbase, mf->inbuf, IBSZ);
  if (rd<0)
    errorjmp(mf,"I/O Error: %s",mf->cache->geterror(mf->cache));

  mf->buflen = rd;
}

// fill the buffer and return next char
static int  nextbuf(MatroskaFile *mf) {
  fillbuf(mf);

  if (mf->bufpos < mf->buflen)
    return (unsigned char)(mf->inbuf[mf->bufpos++]);

  return EOF;
}
*/

static inline int readch(MatroskaFile *mf) {
  return mf->cache->ioreadch(mf->cache); //Picard
  //return mf->bufpos < mf->buflen ? (unsigned char)(mf->inbuf[mf->bufpos++]) : nextbuf(mf);
}

static inline ulonglong	filepos(MatroskaFile *mf) {
  return mf->cache->iotell(mf->cache); //Picard
  //return mf->bufbase + mf->bufpos;
}

static void   readbytes(MatroskaFile *mf,void *buffer,int len) {
  mf->cache->ioread(mf->cache,buffer,len); //Picard
/*  
  char	*cp = buffer;
  int	nb = mf->buflen - mf->bufpos;

  if (nb > len)
    nb = len;

  memcpy(cp, mf->inbuf + mf->bufpos, nb);
  mf->bufpos += nb;
  len -= nb;
  cp += nb;

  if (len>0) {
    mf->bufbase += mf->buflen;
    mf->bufpos = mf->buflen = 0;

    nb = mf->cache->read(mf->cache, mf->bufbase, cp, len);
    if (nb<0)
      errorjmp(mf,"I/O Error: %s",mf->cache->geterror(mf->cache));
    if (nb != len)
      errorjmp(mf,"Short read: got %d bytes of %d",nb,len);
    mf->bufbase += len;
  }
*/
}

static void   skipbytes(MatroskaFile *mf,ulonglong len) {
  mf->cache->ioseek(mf->cache,len,1);//Picard
/*
  int	    nb = mf->buflen - mf->bufpos;

  if (nb > len)
    nb = (int)len;

  mf->bufpos += nb;
  len -= nb;

  if (len>0) {
    mf->bufbase += mf->buflen;
    mf->bufpos = mf->buflen = 0;

    mf->bufbase += len;
  }
*/
}

static void seek(MatroskaFile *mf,ulonglong pos) {
  mf->cache->ioseek(mf->cache,pos,0);//Picard
/*
  // see if pos is inside buffer
  if (pos>=mf->bufbase && pos<mf->bufbase+mf->buflen)
    mf->bufpos = (unsigned)(pos - mf->bufbase);
  else {
    // invalidate buffer and set pointer
    mf->bufbase = pos;
    mf->buflen = mf->bufpos = 0;
  }
*/
}

///////////////////////////////////////////////////////////////////////////
// floating point
static inline MKFLOAT	mkfi(int i) {
#ifdef MATROSKA_INTEGER_ONLY
  MKFLOAT  f;
  f.v = (longlong)i << 32;
  return f;
#else
  return i;
#endif
}

static inline longlong mul3(MKFLOAT scale,longlong tc) {
#ifdef MATROSKA_INTEGER_ONLY
  //             x1 x0
  //             y1 y0
  //    --------------
  //             x0*y0
  //          x1*y0
  //          x0*y1
  //       x1*y1
  //    --------------
  //       .. r1 r0 ..
  //
  //    r = ((x0*y0) >> 32) + (x1*y0) + (x0*y1) + ((x1*y1) << 32)
  unsigned    x0,x1,y0,y1;
  ulonglong   p;
  char	      sign = 0;

  if (scale.v < 0)
    sign = !sign, scale.v = -scale.v;
  if (tc < 0)
    sign = !sign, tc = -tc;

  x0 = (unsigned)scale.v;
  x1 = (unsigned)((ulonglong)scale.v >> 32);
  y0 = (unsigned)tc;
  y1 = (unsigned)((ulonglong)tc >> 32);

  p = (ulonglong)x0*y0 >> 32;
  p += (ulonglong)x0*y1;
  p += (ulonglong)x1*y0;
  p += (ulonglong)(x1*y1) << 32;

  return p;
#else
  return (longlong)(scale * tc);
#endif
}

///////////////////////////////////////////////////////////////////////////
// EBML support
static int   readID(MatroskaFile *mf) {
  int	c1,c2,c3,c4;

  c1 = readch(mf);
  if (c1 == EOF)
    return EOF;

  if (c1 & 0x80)
    return c1;

  if ((c1 & 0xf0) == 0)
    errorjmp(mf,"Invalid first byte of EBML ID: %02X",c1);

  c2 = readch(mf);
  if (c2 == EOF)
fail:
    errorjmp(mf,"Got EOF while reading EBML ID");

  if ((c1 & 0xc0) == 0x40)
    return (c1<<8) | c2;

  c3 = readch(mf);
  if (c3 == EOF)
    goto fail;

  if ((c1 & 0xe0) == 0x20)
    return (c1<<16) | (c2<<8) | c3;

  c4 = readch(mf);
  if (c4 == EOF)
    goto fail;

  if ((c1 & 0xf0) == 0x10)
    return (c1<<24) | (c2<<16) | (c3<<8) | c4;

  return 0; // NOT REACHED
}

static ulonglong readVLUIntImp(MatroskaFile *mf,int *mask) {
  int		c,d,m;
  ulonglong	v = 0;

  c = readch(mf);
  if (c == EOF)
    return EOF;

  if (c == 0)
    errorjmp(mf,"Invalid first byte of EBML integer: 0");

  for (m=0;;++m) {
    if (c & (0x80 >> m)) {
      c &= 0x7f >> m;
      if (mask)
	*mask = m;
      return v | ((ulonglong)c << m*8);
    }
    d = readch(mf);
    if (d == EOF)
      errorjmp(mf,"Got EOF while reading EBML unsigned integer");
    v = (v<<8) | d;
  }
  // NOT REACHED
}

static inline ulonglong	readVLUInt(MatroskaFile *mf) {
  return readVLUIntImp(mf,NULL);
}

static ulonglong	readSize(MatroskaFile *mf) {
  int	    m;
  ulonglong v = readVLUIntImp(mf,&m);

  // see if it's unspecified
  if (v == (MAXU64 >> (57-m*7)))
    errorjmp(mf,"Unspecified element size is not supported here.");

  return v;
}

static inline longlong	readVLSInt(MatroskaFile *mf) {
  static longlong bias[8] = { (ONE<<6)-1, (ONE<<13)-1, (ONE<<20)-1, (ONE<<27)-1,
			      (ONE<<34)-1, (ONE<<41)-1, (ONE<<48)-1, (ONE<<55)-1 };

  int	    m;
  longlong  v = readVLUIntImp(mf,&m);

  return v - bias[m];
}

static ulonglong  readUInt(MatroskaFile *mf,unsigned int len) {
  int		c;
  unsigned int	m = len;
  ulonglong	v = 0;

  if (len==0)
    return v;
  if (len>8)
    errorjmp(mf,"Unsupported integer size in readUInt: %u",len);

  do {
    c = readch(mf);
    if (c == EOF)
      errorjmp(mf,"Got EOF while reading EBML unsigned integer");
    v = (v<<8) | c;
  } while (--m);

  return v;
}

static inline longlong	readSInt(MatroskaFile *mf,unsigned int len) {
  longlong	v = readUInt(mf,(unsigned)len);
  int		s = 64 - (len<<3);
  return (v << s) >> s;
}

static MKFLOAT readFloat(MatroskaFile *mf,unsigned int len) {
#ifdef MATROSKA_INTEGER_ONLY
  MKFLOAT	  f;
  int		  shift;
#else
  union {
    unsigned int  ui;
    ulonglong	  ull;
    float	  f;
    double	  d;
  } u;
#endif

  if (len!=4 && len!=8)
    errorjmp(mf,"Invalid float size in readFloat: %u",len);

#ifdef MATROSKA_INTEGER_ONLY
  if (len == 4) {
    unsigned  ui = (unsigned)readUInt(mf,(unsigned)len);
    f.v = (ui & 0x7fffff) | 0x800000;
    if (ui & 0x80000000)
      f.v = -f.v;
    shift = (ui >> 23) & 0xff;
    if (shift == 0) // assume 0
zero:
      shift = 0, f.v = 0;
    else if (shift == 255)
inf:
      if (ui & 0x80000000)
	f.v = LL(0x8000000000000000);
      else
	f.v = LL(0x7fffffffffffffff);
    else {
      shift += -127 + 9;
      if (shift > 39)
	goto inf;
shift:
      if (shift < 0)
	f.v = f.v >> -shift;
      else if (shift > 0)
	f.v = f.v << shift;
    }
  } else if (len == 8) {
    ulonglong  ui = readUInt(mf,(unsigned)len);
    f.v = (ui & LL(0xfffffffffffff)) | LL(0x10000000000000);
    if (ui & 0x80000000)
      f.v = -f.v;
    shift = (int)((ui >> 52) & 0x7ff);
    if (shift == 0) // assume 0
      goto zero;
    else if (shift == 2047)
      goto inf;
    else {
      shift += -1023 - 20;
      if (shift > 10)
	goto inf;
      goto shift;
    }
  }

  return f;
#else
  if (len==4) {
    u.ui = (unsigned int)readUInt(mf,(unsigned)len);
    return u.f;
  }

  if (len==8) {
    u.ull = readUInt(mf,(unsigned)len);
    return u.d;
  }

  return 0;
#endif
}

static void readString(MatroskaFile *mf,ulonglong len,char *buffer,int buflen) {
  int	  nread;

  if (buflen<1)
    errorjmp(mf,"Invalid buffer size in readString: %d",buflen);

  nread = buflen - 1;

  if (nread > len)
    nread = (int)len;

  readbytes(mf,buffer,nread);
  len -= nread;

  if (len>0)
    skipbytes(mf,len);

  buffer[nread] = '\0';
}

///////////////////////////////////////////////////////////////////////////
// file parser
#define	FOREACH(f,tl) \
  { \
    ulonglong	tmplen = (tl); \
    { \
      ulonglong   start = filepos(f); \
      ulonglong   cur,len; \
      int	      id; \
      for (;;) { \
	cur = filepos(mf); \
	if (cur == start + tmplen) \
	  break; \
	id = readID(f); \
	if (id==EOF) \
	  errorjmp(mf,"Unexpected EOF while reading EBML container"); \
	len = readSize(mf); \
	switch (id) {

#define	ENDFOR1(f) \
	default: \
	  skipbytes(f,len); \
	  break; \
	}
#define	ENDFOR2() \
      } \
    } \
  }

#define	ENDFOR(f) ENDFOR1(f) ENDFOR2()

#define	myalloca(f,c) alloca(c)
#define	STRGETF(f,v,len,func) \
  { \
    char *TmpVal; \
    unsigned TmpLen = (len)>MAX_STRING_LEN ? MAX_STRING_LEN : (unsigned)(len); \
    TmpVal = func(f->cache,TmpLen+1); \
    if (TmpVal == NULL) \
      errorjmp(mf,"Out of memory"); \
    readString(f,len,TmpVal,TmpLen+1); \
    (v) = TmpVal; \
  }

#define	STRGETA(f,v,len)  STRGETF(f,v,len,myalloca)
#define	STRGETM(f,v,len)  STRGETF(f,v,len,f->cache->memalloc)

#if 0
static int  IsWritingApp(MatroskaFile *mf,const char *str) {
  const char  *cp = mf->Seg.WritingApp;
  if (!cp)
    return 0;

  while (*str && *str++==*cp++) ;

  return !*str;
}
#endif

static void parseEBML(MatroskaFile *mf,ulonglong toplen) {
  ulonglong v;
  char	    buf[32];

  FOREACH(mf,toplen)
    case 0x4286: // Version
      v = readUInt(mf,(unsigned)len);
      break;
    case 0x42f7: // ReadVersion
      v = readUInt(mf,(unsigned)len);
      if (v > EBML_VERSION)
	errorjmp(mf,"File requires version %d EBML parser",(int)v);
      break;
    case 0x42f2: // MaxIDLength
      v = readUInt(mf,(unsigned)len);
      if (v > EBML_MAX_ID_LENGTH)
	errorjmp(mf,"File has identifiers longer than %d",(int)v);
      break;
    case 0x42f3: // MaxSizeLength
      v = readUInt(mf,(unsigned)len);
      if (v > EBML_MAX_SIZE_LENGTH)
	errorjmp(mf,"File has integers longer than %d",(int)v);
      break;
    case 0x4282: // DocType
      readString(mf,len,buf,sizeof(buf));
      if (strcmp(buf,MATROSKA_DOCTYPE))
	errorjmp(mf,"Unsupported DocType: %s",buf);
      break;
    case 0x4287: // DocTypeVersion
      v = readUInt(mf,(unsigned)len);
      break;
    case 0x4285: // DocTypeReadVersion
      v = readUInt(mf,(unsigned)len);
      if (v > MATROSKA_VERSION)
	errorjmp(mf,"File requires version %d Matroska parser",(int)v);
      break;
  ENDFOR(mf);
}

static void parseSeekEntry(MatroskaFile *mf,ulonglong toplen) {
  int	    seekid = 0;
  ulonglong pos = (ulonglong)-1;

  FOREACH(mf,toplen)
    case 0x53ab: // SeekID
      if (len>EBML_MAX_ID_LENGTH)
	errorjmp(mf,"Invalid ID size in parseSeekEntry: %d\n",(int)len);
      seekid = (int)readUInt(mf,(unsigned)len);
      break;
    case 0x53ac: // SeekPos
      pos = readUInt(mf,(unsigned)len);
      break;
  ENDFOR(mf);

  if (pos == (ulonglong)-1)
    errorjmp(mf,"Invalid element position in parseSeekEntry");

  pos += mf->pSegment;
  switch (seekid) {
    case 0x114d9b74: // next SeekHead
      if (mf->pSeekHead)
	errorjmp(mf,"SeekHead contains more than one SeekHead pointer");
      mf->pSeekHead = pos;
      break;
    case 0x1549a966: // SegmentInfo
      mf->pSegmentInfo = pos;
      break;
    case 0x1f43b675: // Cluster
      if (!mf->pCluster)
	mf->pCluster = pos;
      break;
    case 0x1654ae6b: // Tracks
      mf->pTracks = pos;
      break;
    case 0x1c53bb6b: // Cues
      mf->pCues = pos;
      break;
    case 0x1941a469: // Attachments
      mf->pAttachments = pos;
      break;
    case 0x1043a770: // Chapters
      mf->pChapters = pos;
      break;
    case 0x1254c367: // tags
      mf->pTags = pos;
      break;
  }
}

static void parseSeekHead(MatroskaFile *mf,ulonglong toplen) {
  FOREACH(mf,toplen)
    case 0x4dbb:
      parseSeekEntry(mf,len);
      break;
  ENDFOR(mf);
}

static void parseSegmentInfo(MatroskaFile *mf,ulonglong toplen) {
  MKFLOAT     duration = mkfi(0);

  if (mf->seen.SegmentInfo) {
    skipbytes(mf,toplen);
    return;
  }

  mf->seen.SegmentInfo = 1;
  mf->Seg.TimecodeScale = 1000000; // Default value

  FOREACH(mf,toplen)
    case 0x73a4: // SegmentUID
      if (len!=sizeof(mf->Seg.UID))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -