TS Source Filter + MPEG-2 Demultiplexer Filter进行简单的TS流解复用(之一:在GraphEdit中测试)

// 所有原创文章转载请注明作者及链接
//
blackboycpp(AT)gmail.com
// QQ群: 135202158

 

 

这个Filter的主要作用是把TS文件分割成TS包并发送至下游的MPEG-2 Demultiplexer(Push模式)。
通过在GraphEdit里(当然也可以编码实现)对MPEG-2 Demultiplexer进行必要的设置,
再连接一些Decoder和Render filters, 可以播放此TS文件。

 

首先, MPEG-2 Demultiplexer是可以用于push模式的:(http://msdn.microsoft.com/en-us/library/dd390717(VS.85).aspx)

 

The MPEG-2 Demultiplexer ("demux") can operate in push mode or pull mode. In push mode, the data comes from a live source, such as a network broadcast. In pull mode, the data comes from a local file.

 

  • Pull mode is available in Windows XP and later, for program streams only. On down-level platforms, use the MPEG-2 Splitter filter.
  • Push mode is available on all platforms, for both program streams and transport streams.

 

 

 

 

1. 首先安装DirectX SDK 9.0c并配置好环境(包括BaseClasses的编译), 如果是在VC++2005下进行工作, 可以看我以前的转帖日志

2. 找一个TS文件, 如果机器上没有, 可以下载这个:http://www.dododge.net/roku/hd-test-streams/wjz-200309111230-clip.ts

   它是一个单节目TS流, 格式为:  视频(codec: MPEG4, PID:0x11), 音频(codec: AC3, PID:0x14)

2. 把位于“DirectX安装目录/Samples/C++/DirectShow/Filters”下的Ball例子复制一个, 我们就要改它了

3. 打开ball工程, 做以下改动:

 (1)修改输出pin媒体格式

  const AMOVIESETUP_MEDIATYPE sudOpPinTypes = { &MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG2_TRANSPORT }; 

 (2)注释掉不必要的函数, 主要是(如果编译时出错, 视情况再注释掉其他无用函数):

//HRESULT SetMediaType(const CMediaType *pMediaType); //HRESULT CheckMediaType(const CMediaType *pMediaType); //HRESULT GetMediaType(int iPosition, CMediaType *pmt); //STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); 

添加一个成员函数:

HRESULT GetMediaType(CMediaType *pMediaType); HRESULT CBallStream::GetMediaType(CMediaType *pmt) { CheckPointer(pmt,E_POINTER); CAutoLock cAutoLock(m_pFilter->pStateLock()); pmt->SetType(&MEDIATYPE_Stream); pmt->SetSubtype(&MEDIASUBTYPE_MPEG2_TRANSPORT); pmt->SetTemporalCompression(FALSE); return NOERROR; } // GetMediaType  

(3)添加一些成员, 用于操作我们的TS文件:

private: FILE* m_file; // TS文件指针 int m_flen; // TS文件长度 int m_offset; // TS文件读取偏移 

(4)在OnThreadCreate()成员函数中添加以下代码:

// 打开你硬盘上的TS文件 m_file = fopen("F://test.ts", "rb"); // 获取文件长度 fseek(m_file, 0L, SEEK_END); m_flen = ftell(m_file); // 我下载的这个文件,TS同步头0x47从第79字节开始 fseek(m_file, 79L, SEEK_SET); m_offset = 79; 

(5)在DecideBufferSize()成员函数中,将每个buffer大小改成188字节:

pProperties->cbBuffer = 188; 

(6)修改FillBuffer()成员函数:

HRESULT CBallStream::FillBuffer(IMediaSample *pms) { CheckPointer(pms,E_POINTER); ASSERT(m_Ball); BYTE *pData; long lDataLen; pms->GetPointer(&pData); lDataLen = pms->GetSize(); ZeroMemory(pData, lDataLen); { CAutoLock cAutoLockShared(&m_cSharedState); // 重复读文件 if(m_offset >= m_flen) { m_offset = 79; fseek(m_file, 79L, SEEK_SET); } // 用188字节的TS包数据填充Buffer fread(pData, 1, 188, m_file); m_offset += 188; } // 实际数据长度为188字节 pms->SetActualDataLength(188); pms->SetSyncPoint(FALSE); return NOERROR; } // FillBuffer 

(7)在CBallStream的构造和析构函数里添加一些初始化/反初始化代码, 主要是一些文件操作。

再检查一下还有哪些无关的代码没注释掉。

4. 编译工程, 如果出错, 依提示修改。 应该主要是一些以前例子的东西, 注释掉就可以了。

5. 使用regsvr32命令注释你生成的Filter,如:

 // 注册: D:/Ball/Debug>regsvr32 ball.ax // 反注册: D:/Ball/Debug>regsvr32 /u ball.ax 

6. 打开Grapedit(在DirectX SDK的DirectX Utilities中), 插入Bouncing Ball Filter和Mpeg-2 Demultiplexer Filter,

再把它们对应的pin相连。 并配置Mpeg-2 Demultiplexer, 设置好各个pin对应的媒体类型,映射好PID,

并将Pin输出的数据结构设为Elementary Stream (A/V only), 如下所示:

然后再添加Audio Render, Video Render,这时MPEG-2 Demultiplexer上应该会出现相应的输出pins,

点右键选render pin即可。 Graph Edit会自动挑选解码器并完成连接。 连接好的Filter Graph如下图:

TS Source Filter + MPEG-2 Demultiplexer Filter进行简单的TS流解复用(之一:在GraphEdit中测试)_第1张图片

 

 

 

然后运行graph就可以了

你可能感兴趣的:(Stream,filter,File,测试,Graph,Codec)