现在的位置: 首页 > 综合 > 正文

DirectShow开发快速入门之慨述(二)

2014年01月05日 ⁄ 综合 ⁄ 共 3321字 ⁄ 字号 评论关闭

3、媒体类型

  因为Directshow是基于com组件的,就需要有一种方式来描述filter graph每一个点的数据格式,例如,我们还以播放AVI文件为例,数据以RIFF块的形式进入graph中,然后被分割成视频和音频流,视频流有一系列的压缩的视频桢组成,解压后,视频流由一系列的无压缩的位图组成,音频流也要走同样的步骤。

Media Types: How DirectShow Represents Formats
  媒体类型是一种很普遍的,可以扩展的用来描述数字媒体格式的方法,当两个filter连接的时候,他们会就采用某一种媒体类型达成一致的协议。媒体类型定义了处于源头的filter将要给下游的filter发送什么样的数据,以及数据的physical layout。如果两个filter不能够支持同一种的媒体类型,那么他们就没法连接起来。

  对于大多数的应用来说,也许你不用考虑媒体类型,但是,有些应用程序中,你会直接应用到媒体类型的。

  媒体类型是通过AM_MEDIA_TYPE结构定义的,看看原始定义吧

typedef struct _MediaType {
  GUID majortype;
  GUID subtype;
  BOOL bFixedSizeSamples;
  BOOL bTemporalCompression;
  ULONG lSampleSize;
  GUID formattype;
  IUnknown *pUnk;
  ULONG cbFormat;
  [size_is(cbFormat)] BYTE *pbFormat;
} AM_MEDIA_TYPE;

  Major type:是一个GUID,用来定义数据的主类型,包括,音频,视频,unparsed字节流,MIDI数据,等等,具体可以参考msdn。

  Subtype:子类型,也是一个GUID,用来进一步的细化数据格式,例如,在视频主类型中,还包括RGB-24, RGB-32, UYVY等等一些子类型,在音频主类型中还包括PCM audio, MPEG-1 payload等类型,子类型提供了比主类型更详细的信息,但是并没有定义所有的格式,例如,视频的子类型并没有定义图像大小,桢率。这些由下面的字段定义。

  bFixedSizeSamples当这个值为TRUE时,表示sample大小固定。

  bTemporalCompression当这个值为TRUE时,表示sample采用了临时压缩格式,表明不是所有的桢都是关键桢,如果为FALSE,表明所有的都是关键桢。

  lSampleSize 表示sample的大小。对于压缩的数据,这个值可能为零。
  
  Formattype一个GUID值,用来表明内存块的格式。包括如下:FORMAT_None,FORMAT_DvInfo,FORMAT_MPEGVideo,FORMAT_MPEG2Video,FORMAT_VideoInfo,FORMAT_VideoInfo2,FORMAT_WaveFormatEx,GUID_NULL。

  pUnk该参数没有用到。

  cbFormat内存块的大小。

  pbFormat指向内存块的指针。

  下面我们看一段代码,看看filter如何检测媒体类型的。

HRESULT CheckMediaType(AM_MEDIA_TYPE *pmt)
{
  if (pmt == NULL) return E_POINTER;
  // Check the major type. We’re looking for video.
  if (pmt->majortype != MEDIATYPE_Video)
  {
   return VFW_E_INVALIDMEDIATYPE;
  }
  // Check the subtype. We’re looking for 24-bit RGB.
  if (pmt->subtype != MEDIASUBTYPE_RGB24)
  {
   return VFW_E_INVALIDMEDIATYPE;
  }
  // Check the format type and the size of the format block.
  if ((pmt->formattype == FORMAT_VideoInfo) && (pmt->cbFormat >= sizeof(VIDEOINFOHEADER) &&
(pmt->pbFormat != NULL))
  {
   // Now it’s safe to coerce the format block pointer to the
   // correct structure, as defined by the formattype GUID.
   VIDEOINFOHEADER *pVIH = (VIDEOINFOHEADER*)pmt->pbFormat;
   // Examine pVIH (not shown). If it looks OK, return S_OK.
   return S_OK;
  }
  return VFW_E_INVALIDMEDIATYPE;
}

  下面简单介绍几个和 Media Type相关的函数:

  AM_MEDIA_TYPE结构包含一个指向数据块的指针,因此,当你使用这个结构的时候,一定要小心内存分配,以防内存泄漏。

  分配函数

  1) AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc );

  这个函数分配一个新的AM_MEDIA_TYPE结构,包含特定格式的数据块。释放由这个函数分配的内存,可以调用DeleteMediaType函数

  2) STDAPI CreateAudioMediaType(const WAVEFORMATEX *pwfx,AM_MEDIA_TYPE *pmt,BOOL bSetFormat);

  该函数利用一个给定的WAVEFORMATIEX结构来初始化媒体类型,如果bsetFormat参数为TRUE,该函数就分配一块新的内存,如果原来的pmt已经包含内存,就有可能发生内存泄漏。为了避免内存泄漏,在调用这个函数前要调用FreeMediaType(),在这个函数返回之后,再次调用FreeMediaType(),释放format block。

  3) HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget,const AM_MEDIA_TYPE *pmtSource);

  这个函数复制了一个结构到另一个结构中去。这个函数也要重新分配内存给目的结构,如果pmtTarget,已经包含一个内存块,就要内存泄漏,因此,在调用该函数前后都要调用FreeMediaType函数。

  释放函数

  4) void WINAPI DeleteMediaType( AM_MEDIA_TYPE *pmt);

  无论是采用CoTaskMemAlloc函数还是用CreateMediaType函数分配的内存都可以用这个函数来释放,如果你没有连接基类的动态库,你可以用下面的代码

void MyDeleteMediaType(AM_MEDIA_TYPE *pmt)
{
  if (pmt != NULL)
  {
   MyFreeMediaType(*pmt); // 见下面的 FreeMediaType 函数
   CoTaskMemFree(pmt);
  }
}

  5) void WINAPI FreeMediaType( AM_MEDIA_TYPE& mt);

  这个函数用来释放数据块的内存,如果要删除AM_MEDIA_TYPE结构,可以使用DeleteMediaType函数。

void MyFreeMediaType(AM_MEDIA_TYPE& mt)
{
  if (mt.cbFormat != 0)
  {
   CoTaskMemFree((PVOID)mt.pbFormat);
   mt.cbFormat = 0;
   mt.pbFormat = NULL;
  }
  if (mt.pUnk != NULL)
  {
   // Unecessary because pUnk should not be used, but safest.
   mt.pUnk->Release();
   mt.pUnk = NULL;
  }
}

【上篇】
【下篇】

抱歉!评论已关闭.