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

📄 matroskaparser.c

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

	QPut(&mf->Queues[track],qe);
      }
	  if (add_ref) { mf->cache->releaseref(mf->cache,add_ref); add_ref = NULL; } //Picard
      break;
  ENDFOR(mf);
}

static void parseBlockGroup(MatroskaFile *mf,ulonglong toplen,ulonglong timecode) {
  ulonglong	v;
  ulonglong	duration = 0;
  ulonglong	dpos;
  //unsigned	add_id = 0; //Picard
  struct QueueEntry *qe,*qf = NULL;
  unsigned char	have_duration = 0, have_block = 0;
  unsigned char	gap = 0;
  unsigned char	lacing = 0;
  unsigned char	ref = 0;
  unsigned char	trackid;
  unsigned	tracknum = 0;
  int		c;
  unsigned	nframes = 0,i;
  unsigned	*sizes;
  signed short	block_timecode;

  FOREACH(mf,toplen)
    case 0xfb: // ReferenceBlock
      readSInt(mf,(unsigned)len);
      ref = 1;
      break;
    case 0xa1: // Block
      have_block = 1;

      dpos = filepos(mf);

      v = readVLUInt(mf);
      if (v>255)
	errorjmp(mf,"Invalid track number in Block: %d",(int)v);
      trackid = (unsigned char)v;

      for (tracknum=0;tracknum<mf->nTracks;++tracknum)
	if (mf->Tracks[tracknum]->Number == trackid)
	  goto found;
      errorjmp(mf,"Invalid track number in Block: %u",trackid);
found:

      if (mf->trackMask & (1<<tracknum)) { // ignore this block
	skipbytes(mf,start + tmplen - filepos(mf)); // shortcut
	return;
      }

      block_timecode = (signed short)readSInt(mf,2);

      // recalculate this block's timecode to final timecode in ns
      timecode = mul3(mf->Tracks[tracknum]->TimecodeScale,
	(timecode - mf->firstTimecode + block_timecode) * mf->Seg.TimecodeScale);

      c = readch(mf);
      if (c==EOF)
	errorjmp(mf,"Unexpected EOF while reading Block flags");

      gap = c & 0x1;
      lacing = (c >> 1) & 3;

      if (lacing) {
	c = readch(mf);
	if (c == EOF)
	  errorjmp(mf,"Unexpected EOF while reading lacing data");
	nframes = c+1;
      } else
	nframes = 1;
      sizes = alloca(nframes*sizeof(*sizes));
 
      switch (lacing) {
	case 0: // No lacing
	  sizes[0] = (unsigned)(len - filepos(mf) + dpos);
	  break;
	case 1: // Xiph lacing
	  sizes[nframes-1] = 0;
	  for (i=0;i<nframes-1;++i) {
	    sizes[i] = 0;
	    do {
	      c = readch(mf);
	      if (c==EOF)
		errorjmp(mf,"Unexpected EOF while reading lacing data");
	      sizes[i] += c;
	    } while (c==255);
	    sizes[nframes-1] += sizes[i];
	  }
	  sizes[nframes-1] = (unsigned)(len - filepos(mf) + dpos) - sizes[nframes-1];
	  break;
	case 3: // EBML lacing
	  sizes[nframes-1] = 0;
	  sizes[0] = (unsigned)readVLUInt(mf);
	  for (i=1;i<nframes-1;++i) {
	    sizes[i] = sizes[i-1] + (int)readVLSInt(mf);
	    sizes[nframes-1] += sizes[i];
	  }
	  if (nframes>1)
	    sizes[nframes-1] = (unsigned)(len - filepos(mf) + dpos) - sizes[0] - sizes[nframes-1];
	  break;
	case 2: // Fixed lacing
	  sizes[0] = (unsigned)(len - filepos(mf) + dpos)/nframes;
	  for (i=1;i<nframes;++i)
	    sizes[i] = sizes[0];
	  break;
      }

      v = filepos(mf);
      qf = NULL;
      for (i=0;i<nframes;++i) {
	qe = QAlloc(mf);
	if (!qf)
	  qf = qe;

	qe->Start = timecode;
	qe->End = timecode;
	qe->Position = v;
	qe->Length = sizes[i];
	qe->Ref = mf->cache->makeref(mf->cache,sizes[i]); //Picard
	qe->flags = FRAME_UNKNOWN_END | FRAME_KF;
	if (i == nframes-1 && gap)
	  qe->flags |= FRAME_GAP;
	if (i > 0)
	  qe->flags |= FRAME_UNKNOWN_START;

	QPut(&mf->Queues[tracknum],qe);

	v += sizes[i];
      }

      // we want to still load these bytes into cache
	  //Picard, not needed for TCPMP 
	  /*
      for (v = filepos(mf) & ~0x3fff; v < len + dpos; v += 0x4000)
	mf->cache->read(mf->cache,v,NULL,0); // touch page
	  */

      skipbytes(mf,len - filepos(mf) + dpos);
      break;
    case 0x9b: // BlockDuration
      duration = readUInt(mf,(unsigned)len);
      have_duration = 1;
      break;
    case 0x75a1: // BlockAdditions
      if (nframes > 0) // have some frames
	parseBlockAdditions(mf, len, timecode, tracknum);
      else
	skipbytes(mf, len);
      break;
  ENDFOR(mf);

  if (!have_block)
    errorjmp(mf,"Found a BlockGroup without Block");

  if (nframes > 1) {
    if (have_duration) {
      duration = mul3(mf->Tracks[tracknum]->TimecodeScale,
	duration * mf->Seg.TimecodeScale);
      dpos = duration / nframes;

      v = qf->Start;
      for (qe = qf; nframes > 1; --nframes, qe = qe->next) {
	qe->Start = v;
	v += dpos;
	duration -= dpos;
	qe->End = v;
	qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
      }
      qe->Start = v;
      qe->End = v + duration;
      qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
    } else if (mf->Tracks[tracknum]->DefaultDuration) {
      dpos = mf->Tracks[tracknum]->DefaultDuration;
      v = qf->Start;
      for (qe = qf; nframes > 0; --nframes, qe = qe->next) {
	qe->Start = v;
	v += dpos;
	qe->End = v;
	qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
      }
    }
  } else if (nframes == 1) {
    if (have_duration) {
      qf->End = qf->Start + mul3(mf->Tracks[tracknum]->TimecodeScale,
	duration * mf->Seg.TimecodeScale);
      qf->flags &= ~FRAME_UNKNOWN_END;
    } else if (mf->Tracks[tracknum]->DefaultDuration) {
      qf->End = qf->Start + mf->Tracks[tracknum]->DefaultDuration;
      qf->flags &= ~FRAME_UNKNOWN_END;
    }
  }

  if (ref)
    while (qf) {
      qf->flags &= ~FRAME_KF;
      qf = qf->next;
    }
}

