{\rtf1\ansi\ansicpg1252\deff0\deflang1033\deflangfe1033{\fonttbl{\f0\fswiss\fprq2\fcharset0 Arial;}} \viewkind4\uc1\pard\nowidctlpar\f0\fs28 Base Class for Fixed Bitrate Content, 1-input 1-output DMOs\fs20\par \par Purpose: many streaming issues, such as discontinuities, timestamps, and incomplete flags, can be handled completely by the base class if the following assumptions are made:\par \par - input and output data can each be considered a series of fixed-sized, byte-granular samples;\par - sample sizes can be derived from mediatypes and never change while streaming;\par - the size of the timestamp range that a given sample of data spans is the same for every input/output samples;\par - there is a known upper bound on lookahead/lookbehind.\par \par With these assumtions, the following interface between the base class and a derived class is possible. This interface is simpler than both the IMediaObject interface and our existing base class interface.\par \par Before streaming starts (but after both mediatypes have been set), the base class calls the following method implemented by the derived class:\par \par \tab HRESULT \b GetStreamingParams\b0 (\par \tab\tab DWORD *\b pdwInputSampleSize\b0 , // in bytes\par \tab\tab DWORD *\b pdwOutputSampleSize\b0 , // in bytes\par \tab\tab DWORD *\b pdwMaxLookahead\b0 , // in input samples, 0 means no lookahead\par \tab\tab DWORD *\b pdwMaxLookbehind\b0 , // in input samples, 0 means no lookbehind\par \tab\tab REFERENCE_TIME *\b prtSampleDuration\b0 , // same for input and output samples\par \tab\tab REFERENCE_TIME *\b prtDurationDenominator\b0 // optional, normally 1\par \tab );\par \par The purpose of \b prtDurationDenominator\b0 is to allow precise values of sample duration when it is not a whole number of REFERENCE_TIME units (e.g., 10000000 / 44100 should be expressed as 100000 / 441 rather than 227 / 1). This is to prevent timestamp round-off errors from accumulating over time in the base class.\par \par After streaming starts, the base class first accumulates at least ((lookahead + lookbehind + 1) times *pdwInputSampleSize) bytes of input data to ensure adequate lookahead/lookbehind. Only then does the base class start calling Process:\par \par \tab HRESULT \b FBRProcess\b0 ( // "Fixed Bitrate Process"\par \tab\tab DWORD \b cSamplesToProcess\b0 ,\par \tab\tab BYTE *\b pbInput\b0 , // points to \b cSamplesToProcess\b0 input samples plus lookahead/lookbehind\par \tab\tab BYTE *\b pbOutput\b0 // points to room for \b cSamplesToProcess\b0 output samples\par \tab );\par \par To ensure that the algorithm has sufficient lookahead/lookbehind, the base class takes a buffer of \b (lookbehind + cSamplesToProcess + lookahead)\b0 input samples and sets the \b pbInput\b0 pointer points to the \b (lookbehind + 1)th \b0 input sample. This way for any of the cSamplesToProcess samples in the current input range, FBRProcess() is allowed to dereference samples in the input buffer up to lookahead positions ahead of the current sample and up to lookbehind positions back from the current sample, even if the current sample is at the very beginning or at the very end of the input range. The base class makes there is valid data there.\par \par For the purposes of computing output timestamps, the base class assumes that the first output sample in the output buffer corresponds in time to the input sample pointed to by pbInput.\par \par Input buffers overlap by (lookahead + lookbehind) samples. I.e., if either lookahead or lookbehind is non-zero, FBRProcess() will see some input samples more than once. Thus FBRProcess itself does not need to remember any past input.\par \par Output buffers are always adjacent in time and do not overlap from one FBRProcess call to the next. Thus if FBRProcess needs previous output samples to compute the current one (e.g., an IIR audio filter), it must store them internally.\par \par Processing efficiency increases with the number of output samples produced during each Process call, especially for objects that use lookahead or lookbehind. Therefore the base class will attempt to invoke FBRProcess on as many output samples at a time as practical.\par \par \b Mediatype negotiation\b0 with this base class happens in much the same way as with the IMediaObject interface, except the function prototypes are slightly simpler due to the 1-input/1-output restriction, and the GetXXXType (code layering) methods are handled by the base class.\par \par Methods implemented by the derived class and called by the base class:\par \par \tab // enumeration\par \tab HRESULT GetInputType(DWORD dwTypeIndex, DMO_MEDIA_TYPE *pmt);\par \tab HRESULT GetOutputType(DWORD dwTypeIndex, DMO_MEDIA_TYPE *pmt);\par \par \tab // verification\par \tab HRESULT CheckInputType(const DMO_MEDIA_TYPE *pmt);\par \tab HRESULT CheckOutputType(const DMO_MEDIA_TYPE *pmt);\par \par Methods implemented by the base class and called by the derived class:\par \par \tab DMO_MEDIA_TYPE *InputType();\par \tab DMO_MEDIA_TYPE *OutputType();\par \par When a type is set, the base class stores the type on behalf of the DMO. The derived class accesses the currently set types by calling InputType() and OutputType(). Each returns NULL if the type has not been set. GetInputType() may be called from CheckOutputType() and vice versa if the object has input/output type dependencies.\par \par \b Other streaming methods\b0 : the base class provides the following overridables:\par \par virtual HRESULT Init() = 0;\par virtual HRESULT Discontinuity() = 0;\par \par \b Init()\b0 is intended as a hook to allow the derived class to initialize itself prior to streaming. Init() is guaranteed to be called at least once before streaming starts. However, \i Init() may be called more than once\i0 , so the derived class should check if it has already been initialized before performing any resource allocation.\par \par There is no corresponding Uninit method. The derived class should perform clean up / free resources inside its destructor.\par \par \b Discontinuity()\b0 is called whenever the next buffer of input data is logically unrelated to the previous one. This can happen due to a source change, dropped data, etc. The derived class should reset any running streaming parameters inside this method. Discontinuity() is guaranteed to be called at least once before streaming starts.\par \par }