Demultiplex transport stream in pull mode
-
Thursday, September 27, 2007 5:38 PM
I have a transport stream file(.ts) and I need to demultiplex it to get various elementary streams and PSI data etc out of it using DirectShow.
The problem is neither MPEG2 Demux nor the MPEG2 splitter filter provided by DirectShow supports transport streams in pull mode.
So what should I do to connect the file source filter to demux filter?
Do I need to write my own filter which pulls data from file source filter and pushes it downstream.
If yes, then please guide on how to achieve that? I was looking at CPullPin class and I figured that I need to use this on my input pin. And to push data downstream, I can use CSourceStream class on the output pin. Is this the right way?
Any sample code or link that can guide me in writing custom filters would be appreciated as I am new to DirectShow.
Thanks.
PS: If I need to modify the in-built MPEG2 Demux filter provided by M$, can I do that or do I need to write the complete demux filter myself. I can take a .ts file, analyze its contents and take the various streams out of it using file operations in C/C++ but how to do that using direct show filters? How can I pass a data, say 100 bytes, generated by my code to a filter? Sorry for asking so many questions in one post..
All Replies
-
Thursday, September 27, 2007 6:19 PM
Thanks Microsoft for nuking my post again! I just love typing stuff out twice!I recommend that your write a custom source filter. The custom source filter will be much easier as you will only have 1 pin, derived from CSourceStream. You will need to implement the IFileSourceFilter interface but it is very simple.
You can register the .ts file extension to your source filter for automatic graph building if you like. You output pin should probably have a major type of MEDIATYPE_Stream and a subtype of MEDIASUBTYPE_MPEG2_TRANSPORT if it is a standard transport stream with 188 byte packets, you can review to docs for more info on that. You should deliver data aligned to the packet boundaries.
I think the development time to write a source filter is about half of that of a pull-push filter, but that's just my experience.
You can not modify the Microsoft filter as there is no source code available to the public. I have access to the source but I'm not allowed to download it or modify it in any way. You would have to re-write it completely from scratch.
-
Monday, October 01, 2007 9:02 AM
My recommendation would be to start with the mpeg-1 pull-mode demux at www.gdcl.co.uk and then add mpeg-2 and TS parsing to this.
G
-
Thursday, October 04, 2007 10:37 AM
WOW!! How lucky this question is to get a reply from G(OD)eraint Davies!!!!!!!!!!!!!!!!
I tried hard to follow the invaluable advice of Chris P. and created a filter derived from CSource and derived its output pin from CSourceStream.
Using the push source filter provided in the samples as reference, I followed the steps in documentation for CSource class for creating a output pin.Since my only problem was to get the data out of transport stream stored in a file and push it to demux so that demux can work in pull mode for transport stream, so I simply read 188 bytes transport packets from .ts file and copied it to the buffer of the sample of output pin.
See the following code..[code]
/***************************************************************
COutputPin Class
******************************************************************/COutputPin::COutputPin(HRESULT *phr, CSource *pFilter)
: CSourceStream(NAME("Push Source Bitmap"), phr, pFilter, L"Out"),
m_count(0),m_EOS(FALSE),
m_hFile(INVALID_HANDLE_VALUE)
{m_hFile = CreateFile("D:\\file.ts", // open file containing transport stream
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // no security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. templateif (m_hFile == INVALID_HANDLE_VALUE)
{
MessageBox(NULL,_T("Could not open "D:\file.ts"),NULL,NULL);
}
SetFilePointer(m_hFile,0,0,FILE_BEGIN);// m_filesize = GetFileSize (m_hFile, NULL) ; //4,294,967,295 ~ 4 GB maximum
}
COutputPin::~COutputPin()
{CloseHandle(m_hFile);
// The constructor might quit early on error and not close the file...
if (m_hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hFile);}
}
HRESULT COutputPin::GetMediaType(CMediaType *pMediaType)
{
CAutoLock cAutoLock(m_pFilter->pStateLock());CheckPointer(pMediaType, E_POINTER);
pMediaType->SetType(&MEDIATYPE_Stream);
pMediaType->SetSubtype(&MEDIASUBTYPE_MPEG2_TRANSPORT);pMediaType->SetFormatType(&FORMAT_MPEG2Video);
pMediaType->SetTemporalCompression(FALSE);
pMediaType->SetSampleSize(PACKET_SIZE);
return S_OK;
}HRESULT COutputPin:
ecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest)
{
HRESULT hr;
CAutoLock cAutoLock(m_pFilter->pStateLock());CheckPointer(pAlloc, E_POINTER);
CheckPointer(pRequest, E_POINTER);// Ensure a minimum number of buffers
if (pRequest->cBuffers == 0)
{
pRequest->cBuffers = 2;
}pRequest->cbBuffer = PACKET_SIZE;
ALLOCATOR_PROPERTIES Actual;
hr = pAlloc->SetProperties(pRequest, &Actual);
if (FAILED(hr))
{
return hr;
}// Is this allocator unsuitable?
if (Actual.cbBuffer < pRequest->cbBuffer)
{
return E_FAIL;
}return S_OK;
}HRESULT COutputPin::FillBuffer(IMediaSample *pSample)
{
BYTE *pData;
long cbData;CheckPointer(pSample, E_POINTER);
CAutoLock cAutoLockShared(&m_cSharedState);
pSample->GetPointer(&pData);
cbData = pSample->GetSize();if(!m_EOS) //m_EOS is TRUE when we reach the end of file
m_pData = GetData();
if(m_pData)
{
memcpy(pData, m_pData, min(PACKET_SIZE, (DWORD) cbData));m_pData = NULL;
}
REFERENCE_TIME rtStop = 100;
pSample->SetTime(0,&rtStop);pSample->SetSyncPoint(TRUE); //to specify the sample as the synchronization point
return S_OK;
}/**************************************************************************************
Copies 188 bytes read from file and return the pointer to buffer.Once it reaches the end of file, it simply returns
*************************************************************************************/
BYTE* COutputPin::GetData()
{
DWORD bytesread;BOOL b = ReadFile(m_hFile,buffer,PACKET_SIZE,&bytesread,NULL);
if(!b)
{
MessageBox(NULL,_T("read opern failed"),NULL,NULL);
return NULL;
}else if(b && bytesread==0)
{
m_EOS = TRUE;
// SetFilePointer(m_hFile,0,0,FILE_BEGIN);
return NULL;
}return(buffer);
}/*************************************************************************
CFilter Class
**************************************************************************/
CFilter::CFilter(IUnknown *pUnk, HRESULT *phr)
: CSource(NAME("Push Source Filter"), pUnk, CLSID_SrcFilter)
{
m_pPin = new COutputPin(phr, this);if (phr)
{
if (m_pPin == NULL)
*phr = E_OUTOFMEMORY;
else
*phr = S_OK;
}
}
CFilter::~CFilter()
{
delete m_pPin;
}//pUnk inidcates which IUknown interface to use.
CUnknown * WINAPI CFilter::CreateInstance(IUnknown *pUnk, HRESULT *phr)
{
CFilter *pNewFilter = new CFilter(pUnk, phr );if (phr)
{
if (pNewFilter == NULL)
*phr = E_OUTOFMEMORY;
else
*phr = S_OK;
}return pNewFilter;
}[/code]
I ran it in GraphEdit by connecting MPEG2 Demux and third party decoder and yes, it works correctly.
But the problem is that once the stream is played in graph edit, it stops and then if I want to play it again, I need to disconnect and add my source filter again. It does not play on hitting the play button in graph edit.
What really happens when I click on Play button in graph edit?
Is calling GetData function and filling the output pin buffer with a new sample(the thing that I hv done here) a good approach?
If I want to play the file again from the beginning once it reaches the end, then I tried to reset the file pointer to the beginning when it reaches the end of stream in the GetData function( see the comment out line SetFilePointer) but this method is not working. It only replays the last frame of the stream?
Geraint Davies pointed me to an extremely useful article and I am reading about the parser filter. That is someting I would like to have in my application instead of using this source filter and MPEG2 demux. Thx G for that. I will get back to you soon regarding multiple graphs and this parser filter.
PS: Chris..do ctrl+a, ctrl+c before u post this time. I dont want u to thank m$ again..

Thx.
-
Friday, October 05, 2007 9:47 AM
Where do you reset m_EOS?


