//------------------------------------------------------------------------------ // // 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: precomp.h Abstract: This module contains project-wide declarations. If we could selectively use precompiled headers, this would be it. Revision History: 02-Jul-1999 created 04-Apr-2000 added bdaiface.h include Projectwide Notes: 1. unicode / ansi: all internals of the demux assume unicode. COM interface calls with strings are obviously unicode, so there's no conversion required there. DirectShow strings are unicode. The only time a conversion must be made to/from ansi is or UI i.e. property sheets. All the conversion code lives in uictrl.h and uictrl.cpp. The demux side of the interface objects which live in those files is unicode. The windowing side i.e. SendMessage, etc... are all TCHAR. Depending on the UNICODE definition or lack thereof, uictrl.* include conversion code to translate to when outputing to the UI, or convert from when reading from the UI. 2. Locking The demux implements locking on 3 levels: 1. filter level: normal dshow locking during state transitions of the filter and pins e.g. filter state transition from stopped to paused. 2. controller level: the controller locks calls that are not thread-safe e.g. MapPID & UnmapPID 3. vector level there are a number of vectors used internally; all are of type TSimpleVector, which has a lock as part of the class, however the lock is not used in all cases; specifically those cases where the operation on a vector is already protected by one of the other 2 locks; the vector for which this is used is the pin record vector The controller locking is quite intrusive and could be implemented at a finer granularity such as per PID map, but this would mean that locking/unlocking operations would happen each time a TS packet is processed, so expectedly, up to 13000 times/second vs. ~40 times/sec NOTE: there may also be a way to have just 1 lock on the m_PIDFilter and m_pPIDMapContext members of the mapper to retrieve the PID_MAP_CONTEXT data structure, and have subsequent PID maps and die by refcounts alone; updating an existing PID map would be very simple and non-intrusive and the data structure's destructor would take care of clearing what references it; this may be worth investigating, but we'll run into the very high hit rate on the lock. 3. counters / stats The demux makes available counters for other applications to use via a named file mapping object. See the comment block in tsstats.h for more details. 4. timeout support The demux has several mechanisms that trigger a downstream transmission of a media sample: (1) buffer fullness [e.g. a PES payload does not fit completely into 1 media sample], (2) a new payload [e.g. payload_unit_indicator bit is '1' as is the case with a new PES packet], (3) correct size of buffer has been gathered [e.g. a complete PSI section]. In the case of #2, in effect a new PES packet triggers the transmission downstream of the previous one. The result of this is that the last PES packet is never sent downstream, because the next one is never received. Another example occurs in pass-through mode, where buffer fullness triggers the transmission. If a PID carries very slow traffic that is still useful to downstream filters, they may have to wait for very long before a 64k buffer fills to see the traffic. To prevent this problem, a timeout mechanism has been implemented whereby a buffer becomes stale after a specified period of time and is sent downstream, regardless of the usual trigger. This is implemented by having the input thread check all mappings after a complete input buffer has been processed, and check for stale buffers. --*/ #ifndef _mp2demux__precomp_h #define _mp2demux__precomp_h #include #ifdef UNDER_CE #include "dshowfix.h" #endif // UNDER_CE #include #include // for the property pages #include #include #include #include #include // define this to use macros for header parsing vs. functions //#undef PARSE_WITH_MACROS #define PARSE_WITH_MACROS // --------------------------------------------------------------------------- // CONSTANTS // --------------------------------------------------------------------------- // filter - associated names #define FILTER_NAME L"MPEG-2 Demultiplexer" #define INPUT_PIN_NAME L"MPEG-2 Stream" #define VIDEO_PIN_NAME L"Video" #define AC3_AUDIO_PIN_NAME L"AC-3" #define MPEG1_AUDIO_PIN_NAME L"Mpeg-1" #define LPCM_AUDIO_PIN_NAME L"LPCM" #define PROP_PAGE_NAME_PINS L"Output Pins" #define PROP_PAGE_NAME_PID_MAP L"PID Mappings" #define PROP_PAGE_NAME_STREAMID_MAP L"stream_id Mappings" // filter-wide #define UNDEFINED -1 #define WILDCARD_STREAM -1 // --------------------------------------------------------------------------- // registry keys // registry - names #define REG_MPEG2_DEMUX TEXT ("SOFTWARE\\Microsoft\\MPEG2Demultiplexer") #define REG_TRANSPORT_SUBKEY TEXT ("Transport") #define REG_PROGRAM_SUBKEY TEXT ("Program") #define REG_MPEG2_TRANSPORT_DEMUX REG_MPEG2_DEMUX TEXT("\\") REG_TRANSPORT_SUBKEY #define REG_MPEG2_PROGRAM_DEMUX REG_MPEG2_DEMUX TEXT("\\") REG_PROGRAM_SUBKEY #define REG_REPORT_DISCONTINUITIES TEXT ("ReportDiscontinuities") #define REG_WAIT_FOR_FIRST_SEQUENCE_HEADER TEXT ("WaitForSequenceHeader") #define REG_STATS_LEVEL TEXT ("Stats") #define REG_TIMEOUT_CHECK_THRESHOLD TEXT ("TimeoutCheckThreshold") #define REG_TRACK_PSI TEXT ("TrackPSI") #define REG_ESTIMATED_INPUT_BITRATE TEXT ("EstimatedInputBitRate") #define REG_IMPLEMENT_IREFERENCECLOCK TEXT ("Clock") #define REG_STREAM_TYPE TEXT ("StreamType") #define REG_SET_SYNC_POINTS TEXT ("SetSyncPoints") #define REG_AUDIO_PTS_OFFSET_MILLIS TEXT ("AudioPTSOffsetMillis") #define REG_VIDEO_PTS_OFFSET_MILLIS TEXT ("VideoPTSOffsetMillis") #define REG_MAX_PTS_PADDING_MILLIS TEXT ("MaxPTSPaddingMillis") #define REG_CLOCKSUBORDINATE_SAMPLING_WIN_MILLIS_NAME \ TEXT ("ClockSubordinateMinSamplingWindowMillis") #define REG_CLOCKSUBORDINATE_HISTORY_MILLIS_NAME TEXT ("ClockSubordinateHistoryMillis") #define REG_CLOCKSUBORDINATE_MIN_SUBORDINATABLE_NAME\ TEXT ("ClockSubordinateMinSlavable") #define REG_CLOCKSUBORDINATE_MAX_SUBORDINATABLE_NAME\ TEXT ("ClockSubordinateMaxSlavable") #define REG_CLOCKSUBORDINATE_SETTLING_MILLIS TEXT ("ClockSubordinateSettlingMillis") #define REG_MIN_DOWNSTREAM_BUFFERING_MILLIS_NAME TEXT ("MinDownstreamBufferingMillis") #define REG_OVERPAD_MILLIS_NAME TEXT ("OverPadMillis") #define REG_MAX_GLITCHES_PER_HOUR_NAME TEXT ("ShiftMaxGlitchesPerHour") // ---------------------------------------------------------------------------- // default registry values // settle for 10sec before we start subordinating to the SCRs/PCRs #define REG_DEF_CLOCKSUBORDINATE_SETTLING_MILLIS 10000 #define REG_DEF_MAX_GLITCHES_PER_HOUR 60 // stream type #define REG_DEFAULT_INIT_STREAM_TYPE MPEG2_STREAM_UNDEFINED #define REG_DEFAULT_SET_SYNC_POINTS TRUE // report discontinuities to downstream filters #define REG_DEFAULT_REPORT_DISCONTINUITIES TRUE // wait for first sequence header before passing a PES payload downstream #define REG_DEFAULT_WAIT_FOR_SEQUENCE_HEADER TRUE // supported stats levels #define REG_STATS_LEVEL_NONE 0 #define REG_STATS_LEVEL_ENABLED 1 // default is to have no stats #define REG_DEFAULT_STATS_LEVEL REG_STATS_LEVEL_NONE // check for timeouts when more than #define REG_DEFAULT_TIMEOUT_CHECK_THRESHOLD 100 // track PSI #define REG_DEFAULT_TRACK_PSI 1 // estimate incoming bitrate to ATSC #define REG_DEFAULT_ESTIMATED_INPUT_BIT_RATE ATSC_BITRATE // demux implements IReferenceClock if queried #define REG_DEFAULT_IMPLEMENT_IREFERENCECLOCK 1 // we can offset PES PTSs by a fixed number of milliseconds to fine-tune // AV sync; this is audio; max allowable value follows #define REG_DEFAULT_REG_AUDIO_PTS_OFFSET_MILLIS 100 #define MAX_REG_AUDIO_PTS_OFFSET_MILLIS 1000 // we can offset PES PTSs by a fixed number of milliseconds to fine-tune // AV sync; this is video; max allowable value follows #define REG_DEFAULT_REG_VIDEO_PTS_OFFSET_MILLIS 100 #define MAX_REG_VIDEO_PTS_OFFSET_MILLIS 1000 #define REG_DEF_CLOCKSUBORDINATE_SAMPLING_WIN_MILLIS 2000 // we maintain a history of sampling windows for at most this long #define REG_DEF_CLOCKSUBORDINATE_HISTORY_MILLIS (120 * REG_DEF_CLOCKSUBORDINATE_SAMPLING_WIN_MILLIS) // min we try to subordinate to is when host clock is observed to run at 98% rate // of master clock #define REG_DEF_CLOCKSUBORDINATE_MIN_SUBORDINATABLE 95 // max we try to subordinate to is when host clock is observed to run at 102% rate // of master clock #define REG_DEF_CLOCKSUBORDINATE_MAX_SUBORDINATABLE 105 // minimum downstream buffering; when a PTS is generated it is examined against // now - tStart to ensure there's at least this much buffering #define REG_DEF_MIN_DOWNSTREAM_BUFFERING_MILLIS 200 // when we make a correction for buffering, we over correct // by this amount so we don't immediately jitter back down #define REG_DEF_OVERPAD_MILLIS 50 // --------------------------------------------------------------------------- // filter wide constants // --------------------------------------------------------------------------- // max output pin media sample payload #define DEFAULT_OUTPUT_PIN_BUFFER_MAX 8192 // number of media samples to allocate #define DEFAULT_OUTPUT_PIN_BUFFER_POOL 64 // minimum media sample pool for AV #define MIN_AV_BUFFER_POOL_SIZE 256 // media samples in batch for downstream send #define DEFAULT_SEND_BATCH_SIZE 1 // always send exact batches of media samples #define DEFAULT_SEND_BATCH_EXACT FALSE // master clock vs. host clock; this value the slope of each's delta; if they // are the same, the slope will be 1.0 #define CLOCKS_SAME_SCALING_VALUE 1 // --------------------------------------------------------------------------- // MACROS // --------------------------------------------------------------------------- #define RELEASE_AND_CLEAR(punk) if (punk) { (punk)->Release(); (punk) = NULL; } #define DELETE_RESET(p) { delete (p); (p) = NULL ; } #define DELETE_RESET_COM(p) { CoTaskMemFree (p); (p) = NULL ; } #define CLOSE_RESET_HANDLE(h) if ((h) != NULL) { CloseHandle (h); (h) = NULL ;} #define CLOSE_RESET_REG_KEY(r) if ((r) != NULL) { RegCloseKey (r); (r) = NULL ;} #define GOTO_NE(v,c,l) if ((v) != (c)) { ERROR_SPEW(v,!=,c) ; goto l ; } #define GOTO_EQ(v,c,l) if ((v) == (c)) { ERROR_SPEW(v,==,c) ; goto l ; } #define GOTO_NE_SET(v,c,l,h,r) if ((v) != (c)) { (h) = (r) ; ERROR_SPEW(v,!=,c) ; goto l ; } #define GOTO_EQ_SET(v,c,l,h,r) if ((v) == (c)) { (h) = (r) ; ERROR_SPEW(v,==,c) ; goto l ; } #define DIV_ROUND_UP_MAYBE(num,den) ((num) / (den) + ((num) % (den) ? 1 : 0)) #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define ABS(a) ((a) >= 0 ? (a) : 0 - (a)) #define IN_RANGE(v,min,max) (((min) <= (v)) && ((v) <= (max))) #define NE_ERROR_RET(v,c) ERROR_RET(v,!=,c) #define EQ_ERROR_RET(v,c) ERROR_RET(v,==,c) #define NE_ERROR_RET_VAL(v,c,r) ERROR_RET_VAL(v,!=,c,r) #define EQ_ERROR_RET_VAL(v,c,r) ERROR_RET_VAL(v,==,c,r) #define NE_ERROR_RET_EX(v,c,m) ERROR_RET_EX(v,!=,c,m) #define EQ_ERROR_RET_EX(v,c,m) ERROR_RET_EX(v,==,c,m) #define NE_ERROR_RET_VAL_EX(v,c,r,m) ERROR_RET_VAL_EX(v,!=,c,r,m) #define EQ_ERROR_RET_VAL_EX(v,c,r,m) ERROR_RET_VAL_EX(v,==,c,r,m) // empty if-clauses should be otpimized out in release builds #define NE_SPEW(v,c,m) if ((v) != (c)) ERROR_SPEW_EX(v,!=,c,m) #define EQ_SPEW(v,c,m) if ((v) == (c)) ERROR_SPEW_EX(v,==,c,m) // confirms validity of media sample settings #define VALID_MEDIA_SAMPLE_SETTINGS(batch_size, batch_exact, sample_max_len, sample_pool) \ (((DWORD)(batch_size) <= (DWORD)(sample_pool)) && \ ((sample_max_len) > 0) && \ ((DWORD)(batch_size) <= (DWORD)(sample_pool))) #define MPEG2_DEMUX(pf) (reinterpret_cast (pf)) // --------------------------------------------------------------------------- // clock conversion macros // --------------------------------------------------------------------------- // // The demux deals with 3 clocks: // 1. Program Clock Reference (PCR) // 2. QueryPerformanceCounter (QPC) // 3. DShow REFERENCE_TIMEs // // PCR operates at 27 MHz // // QPC operates at variable rates, depending on the host system. A call to // QueryPerformanceFrequency returns the QPC ticks / second rate. From now // on we will refer to that frequency as QPC_FREQ. // // DShow REFERENCE_TIME increased at a 100 nanosecond granularity. // // 27 MHz = 27 x 10^6 #define PCR_HZ (27000000) // 100 ns / sec = 10 MHz = 10 x 10^6 = 1 x 10^7 #define DSHOW_TIME_HZ (10000000) // 90 KHz = 90 x 10^3 #define PTS_HZ (90000) // PCR ticks / sec #define PCR_TICKS_PER_SECOND PCR_HZ #define DSHOW_TICKS_PER_SECOND DSHOW_TIME_HZ #define DSHOW_TICKS_PER_MILLISECOND (DSHOW_TICKS_PER_SECOND / MILLISECONDS_PER_SECOND) #define PTS_TICKS_PER_SECOND PTS_HZ // 1 x 10^3 #define MILLISECONDS_PER_SECOND (1000) // straigh-forward time-base conversions #define DSHOW_TO_MILLISECONDS(rt) ((rt) / (DSHOW_TICKS_PER_SECOND / MILLISECONDS_PER_SECOND)) #define MILLISECONDS_TO_PTS_TIME_BASE(millis) llMulDiv ((millis), PTS_HZ, MILLISECONDS_PER_SECOND, 0) #define MILLISECONDS_TO_PCR_TIME_BASE(millis) llMulDiv ((millis), PCR_HZ, MILLISECONDS_PER_SECOND, 0) #define SECONDS_TO_DSHOW(sec) ((REFERENCE_TIME) (((REFERENCE_TIME) (sec)) * DSHOW_TICKS_PER_SECOND)) // --------------------------------------------------------------------------- // MPEG2 - related constants & macros // --------------------------------------------------------------------------- #include "mp2const.h" #include "parsemac.h" // --------------------------------------------------------------------------- // demux-wide // --------------------------------------------------------------------------- #include "trace.h" #include "demxutil.h" // --------------------------------------------------------------------------- // stream types handled by the demux enum { MPEG2_STREAM_UNDEFINED = 0, MPEG2_STREAM_TRANSPORT = 1, MPEG2_STREAM_PROGRAM = 2 } ; /*++ The purpose of this data structure is to reference an MPEG2 Systems buffer, regardless of the specific type (program or transport). It is used by the mapper to pass a reference to each parser. The parsers all understand this data structure. --*/ struct MPEG2_SYS_BUFFER { BYTE * pbSysBuffer ; // points to the start of sys packet int iSysBufferLength ; // length of sys packet BYTE * pbSysBufferPayload ; // points to the sys packet payload, following header int iSysBufferPayloadLength ; // length of payload } ; // --------------------------------------------------------------------------- // class & struct forward declarations struct MPEG2_TRANSPORT_HEADER ; struct MPEG2_TRANSPORT_PACKET ; struct SINGULAR_STREAM ; struct SECTION_BUFFER ; struct PARSER_REF ; struct PCR_RECORD ; struct MPEG2_TRANSPORT_CLOCK_SUBORDINATE_STATS ; struct MPEG2_TRANSPORT_TIMESTAMP_STATS ; struct MPEG2_TRANSPORT_TIME_STATS ; struct MPEG2_TRANSPORT_STATS_GLOBAL ; struct MPEG2_TRANSPORT_STATS_PID ; struct MPEG2_TRANSPORT_STATS_GLOBAL_AND_PID ; class CMPEG2Demultiplexer ; class CBufferSource ; class CMediaSampleWrapperPool ; class CMediaSampleCopyBuffer ; class CMediaSampleWrapper ; class CMediaSampleWrapperPool ; class CMPEG2PushClock ; class CMonotonicClock ; class CStreamMonotonicClock ; class CDataCache ; class CRefCountedCritSec ; class CDShowMPEG2Demux ; class CEnumStreamMapBase ; class CMPEG2DemuxInputPin ; class CStreamPull ; class CMPEG2DemuxOutputPin ; class CDemuxBaseParser ; class CBufferSourceManager ; class CStreamParser ; class CCopyFrameParser ; class CMpeg2PESStreamParser ; class CMpeg2TSPassThroughParser ; class CMpeg2PSIParse ; class CMpeg2NonVersionedPSIParse ; class CMpeg2VersionFilteredPSIParse ; class CMpeg2PATSectionParser ; class CMpeg2PMTSectionParser ; class CMpeg2PCRParser ; class CMpeg2GenericTSPayload ; class CTSContentManager ; class CTSProgram ; class CIPTSConvert ; class CMPEG2PSISectionBufferSource ; class CISectionEventCallback ; class CMPEG2Controller ; class CPCRValue ; class CPCRRecordBufferSource ; class CMPEG2PushClock ; class CIPCRValueNotify ; class CMPEG2PropOutputPins ; class CScratchMediaSample ; class CMpeg2PropStreamMap ; class CMPEG2PropPIDMap ; class CMPEG2PropStreamIdMap ; class CStreamToPinMap ; class CMPEG2Controller ; class CMPEG2TransportController ; class CMPEG2ProgramController ; class CMpeg2StreamContentManager ; class CStreamMapper ; class CTransportStreamMapper ; class CProgramStreamMapper ; class CStreamMapContext ; class CTransportStreamMapContext ; class CProgramStreamMapContext ; class CMpeg2SharedMem ; class CMpeg2TransportStatsCOM ; class CMpeg2ProgramStatsCOM ; class CMpeg2StatsCOM ; class CMpeg2Stats ; class CControlBase ; class CEditControl ; class CCombobox ; class CListview ; class CMpeg2ProgStreamSniffer ; class CMpeg2StreamAnalyzer ; class CMpeg2ProgramStreamAnalyzer ; class CMpeg2DemuxMediaSeekingCore ; class CMpeg2DemuxMediaSeekingCOM ; class CIInputStreamEvent ; #endif // _mp2demux__precomp_h