static void ClearQueue(MatroskaFile *mf,struct Queue *q) {
  struct QueueEntry *qe,*qn;

  for (qe=q->head;qe;qe=qn) {
    qn = qe->next;
	QFree(mf,qe); //Picard
    /*
	qe->next = mf->QFreeList;
    mf->QFreeList = qe;
	*/
  }

  q->head = NULL;
  q->tail = NULL;
}

static void EmptyQueues(MatroskaFile *mf) {
  unsigned	    i;

  for (i=0;i<mf->nTracks;++i)
    ClearQueue(mf,&mf->Queues[i]);
}

static int  readMoreBlocks(MatroskaFile *mf) {
  ulonglong		toplen, cstop;
  longlong		cp;
  int			cid, ret = 0;
  jmp_buf		jb;
  volatile unsigned	retries = 0;

  if (mf->readPosition >= mf->pSegmentTop)
    return EOF;

  memcpy(&jb,&mf->jb,sizeof(jb));

  if (setjmp(mf->jb)) { // something evil happened here, try to resync
    // always advance read position no matter what so
    // we don't get caught in an endless loop
    mf->readPosition = filepos(mf);

    ret = EOF;

    if (++retries > 3) // don't try too hard
      goto ex;

    for (;;) {
      if (filepos(mf) >= mf->pSegmentTop)
	goto ex;

      cp = mf->cache->scan(mf->cache,filepos(mf),0x1f43b675); // cluster

      if (cp < 0 || (ulonglong)cp >= mf->pSegmentTop)
	goto ex;

      seek(mf,cp);

      cid = readID(mf);
      if (cid == EOF)
	goto ex;
      if (cid == 0x1f43b675) {
	toplen = readSize(mf);
	if (toplen < MAXCLUSTER) {
	  // reset error flags
	  mf->flags &= ~MPF_ERROR;
	  ret = RBRESYNC;
	  break;
	}
      }
    }

    mf->readPosition = cp;
  }

  cstop = mf->cache->getsize(mf->cache)>>1;
  if (cstop > MAX_READAHEAD)
    cstop = MAX_READAHEAD;
  cstop += mf->readPosition;

  seek(mf,mf->readPosition);

  while (filepos(mf) < mf->pSegmentTop) {
    cid = readID(mf);
    if (cid == EOF) {
      ret = EOF;
      break;
    }
    toplen = readSize(mf);

    if (cid == 0x1f43b675) { // Cluster
      unsigned char	have_timecode = 0;

      FOREACH(mf,toplen)
	case 0xe7: // Timecode
	  mf->tcCluster = readUInt(mf,(unsigned)len);
	  have_timecode = 1;
	  break;
	case 0xa7: // Position
	  readUInt(mf,(unsigned)len);
	  break;
	case 0xab: // PrevSize
	  readUInt(mf,(unsigned)len);
	  break;
	case 0x5854: { // SilentTracks
	  unsigned  stmask = 0, i, trk;
	  FOREACH(mf, len)
	    case 0x58d7: // SilentTrackNumber
	      trk = (unsigned)readUInt(mf, (unsigned)len);
	      for (i = 0; i < mf->nTracks; ++i)
		if (mf->Tracks[i]->Number == trk) {
		  stmask |= 1 << i;
		  break;
		}
	      break;
	  ENDFOR(mf);
	  // TODO pass stmask to reading app
	  break; }
	case 0xa0: // BlockGroup
	  if (!have_timecode)
	    errorjmp(mf,"Found BlockGroup before cluster TimeCode");
	  parseBlockGroup(mf,len,mf->tcCluster);
	  goto out;
      ENDFOR(mf);
out:;
    } else {
      if (toplen > MAXFRAME)
	errorjmp(mf,"Element in a cluster is too large around %llu, %X [%u]",filepos(mf),cid,(unsigned)toplen);
      if (cid == 0xa0) // BlockGroup
	parseBlockGroup(mf,toplen,mf->tcCluster);
      else
	skipbytes(mf,toplen);
    }

    if ((mf->readPosition = filepos(mf)) > cstop)
      break;
  }

  mf->readPosition = filepos(mf);

ex:
  memcpy(&mf->jb,&jb,sizeof(jb));

  return ret;
}

