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

📄 avifile.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 5 页
字号:
  /* convert MainAVIHeader into AVIFILINFOW */
  memset(&This->fInfo, 0, sizeof(This->fInfo));
  This->fInfo.dwRate                = MainAVIHdr.dwMicroSecPerFrame;
  This->fInfo.dwScale               = 1000000;
  This->fInfo.dwMaxBytesPerSec      = MainAVIHdr.dwMaxBytesPerSec;
  This->fInfo.dwFlags               = MainAVIHdr.dwFlags;
  This->fInfo.dwCaps                = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
  This->fInfo.dwLength              = MainAVIHdr.dwTotalFrames;
  This->fInfo.dwStreams             = MainAVIHdr.dwStreams;
  This->fInfo.dwSuggestedBufferSize = MainAVIHdr.dwSuggestedBufferSize;
  This->fInfo.dwWidth               = MainAVIHdr.dwWidth;
  This->fInfo.dwHeight              = MainAVIHdr.dwHeight;
  LoadStringW(AVIFILE_hModule, IDS_AVIFILETYPE, This->fInfo.szFileType,
	      sizeof(This->fInfo.szFileType));

  /* go back to into header list */
  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
    return AVIERR_FILEREAD;

  /* foreach stream exists a "LIST","strl" chunk */
  for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
    /* get next nested chunk in this "LIST","strl" */
    if (mmioDescend(This->hmmio, &ckLIST2, &ckLIST1, 0) != S_OK)
      return AVIERR_FILEREAD;

    /* nested chunk must be of type "LIST","strl" -- when not normally JUNK */
    if (ckLIST2.ckid == FOURCC_LIST &&
	ckLIST2.fccType == listtypeSTREAMHEADER) {
      pStream = This->ppStreams[nStream] =
	HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAVIStreamImpl));
      if (pStream == NULL)
	return AVIERR_MEMORY;
      AVIFILE_ConstructAVIStream(This, nStream, NULL);

      ck.ckid = 0;
      while (mmioDescend(This->hmmio, &ck, &ckLIST2, 0) == S_OK) {
	switch (ck.ckid) {
	case ckidSTREAMHANDLERDATA:
	  if (pStream->lpHandlerData != NULL)
	    return AVIERR_BADFORMAT;
	  pStream->lpHandlerData = HeapAlloc(GetProcessHeap(), 0, ck.cksize);
	  if (pStream->lpHandlerData == NULL)
	    return AVIERR_MEMORY;
	  pStream->cbHandlerData = ck.cksize;

	  if (mmioRead(This->hmmio, (HPSTR)pStream->lpHandlerData, ck.cksize) != ck.cksize)
	    return AVIERR_FILEREAD;
	  break;
	case ckidSTREAMFORMAT:
	  if (pStream->lpFormat != NULL)
	    return AVIERR_BADFORMAT;
          if (ck.cksize == 0)
            break;

	  pStream->lpFormat = HeapAlloc(GetProcessHeap(), 0, ck.cksize);
	  if (pStream->lpFormat == NULL)
	    return AVIERR_MEMORY;
	  pStream->cbFormat = ck.cksize;

	  if (mmioRead(This->hmmio, (HPSTR)pStream->lpFormat, ck.cksize) != ck.cksize)
	    return AVIERR_FILEREAD;

	  if (pStream->sInfo.fccType == streamtypeVIDEO) {
	    LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)pStream->lpFormat;

	    /* some corrections to the video format */
	    if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
	      lpbi->biClrUsed = 1u << lpbi->biBitCount;
	    if (lpbi->biCompression == BI_RGB && lpbi->biSizeImage == 0)
	      lpbi->biSizeImage = DIBWIDTHBYTES(*lpbi) * lpbi->biHeight;
	    if (lpbi->biCompression != BI_RGB && lpbi->biBitCount == 8) {
	      if (pStream->sInfo.fccHandler == mmioFOURCC('R','L','E','0') ||
		  pStream->sInfo.fccHandler == mmioFOURCC('R','L','E',' '))
		lpbi->biCompression = BI_RLE8;
	    }
	    if (lpbi->biCompression == BI_RGB &&
		(pStream->sInfo.fccHandler == 0 ||
		 pStream->sInfo.fccHandler == mmioFOURCC('N','O','N','E')))
	      pStream->sInfo.fccHandler = comptypeDIB;

	    /* init rcFrame if it's empty */
	    if (IsRectEmpty(&pStream->sInfo.rcFrame))
	      SetRect(&pStream->sInfo.rcFrame, 0, 0, lpbi->biWidth, lpbi->biHeight);
	  }
	  break;
	case ckidSTREAMHEADER:
	  {
	    static const WCHAR streamTypeFmt[] = {'%','4','.','4','h','s',0};

	    AVIStreamHeader streamHdr;
	    WCHAR           szType[25];
	    WCHAR           streamNameFmt[25];
	    UINT            count;
	    LONG            n = ck.cksize;

	    if (ck.cksize > sizeof(streamHdr))
	      n = sizeof(streamHdr);

	    if (mmioRead(This->hmmio, (HPSTR)&streamHdr, n) != n)
	      return AVIERR_FILEREAD;

	    pStream->sInfo.fccType               = streamHdr.fccType;
	    pStream->sInfo.fccHandler            = streamHdr.fccHandler;
	    pStream->sInfo.dwFlags               = streamHdr.dwFlags;
	    pStream->sInfo.wPriority             = streamHdr.wPriority;
	    pStream->sInfo.wLanguage             = streamHdr.wLanguage;
	    pStream->sInfo.dwInitialFrames       = streamHdr.dwInitialFrames;
	    pStream->sInfo.dwScale               = streamHdr.dwScale;
	    pStream->sInfo.dwRate                = streamHdr.dwRate;
	    pStream->sInfo.dwStart               = streamHdr.dwStart;
	    pStream->sInfo.dwLength              = streamHdr.dwLength;
	    pStream->sInfo.dwSuggestedBufferSize =
	      streamHdr.dwSuggestedBufferSize;
	    pStream->sInfo.dwQuality             = streamHdr.dwQuality;
	    pStream->sInfo.dwSampleSize          = streamHdr.dwSampleSize;
	    pStream->sInfo.rcFrame.left          = streamHdr.rcFrame.left;
	    pStream->sInfo.rcFrame.top           = streamHdr.rcFrame.top;
	    pStream->sInfo.rcFrame.right         = streamHdr.rcFrame.right;
	    pStream->sInfo.rcFrame.bottom        = streamHdr.rcFrame.bottom;
	    pStream->sInfo.dwEditCount           = 0;
	    pStream->sInfo.dwFormatChangeCount   = 0;

	    /* generate description for stream like "filename.avi Type #n" */
	    if (streamHdr.fccType == streamtypeVIDEO)
	      LoadStringW(AVIFILE_hModule, IDS_VIDEO, szType, sizeof(szType));
	    else if (streamHdr.fccType == streamtypeAUDIO)
	      LoadStringW(AVIFILE_hModule, IDS_AUDIO, szType, sizeof(szType));
	    else
	      wsprintfW(szType, streamTypeFmt, (char*)&streamHdr.fccType);

	    /* get count of this streamtype up to this stream */
	    count = 0;
	    for (n = nStream; 0 <= n; n--) {
	      if (This->ppStreams[n]->sInfo.fccHandler == streamHdr.fccType)
		count++;
	    }

	    memset(pStream->sInfo.szName, 0, sizeof(pStream->sInfo.szName));

	    LoadStringW(AVIFILE_hModule, IDS_AVISTREAMFORMAT, streamNameFmt, sizeof(streamNameFmt));

	    /* FIXME: avoid overflow -- better use wsnprintfW, which doesn't exists ! */
	    wsprintfW(pStream->sInfo.szName, streamNameFmt,
		      AVIFILE_BasenameW(This->szFileName), szType, count);
	  }
	  break;
	case ckidSTREAMNAME:
	  { /* streamname will be saved as ASCII string */
	    LPSTR str = HeapAlloc(GetProcessHeap(), 0, ck.cksize);
	    if (str == NULL)
	      return AVIERR_MEMORY;

	    if (mmioRead(This->hmmio, (HPSTR)str, ck.cksize) != ck.cksize)
	    {
	      HeapFree(GetProcessHeap(), 0, str);
	      return AVIERR_FILEREAD;
	    }

	    MultiByteToWideChar(CP_ACP, 0, str, -1, pStream->sInfo.szName,
				sizeof(pStream->sInfo.szName)/sizeof(pStream->sInfo.szName[0]));

	    HeapFree(GetProcessHeap(), 0, str);
	  }
	  break;
	case ckidAVIPADDING:
	case mmioFOURCC('p','a','d','d'):
	  break;
	default:
          WARN(": found extra chunk 0x%08X\n", ck.ckid);
	  hr = ReadChunkIntoExtra(&pStream->extra, This->hmmio, &ck);
	  if (FAILED(hr))
	    return hr;
	};

	if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
	  return AVIERR_FILEREAD;
      }
    } else {
      /* nested chunks in "LIST","hdrl" which are not of type "LIST","strl" */
      hr = ReadChunkIntoExtra(&This->fileextra, This->hmmio, &ckLIST2);
      if (FAILED(hr))
	return hr;
    }
    if (mmioAscend(This->hmmio, &ckLIST2, 0) != S_OK)
      return AVIERR_FILEREAD;
  }

  /* read any extra headers in "LIST","hdrl" */
  FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ck, &ckLIST1, 0);
  if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
    return AVIERR_FILEREAD;

  /* search "LIST","movi" chunk in "RIFF","AVI " */
  ckLIST1.fccType = listtypeAVIMOVIE;
  hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ckLIST1, &ckRIFF,
			      MMIO_FINDLIST);
  if (FAILED(hr))
    return hr;

  This->dwMoviChunkPos = ckLIST1.dwDataOffset;
  This->dwIdxChunkPos  = ckLIST1.cksize + ckLIST1.dwDataOffset;
  if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
    return AVIERR_FILEREAD;

  /* try to find an index */
  ck.ckid = ckidAVINEWINDEX;
  hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio,
			      &ck, &ckRIFF, MMIO_FINDCHUNK);
  if (SUCCEEDED(hr) && ck.cksize > 0) {
    if (FAILED(AVIFILE_LoadIndex(This, ck.cksize, ckLIST1.dwDataOffset)))
      This->fInfo.dwFlags &= ~AVIFILEINFO_HASINDEX;
  }

  /* when we haven't found an index or it's bad, then build one
   * by parsing 'movi' chunk */
  if ((This->fInfo.dwFlags & AVIFILEINFO_HASINDEX) == 0) {
    for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++)
      This->ppStreams[nStream]->lLastFrame = -1;

    if (mmioSeek(This->hmmio, ckLIST1.dwDataOffset + sizeof(DWORD), SEEK_SET) == -1) {
      ERR(": Oops, can't seek back to 'movi' chunk!\n");
      return AVIERR_FILEREAD;
    }

    /* seek through the 'movi' list until end */
    while (mmioDescend(This->hmmio, &ck, &ckLIST1, 0) == S_OK) {
      if (ck.ckid != FOURCC_LIST) {
	if (mmioAscend(This->hmmio, &ck, 0) == S_OK) {
	  nStream = StreamFromFOURCC(ck.ckid);

	  if (nStream > This->fInfo.dwStreams)
	    return AVIERR_BADFORMAT;

	  AVIFILE_AddFrame(This->ppStreams[nStream], ck.ckid, ck.cksize,
			   ck.dwDataOffset - 2 * sizeof(DWORD), 0);
	} else {
	  nStream = StreamFromFOURCC(ck.ckid);
	  WARN(": file seems to be truncated!\n");
	  if (nStream <= This->fInfo.dwStreams &&
	      This->ppStreams[nStream]->sInfo.dwSampleSize > 0) {
	    ck.cksize = mmioSeek(This->hmmio, 0, SEEK_END);
	    if (ck.cksize != -1) {
	      ck.cksize -= ck.dwDataOffset;
	      ck.cksize &= ~(This->ppStreams[nStream]->sInfo.dwSampleSize - 1);

	      AVIFILE_AddFrame(This->ppStreams[nStream], ck.ckid, ck.cksize,
			       ck.dwDataOffset - 2 * sizeof(DWORD), 0);
	    }
	  }
	}
      }
    }
  }

  /* find other chunks */
  FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ck, &ckRIFF, 0);

  return AVIERR_OK;
}

