//------------------------------------------------------------------------------
//
// 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 ;
}