// this is almost the same as readMoreBlocks, except it ensures
// there are no partial frames queued, however empty queues are ok
static int  fillQueues(MatroskaFile *mf,unsigned int mask) {
  unsigned    i,j;
  int	      ret = 0;

  for (;;) {
    j = 0;

    for (i=0;i<mf->nTracks;++i)
      if (mf->Queues[i].head && !(mask & (1<<i)))
	++j;

    if (j>0) // have at least some frames
      return ret;

    if ((ret = readMoreBlocks(mf)) < 0) {
      j = 0;
      for (i=0;i<mf->nTracks;++i)
	if (mf->Queues[i].head && !(mask & (1<<i)))
	  ++j;
      if (j) // we adjusted some blocks
	return 0;
      return EOF;
    }
  }
}

static void reindex(MatroskaFile *mf) {
  jmp_buf     jb;
  ulonglong   pos = mf->pCluster;
  ulonglong   step = 10*1024*1024;
  ulonglong   size, tc=0, isize; //Picard
  longlong    next_cluster;
  int	      id, have_tc, bad;
  struct Cue  *cue;

  if (pos >= mf->pSegmentTop)
    return;

  if (pos + step * 10 > mf->pSegmentTop)
    step = (mf->pSegmentTop - pos) / 10;
  if (step == 0)
    step = 1;

  memcpy(&jb,&mf->jb,sizeof(jb));

  // remove all cues
  mf->nCues = 0;

  bad = 0;

  while (pos < mf->pSegmentTop) {
    if (!mf->cache->progress(mf->cache,pos,mf->pSegmentTop))
      break;

    if (++bad > 50) {
      pos += step;
      bad = 0;
      continue;
    }

    // find next cluster header
    next_cluster = mf->cache->scan(mf->cache,pos,0x1f43b675); // cluster
    if (next_cluster < 0 || (ulonglong)next_cluster >= mf->pSegmentTop)
      break;

    pos = next_cluster + 4; // prevent endless loops

    if (setjmp(mf->jb)) // something evil happened while reindexing
      continue;

    seek(mf,next_cluster);

    id = readID(mf);
    if (id == EOF)
      break;
    if (id != 0x1f43b675) // shouldn't happen
      continue;

    size = readVLUInt(mf);
    if (size >= MAXCLUSTER || size < 1024)
      continue;

    have_tc = 0;
    size += filepos(mf);

    while (filepos(mf) < (ulonglong)next_cluster + 1024) {
      id = readID(mf);
      if (id == EOF)
	break;

      isize = readVLUInt(mf);

      if (id == 0xe7) { // cluster timecode
	tc = readUInt(mf,(unsigned)isize);
	have_tc = 1;
	break;
      }

      skipbytes(mf,isize);
    }

    if (!have_tc)
      continue;

    seek(mf,size);
    id = readID(mf);

    if (id == EOF)
      break;

    if (id != 0x1f43b675) // cluster
      continue;

    // good cluster, remember it
    cue = AGET(mf,Cues);
    cue->Time = tc;
    cue->Position = next_cluster - mf->pSegment;
    cue->Block = 0;
    cue->Track = 0;

    // advance to the next point
    pos = next_cluster + step;
    if (pos < size)
      pos = size;

    bad = 0;
  }

  fixupCues(mf);

  if (mf->nCues == 0) {
    cue = AGET(mf,Cues);
    cue->Time = mf->firstTimecode;
    cue->Position = mf->pCluster - mf->pSegment;
    cue->Block = 0;
    cue->Track = 0;
  }

  mf->cache->progress(mf->cache,0,0);

  memcpy(&mf->jb,&jb,sizeof(jb));
}

static void fixupChapter(ulonglong adj, struct Chapter *ch) {
  unsigned i;

  if (ch->Start != 0)
    ch->Start -= adj;
  if (ch->End != 0)
    ch->End -= adj;

  for (i=0;i<ch->nChildren;++i)
    fixupChapter(adj,&ch->Children[i]);
}

static longlong	findLastTimecode(MatroskaFile *mf) {
  ulonglong   nd = 0;
  unsigned    n,vtrack;

  if (mf->nCues == 0 || mf->nTracks == 0)
    return -1;

  for (n=vtrack=0;n<mf->nTracks;++n)
    if (mf->Tracks[n]->Type == TT_VIDEO) {
      vtrack = n;
      goto ok;
    }

  return -1;
ok:

  EmptyQueues(mf);

  mf->trackMask = ~(1 << vtrack);
  mf->readPosition = mf->Cues[mf->nCues - 1].Position + mf->pSegme

⌨️ 快捷键说明

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