static HRESULT AVIFILE_LoadIndex(IAVIFileImpl *This, DWORD size, DWORD offset)
{
  AVIINDEXENTRY *lp;
  DWORD          pos, n;
  HRESULT        hr = AVIERR_OK;
  BOOL           bAbsolute = TRUE;

  lp = HeapAlloc(GetProcessHeap(), 0, IDX_PER_BLOCK * sizeof(AVIINDEXENTRY));
  if (lp == NULL)
    return AVIERR_MEMORY;

  /* adjust limits for index tables, so that inserting will be faster */
  for (n = 0; n < This->fInfo.dwStreams; n++) {
    IAVIStreamImpl *pStream = This->ppStreams[n];

    pStream->lLastFrame = -1;

    if (pStream->idxFrames != NULL) {
      HeapFree(GetProcessHeap(), 0, pStream->idxFrames);
      pStream->idxFrames  = NULL;
      pStream->nIdxFrames = 0;
    }

    if (pStream->sInfo.dwSampleSize != 0) {
      if (n > 0 && This->fInfo.dwFlags & AVIFILEINFO_ISINTERLEAVED) {
	pStream->nIdxFrames = This->ppStreams[0]->nIdxFrames;
      } else if (pStream->sInfo.dwSuggestedBufferSize) {
	pStream->nIdxFrames =
	  pStream->sInfo.dwLength / pStream->sInfo.dwSuggestedBufferSize;
      }
    } else
      pStream->nIdxFrames = pStream->sInfo.dwLength;

    pStream->idxFrames =
      HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pStream->nIdxFrames * sizeof(AVIINDEXENTRY));
    if (pStream->idxFrames == NULL && pStream->nIdxFrames > 0) {
      pStream->nIdxFrames = 0;
      return AVIERR_MEMORY;
    }
  }

  pos = (DWORD)-1;
  while (size != 0) {
    LONG read = min(IDX_PER_BLOCK * sizeof(AVIINDEXENTRY), size);

    if (mmioRead(This->hmmio, (HPSTR)lp, read) != read) {
      hr = AVIERR_FILEREAD;
      break;
    }
    size -= read;

    if (pos == (DWORD)-1)
      pos = offset - lp->dwChunkOffset + sizeof(DWORD);

    AVIFILE_ParseIndex(This, lp, read / sizeof(AVIINDEXENTRY),
		       pos, &bAbsolute);
  }

  HeapFree(GetProcessHeap(), 0, lp);

  /* checking ... */
  for (n = 0; n < This->fInfo.dwStreams; n++) {
    IAVIStreamImpl *pStream = This->ppStreams[n];

    if (pStream->sInfo.dwSampleSize == 0 &&
	pStream->sInfo.dwLength != pStream->lLastFrame+1)
      ERR("stream %u length mismatch: dwLength=%u found=%d\n",
	   n, pStream->sInfo.dwLength, pStream->lLastFrame);
  }

  return hr;
}

