//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // The use and distribution terms for this software are covered by the // Microsoft Limited Public License (Ms-LPL) // which can be found in the file MS-LPL.txt at the root of this distribution. // By using this software in any fashion, you are agreeing to be bound by // the terms of this license. // // The software is licensed “as-is.” // // You must not remove this notice, or any other, from this software. // // // // Demux code for Windows CE // //------------------------------------------------------------------------- //====================================================================== // Demux code for Windows CE //====================================================================== /*++ Module Name: mp2enum.cpp Abstract: This module contains enumerator implementations Revision History: 31-Aug-1999 created Notes: --*/ #include "precomp.h" #include "mp2demux.h" #include "mp2enum.h" #include "tsstats.h" #include "mp2seek.h" #include "pin_out.h" #include "filter.h" #include "bufsrc.h" #include "plparse.h" // --------------------------------------------------------------------------- // CEnumStreamMapBase // --------------------------------------------------------------------------- CEnumStreamMapBase::CEnumStreamMapBase ( IN REFIID riid ) : m_IID (riid), m_lRefcount (1), m_pCurStreamMapRecord (NULL), m_cStreamMaps (0), m_cStreamMapsLeft (0) { TRACE_CONSTRUCTOR (TEXT ("CEnumStreamMapBase")) ; TRACE_ENTER_0 (TEXT("CEnumStreamMapBase::CEnumStreamMapBase ()")) ; InitializeListHead (& m_StreamMapListHead) ; } CEnumStreamMapBase::CEnumStreamMapBase ( IN REFIID riid, IN CEnumStreamMapBase * pCEnumStreamMapBase, OUT HRESULT * pHr ) : m_IID (riid), m_lRefcount (1), m_pCurStreamMapRecord (NULL), m_cStreamMaps (0), m_cStreamMapsLeft (0) { #ifndef UNDER_CE HRESULT hr ; #endif //UNDER_CE STREAM_MAP_RECORD * pCurStreamMapRecord ; LIST_ENTRY * pListEntry ; ASSERT (pCEnumStreamMapBase) ; TRACE_CONSTRUCTOR (TEXT ("CEnumStreamMapBase")) ; TRACE_ENTER_0 (TEXT("CEnumStreamMapBase::CEnumStreamMapBase ()")) ; InitializeListHead (& m_StreamMapListHead) ; * pHr = S_OK ; for (pListEntry = pCEnumStreamMapBase -> m_StreamMapListHead.Flink ; pListEntry != & pCEnumStreamMapBase -> m_StreamMapListHead ; pListEntry = pListEntry -> Flink) { pCurStreamMapRecord = CONTAINING_RECORD (pListEntry, STREAM_MAP_RECORD, ListEntry) ; * pHr = AddStreamMap ( pCurStreamMapRecord -> dwStreamId, pCurStreamMapRecord -> pszPinID, pCurStreamMapRecord -> dwMediaSampleContent, pCurStreamMapRecord -> pvParserArg ) ; // break in the case of failure; means partial // success if (FAILED (* pHr)) { break ; } } } CEnumStreamMapBase::~CEnumStreamMapBase ( ) { LIST_ENTRY * pListEntry ; STREAM_MAP_RECORD * pStreamMapRecord ; while (!IsListEmpty (& m_StreamMapListHead)) { pListEntry = RemoveHeadList (& m_StreamMapListHead) ; pStreamMapRecord = CONTAINING_RECORD (pListEntry, STREAM_MAP_RECORD, ListEntry) ; CoTaskMemFree (pStreamMapRecord -> pszPinID) ; CoTaskMemFree (pStreamMapRecord -> pvParserArg) ; CoTaskMemFree (pStreamMapRecord) ; } } HRESULT CEnumStreamMapBase::AddStreamMap ( IN DWORD dwStreamId, IN LPWSTR pszPinID, IN DWORD dwMediaSampleContent, IN LPVOID pvParserArg ) // makes copies of all 3 parameters { STREAM_MAP_RECORD * pStreamMap ; #ifndef UNDER_CE int r ; #endif //UNDER_CE int iParserArgSize ; TRACE_ENTER_3 (TEXT("CEnumStreamMapBase::AddStreamMap (%08xh, %08xh, %08xh)"), dwStreamId, pszPinID, dwMediaSampleContent) ; ASSERT (pszPinID) ; // allocate for the STREAM_MAP_RECORD pStreamMap = (STREAM_MAP_RECORD *) CoTaskMemAlloc (sizeof STREAM_MAP_RECORD) ; if (pStreamMap == NULL) { return E_OUTOFMEMORY ; } // set the PID, media sample content pStreamMap -> dwStreamId = dwStreamId ; pStreamMap -> dwMediaSampleContent = dwMediaSampleContent ; // allocate pStreamMap -> pszPinID = (LPWSTR) CoTaskMemAlloc ((wcslen (pszPinID) + 1) * sizeof WCHAR) ; if (pStreamMap -> pszPinID == NULL) { CoTaskMemFree (pStreamMap) ; return E_OUTOFMEMORY ; } // copy the pin ID wcscpy ( pStreamMap -> pszPinID, pszPinID ) ; if (pvParserArg != NULL) { iParserArgSize = ParserArgSize (dwMediaSampleContent) ; pStreamMap -> pvParserArg = CoTaskMemAlloc (iParserArgSize) ; if (pStreamMap -> pvParserArg != NULL) { CopyMemory ( pStreamMap -> pvParserArg, pvParserArg, iParserArgSize ) ; } else { return E_OUTOFMEMORY ; } } else { pStreamMap -> pvParserArg = NULL ; } InsertTailList (& m_StreamMapListHead, & pStreamMap -> ListEntry) ; m_cStreamMaps++ ; m_cStreamMapsLeft++ ; return S_OK ; } HRESULT CEnumStreamMapBase::AddStreamMap ( IN DWORD dwStreamId, IN IPin * pIPin, IN DWORD dwMediaSampleContent, IN LPVOID pvParserArg ) { HRESULT hr ; LPWSTR pszPinID ; TRACE_ENTER_3 (TEXT("CEnumStreamMapBase::AddStreamMap (%08xh, %08xh, %08xh)"), dwStreamId, pIPin, dwMediaSampleContent) ; ASSERT (pIPin) ; // get the pin ID pszPinID = NULL ; hr = pIPin -> QueryId (& pszPinID) ; if (FAILED (hr)) { return E_OUTOFMEMORY ; } hr = AddStreamMap ( dwStreamId, pszPinID, dwMediaSampleContent, pvParserArg ) ; CoTaskMemFree (pszPinID) ; return hr ; } // --------------------------------------------------------------------------- // IEnumPIDMap // --------------------------------------------------------------------------- CDBDADemuxEnumPIDMap::CDBDADemuxEnumPIDMap ( ) : CEnumStreamMapBase ( IID_IEnumPIDMap ) { TRACE_CONSTRUCTOR (TEXT ("CDBDADemuxEnumPIDMap")) ; TRACE_ENTER_0 (TEXT("CDBDADemuxEnumPIDMap::CDBDADemuxEnumPIDMap ()")) ; } CDBDADemuxEnumPIDMap::CDBDADemuxEnumPIDMap ( IN CDBDADemuxEnumPIDMap * pCDBDADemuxEnumPIDMap, OUT HRESULT * pHr ) : CEnumStreamMapBase ( IID_IEnumPIDMap, pCDBDADemuxEnumPIDMap, pHr ) { TRACE_CONSTRUCTOR (TEXT ("CDBDADemuxEnumPIDMap")) ; TRACE_ENTER_0 (TEXT("CDBDADemuxEnumPIDMap::CDBDADemuxEnumPIDMap ()")) ; } CDBDADemuxEnumPIDMap::~CDBDADemuxEnumPIDMap ( ) { TRACE_DESTRUCTOR (TEXT ("CDBDADemuxEnumPIDMap")) ; TRACE_ENTER_0 (TEXT("CDBDADemuxEnumPIDMap::~CDBDADemuxEnumPIDMap ()")) ; } // IEnumMPEG2PIDMap STDMETHODIMP CDBDADemuxEnumPIDMap::Next ( IN ULONG cRequest, IN OUT PID_MAP * pPIDMap, OUT ULONG * pcReceived ) { DWORD cPIDMapsReturn ; LIST_ENTRY * pListEntry ; DWORD dwMediaSampleContent ; HRESULT hr ; TRACE_ENTER_3 (TEXT("CDBDADemuxEnumPIDMap::Next (%08xh, %08xh, %08xh)"), cRequest, pPIDMap, pcReceived) ; if (cRequest == 0 && pcReceived != NULL) { (* pcReceived) = m_cStreamMapsLeft ; return S_OK ; } else if (pPIDMap == NULL || pcReceived == NULL) { return E_INVALIDARG ; } // initialize the return count * pcReceived = 0 ; // figure out how many we can return cPIDMapsReturn = m_cStreamMapsLeft ; cPIDMapsReturn = MIN (cPIDMapsReturn, cRequest) ; // if there are none to return, stop here if (cPIDMapsReturn == 0) { return S_FALSE ; } ASSERT (!IsListEmpty (& m_StreamMapListHead)) ; if (m_pCurStreamMapRecord == NULL) { pListEntry = m_StreamMapListHead.Flink ; m_pCurStreamMapRecord = CONTAINING_RECORD (pListEntry, STREAM_MAP_RECORD, ListEntry) ; } ASSERT (m_pCurStreamMapRecord) ; // for each STREAM_MAP_RECORD we will return while (cPIDMapsReturn > 0) { hr = TransportMediaSampleContentItoE ( m_pCurStreamMapRecord -> dwMediaSampleContent, & dwMediaSampleContent ) ; // values are validated on the way in ASSERT (SUCCEEDED (hr)) ; // set the PID value pPIDMap [* pcReceived].ulPID = m_pCurStreamMapRecord -> dwStreamId ; pPIDMap [* pcReceived].MediaSampleContent = (MEDIA_SAMPLE_CONTENT) dwMediaSampleContent ; // update our counters (* pcReceived)++ ; cPIDMapsReturn-- ; pListEntry = m_pCurStreamMapRecord -> ListEntry.Flink ; m_pCurStreamMapRecord = CONTAINING_RECORD (pListEntry, STREAM_MAP_RECORD, ListEntry) ; m_cStreamMapsLeft-- ; } return S_OK ; } STDMETHODIMP CDBDADemuxEnumPIDMap::Skip ( IN ULONG cRecords ) { LIST_ENTRY * pListEntry ; TRACE_ENTER_1 (TEXT("CDBDADemuxEnumPIDMap::Skip (%08xh)"), cRecords) ; if (cRecords >= m_cStreamMapsLeft) { return S_FALSE ; } // might have to initialize if (m_pCurStreamMapRecord == NULL) { pListEntry = m_StreamMapListHead.Flink ; m_pCurStreamMapRecord = CONTAINING_RECORD (pListEntry, STREAM_MAP_RECORD, ListEntry) ; } else { pListEntry = & m_pCurStreamMapRecord -> ListEntry ; } // skip ahead for (DWORD i = 0; i < cRecords; i++, pListEntry = pListEntry -> Flink, m_cStreamMapsLeft--) ; // reset our current pointer m_pCurStreamMapRecord = CONTAINING_RECORD (pListEntry, STREAM_MAP_RECORD, ListEntry) ; return S_OK ; } STDMETHODIMP CDBDADemuxEnumPIDMap::Reset ( ) { TRACE_ENTER_0 (TEXT("CDBDADemuxEnumPIDMap::Reset ()")) ; m_pCurStreamMapRecord = NULL ; m_cStreamMapsLeft = m_cStreamMaps ; return S_OK ; } STDMETHODIMP CDBDADemuxEnumPIDMap::Clone ( OUT IEnumPIDMap ** ppIEnum ) { CDBDADemuxEnumPIDMap * pCDBDADemuxEnumPIDMap ; HRESULT hr ; TRACE_ENTER_1 (TEXT("CDBDADemuxEnumPIDMap::Clone (%08xh)"), ppIEnum) ; if (ppIEnum == NULL) { return E_INVALIDARG ; } // copy pCDBDADemuxEnumPIDMap = new CDBDADemuxEnumPIDMap ( this, & hr ) ; // confirm if (pCDBDADemuxEnumPIDMap == NULL) { return E_OUTOFMEMORY ; } if (FAILED (hr)) { delete pCDBDADemuxEnumPIDMap ; return hr ; } * ppIEnum = pCDBDADemuxEnumPIDMap ; // refcounts: pCDBDADemuxEnumPIDMap should have a refcount of 1, which // pass out as the caller's refcount return S_OK ; } // --------------------------------------------------------------------------- // IEnumStreamIdMap // --------------------------------------------------------------------------- CDBDADemuxEnumStreamIdMap::CDBDADemuxEnumStreamIdMap ( ) : CEnumStreamMapBase ( IID_IEnumPIDMap ) { TRACE_CONSTRUCTOR (TEXT ("CDBDADemuxEnumStreamIdMap")) ; TRACE_ENTER_0 (TEXT("CDBDADemuxEnumStreamIdMap::CDBDADemuxEnumStreamIdMap ()")) ; } CDBDADemuxEnumStreamIdMap::CDBDADemuxEnumStreamIdMap ( IN CDBDADemuxEnumStreamIdMap * pCDBDADemuxEnumStreamIdMap, OUT HRESULT * pHr ) : CEnumStreamMapBase ( IID_IEnumStreamIdMap, pCDBDADemuxEnumStreamIdMap, pHr ) { TRACE_CONSTRUCTOR (TEXT ("CDBDADemuxEnumStreamIdMap")) ; } CDBDADemuxEnumStreamIdMap::~CDBDADemuxEnumStreamIdMap ( ) { TRACE_DESTRUCTOR (TEXT ("CDBDADemuxEnumStreamIdMap")) ; } // IEnumMPEG2PIDMap STDMETHODIMP CDBDADemuxEnumStreamIdMap::Next ( IN ULONG cRequest, IN OUT STREAM_ID_MAP * pStreamIdMap, OUT ULONG * pcReceived ) { DWORD cStreamIdMapsReturn ; LIST_ENTRY * pListEntry ; DWORD dwMediaSampleContent ; AUDIO_FILTER_INFO * pAudioFilterInfo ; HRESULT hr ; TRACE_ENTER_3 (TEXT("CDBDADemuxEnumStreamIdMap::Next (%08xh, %08xh, %08xh)"), cRequest, pStreamIdMap, pcReceived) ; // check for the case where the caller just wants to know how many are left if (cRequest == 0 && pcReceived != NULL) { (* pcReceived) = m_cStreamMapsLeft ; return S_OK ; } else if (pStreamIdMap == NULL || pcReceived == NULL) { return E_INVALIDARG ; } // initialize the return count * pcReceived = 0 ; // figure out how many we can return cStreamIdMapsReturn = m_cStreamMapsLeft ; cStreamIdMapsReturn = MIN (cStreamIdMapsReturn, cRequest) ; // if there are none to return, stop here if (cStreamIdMapsReturn == 0) { return S_FALSE ; } ASSERT (!IsListEmpty (& m_StreamMapListHead)) ; if (m_pCurStreamMapRecord == NULL) { pListEntry = m_StreamMapListHead.Flink ; m_pCurStreamMapRecord = CONTAINING_RECORD (pListEntry, STREAM_MAP_RECORD, ListEntry) ; } ASSERT (m_pCurStreamMapRecord) ; // for each STREAM_MAP_RECORD we will return while (cStreamIdMapsReturn > 0) { hr = ProgramMediaSampleContentItoE ( m_pCurStreamMapRecord -> dwMediaSampleContent, & dwMediaSampleContent ) ; // values are validated on the way in ASSERT (SUCCEEDED (hr)) ; // set the map values pStreamIdMap [* pcReceived].stream_id = m_pCurStreamMapRecord -> dwStreamId ; pStreamIdMap [* pcReceived].dwMediaSampleContent = dwMediaSampleContent ; if (m_pCurStreamMapRecord -> pvParserArg != NULL && m_pCurStreamMapRecord -> dwMediaSampleContent == MPEG2_MEDIA_ELEMENTARY_STREAM) { pAudioFilterInfo = reinterpret_cast (m_pCurStreamMapRecord -> pvParserArg) ; pStreamIdMap [* pcReceived].ulSubstreamFilterValue = pAudioFilterInfo -> dwSubstreamValue ; pStreamIdMap [* pcReceived].iDataOffset = pAudioFilterInfo -> iDataOffset ; } else { pStreamIdMap [* pcReceived].ulSubstreamFilterValue = SUBSTREAM_FILTER_VAL_NONE ; pStreamIdMap [* pcReceived].iDataOffset = 0 ; } // update our counters (* pcReceived)++ ; cStreamIdMapsReturn-- ; pListEntry = m_pCurStreamMapRecord -> ListEntry.Flink ; m_pCurStreamMapRecord = CONTAINING_RECORD (pListEntry, STREAM_MAP_RECORD, ListEntry) ; m_cStreamMapsLeft-- ; } return S_OK ; } STDMETHODIMP CDBDADemuxEnumStreamIdMap::Skip ( IN ULONG cRecords ) { LIST_ENTRY * pListEntry ; TRACE_ENTER_1 (TEXT("CDBDADemuxEnumStreamIdMap::Skip (%08xh)"), cRecords) ; if (cRecords >= m_cStreamMapsLeft) { return S_FALSE ; } // might have to initialize if (m_pCurStreamMapRecord == NULL) { pListEntry = m_StreamMapListHead.Flink ; m_pCurStreamMapRecord = CONTAINING_RECORD (pListEntry, STREAM_MAP_RECORD, ListEntry) ; } else { pListEntry = & m_pCurStreamMapRecord -> ListEntry ; } // skip ahead for (DWORD i = 0; i < cRecords; i++, pListEntry = pListEntry -> Flink, m_cStreamMapsLeft--) ; // reset our current pointer m_pCurStreamMapRecord = CONTAINING_RECORD (pListEntry, STREAM_MAP_RECORD, ListEntry) ; return S_OK ; } STDMETHODIMP CDBDADemuxEnumStreamIdMap::Reset ( ) { TRACE_ENTER_0 (TEXT("CDBDADemuxEnumStreamIdMap::Reset ()")) ; m_pCurStreamMapRecord = NULL ; m_cStreamMapsLeft = m_cStreamMaps ; return S_OK ; } STDMETHODIMP CDBDADemuxEnumStreamIdMap::Clone ( OUT IEnumStreamIdMap ** ppIEnum ) { CDBDADemuxEnumStreamIdMap * pCDBDADemuxEnumStreamIdMap ; HRESULT hr ; TRACE_ENTER_1 (TEXT("CDBDADemuxEnumStreamIdMap::Clone (%08xh)"), ppIEnum) ; if (ppIEnum == NULL) { return E_INVALIDARG ; } // copy pCDBDADemuxEnumStreamIdMap = new CDBDADemuxEnumStreamIdMap ( this, & hr ) ; // confirm if (pCDBDADemuxEnumStreamIdMap == NULL) { return E_OUTOFMEMORY ; } if (FAILED (hr)) { delete pCDBDADemuxEnumStreamIdMap ; return hr ; } * ppIEnum = pCDBDADemuxEnumStreamIdMap ; // refcounts: pCDBDADemuxEnumStreamIdMap should have a refcount of 1, which // pass out as the caller's refcount return S_OK ; }