static HRESULT AVIFILE_ParseIndex(IAVIFileImpl *This, AVIINDEXENTRY *lp,
				  LONG count, DWORD pos, BOOL *bAbsolute)
{
  if (lp == NULL)
    return AVIERR_BADPARAM;

  for (; count > 0; count--, lp++) {
    WORD nStream = StreamFromFOURCC(lp->ckid);

    if (lp->ckid == listtypeAVIRECORD || nStream == 0x7F)
      continue; /* skip these */

    if (nStream > This->fInfo.dwStreams)
      return AVIERR_BADFORMAT;

    if (*bAbsolute && lp->dwChunkOffset < This->dwMoviChunkPos)
      *bAbsolute = FALSE;

    if (*bAbsolute)
      lp->dwChunkOffset += sizeof(DWORD);
    else
      lp->dwChunkOffset += pos;

    if (FAILED(AVIFILE_AddFrame(This->ppStreams[nStream], lp->ckid, lp->dwChunkLength, lp->dwChunkOffset, lp->dwFlags)))
      return AVIERR_MEMORY;
  }

  return AVIERR_OK;
}

static HRESULT AVIFILE_ReadBlock(IAVIStreamImpl *This, DWORD pos,
				 LPVOID buffer, LONG size)
{
  /* pre-conditions */
  assert(This != NULL);
  assert(This->paf != NULL);
  assert(This->paf->hmmio != NULL);
  assert(This->sInfo.dwStart <= pos && pos < This->sInfo.dwLength);
  assert(pos <= This->lLastFrame);

  /* should we read as much as block gives us? */
  if (size == 0 || size > This->idxFrames[pos].dwChunkLength)
    size = This->idxFrames[pos].dwChunkLength;

  /* read into out own buffer or given one? */
  if (buffer == NULL) {
    /* we also read the chunk */
    size += 2 * sizeof(DWORD);

    /* check that buffer is big enough -- don't trust dwSuggestedBufferSize */
    if (This->lpBuffer == NULL || size < This->cbBuffer) {
      DWORD maxSize = max(size, This->sInfo.dwSuggestedBufferSize);

      if (This->lpBuffer == NULL)
	This->lpBuffer = HeapAlloc(GetProcessHeap(), 0, maxSize);
      else
	This->lpBuffer = HeapReAlloc(GetProcessHeap(), 0, This->lpBuffer, maxSize);
      if (This->lpBuffer == NULL)
	return AVIERR_MEMORY;
      This->cbBuffer = max(size, This->sInfo.dwSuggestedBufferSize);
    }

    /* now read the complete chunk into our buffer */
    if (mmioSeek(This->paf->hmmio, This->idxFrames[pos].dwChunkOffset, SEEK_SET) == -1)
      return AVIERR_FILEREAD;
    if (mmioRead(This->paf->hmmio, (HPSTR)This->lpBuffer, size) != size)
      return AVIERR_FILEREAD;

    /* check if it was the correct block which we have read */
    if (This->lpBuffer[0] != This->idxFrames[pos].ckid ||
	This->lpBuffer[1] != This->idxFrames[pos].dwChunkLength) {
      ERR(": block %d not found at 0x%08X\n", pos, This->idxFrames[pos].dwChunkOffset);
      ERR(": Index says: '%4.4s'(0x%08X) size 0x%08X\n",
	  (char*)&This->idxFrames[pos].ckid, This->idxFrames[pos].ckid,
	  This->idxFrames[pos].dwChunk

⌨️ 快捷键说明

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