home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / mpgvideo.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-19  |  61.0 KB  |  2,169 lines

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (c) 1992 - 1996  Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. /******************************Module*Header*******************************\
  13. * Module Name: MpgVideo.cpp
  14. *
  15. * Implements a prototype Mpeg Video Software codec.  It just consumes
  16. * the passed in packets.
  17. *
  18. \**************************************************************************/
  19. #include "MpgVideo.h"
  20.  
  21. // define the GUIDs for streams and my CLSID in this file
  22. #include <initguid.h>
  23. #include "mpegUids.h"
  24. #include "palette.h"
  25.  
  26.  
  27. // setup data
  28.  
  29. AMOVIESETUP_MEDIATYPE psudIpPinTypes[] = { { &MEDIATYPE_Video                // clsMajorType
  30.                                            , &MEDIASUBTYPE_MPEG1Packet  }    // clsMinorType
  31.                                          , { &MEDIATYPE_Video                // clsMajorType
  32.                                            , &MEDIASUBTYPE_MPEG1Payload } }; // clsMinorType
  33.  
  34. AMOVIESETUP_MEDIATYPE sudOpPinTypes = { &MEDIATYPE_Video      // clsMajorType
  35.                                       , &MEDIASUBTYPE_NULL }; // clsMinorType
  36.  
  37. AMOVIESETUP_PIN psudPins[] = { { L"Input"            // strName
  38.                                , FALSE               // bRendered
  39.                                , FALSE               // bOutput
  40.                                , FALSE               // bZero
  41.                                , FALSE               // bMany
  42.                                , &CLSID_NULL         // clsConnectsToFilter
  43.                                , L"Output"           // strConnectsToPin
  44.                                , 2                   // nTypes
  45.                                , psudIpPinTypes }    // lpTypes
  46.                              , { L"Output"           // strName
  47.                                , FALSE               // bRendered
  48.                                , TRUE                // bOutput
  49.                                , FALSE               // bZero
  50.                                , FALSE               // bMany
  51.                                , &CLSID_NULL         // clsConnectsToFilter
  52.                                , L"Input"            // strConnectsToPin
  53.                                , 1                   // nTypes
  54.                                , &sudOpPinTypes } }; // lpTypes
  55.  
  56.  
  57.  
  58. AMOVIESETUP_FILTER sudMPEGVideo = { &CLSID_CMpegFrameworkVideoCodec // clsID
  59.                                   , L"MPEG Framework Audio Codec"   // strName
  60.                                   , 0x00600000                      // dwMerit
  61.                                   , 2                               // nPins
  62.                                   , psudPins };                     // lpPin
  63.  
  64. /* -------------------------------------------------------------------------
  65. ** list of class ids and creator functions for class factory
  66. ** -------------------------------------------------------------------------
  67. */
  68. CFactoryTemplate g_Templates[] =
  69. {
  70.     {L"MPEG Framework Video Codec", &CLSID_CMpegFrameworkVideoCodec, CMpegVideoCodec::CreateInstance, NULL}
  71. };
  72.  
  73. int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
  74.  
  75.  
  76. /* -------------------------------------------------------------------------
  77. ** CMpegVideoCodec
  78. ** -------------------------------------------------------------------------
  79. */
  80. CMpegVideoCodec::CMpegVideoCodec(
  81.     TCHAR *pName,
  82.     LPUNKNOWN pUnk,
  83.     HRESULT *phr
  84.     )
  85.     : CTransformFilter(pName, pUnk, CLSID_CMpegVideoCodec, phr),
  86.       m_pVideoDecoder(NULL),
  87.       m_PtsQueue(NAME("Pts queue"), 30, FALSE, FALSE),
  88.       m_pFrameBuff(NULL),
  89.       m_Buffer(NULL),
  90.       m_pOutSample(NULL)
  91. {
  92.     //
  93.     // Pick up any user preferences - this should get moved to the register
  94.     //
  95.     m_IgnoreQualityMessage = GetProfileInt(TEXT("Quartz"),
  96.                                            TEXT("IgnoreQMessages"), FALSE);
  97.  
  98.     m_dwCtrlDefault = GetProfileInt(TEXT("Quartz"),
  99.                                     TEXT("VideoFramesDecoded"), DECODE_IPB);
  100.     m_dwCtrlDefault &= 0x3F;
  101.     m_dwQualDefault = GetProfileInt(TEXT("Quartz"),
  102.                                     TEXT("VideoQuality"), 0);
  103.     m_dwQualDefault &= 0x30000000;
  104.     m_dwCtrl = (m_dwCtrlDefault | m_dwQualDefault);
  105.  
  106.  
  107.     if (GetProfileInt(TEXT("Quartz"), TEXT("GreyScale"), 0)) {
  108.         m_PaletteType = GREY_PALETTE;
  109.         m_dwOutputFormatDib = MM_Y_DIB;
  110.         m_dwOutputFormatDdb = MM_Y_DDB;
  111.     }
  112.     else {
  113.         m_PaletteType = COLOUR_PALETTE;
  114.         m_dwOutputFormatDib = MM_RGB8_DIB;
  115.         m_dwOutputFormatDdb = MM_RGB8_DDB;
  116.     }
  117.  
  118.     //
  119.     // Reset frame stats
  120.     //
  121.     ZeroMemory(m_dwFramesSkipped, sizeof(m_dwFramesSkipped));
  122.     ZeroMemory(m_dwFramesDecoded, sizeof(m_dwFramesDecoded));
  123.  
  124.     m_PerfDecode = MSR_REGISTER(TEXT("Decode Time  - Start/Stop"));
  125.     m_QualMsg = MSR_REGISTER(TEXT("Quality Message"));
  126.     m_FrameDrawn = MSR_REGISTER(TEXT("Frame Drawn"));
  127.     m_FrameType = MSR_REGISTER(TEXT("Frame Type"));
  128. }
  129.  
  130. /******************************Public*Routine******************************\
  131. * GetSetupData
  132. *
  133. *
  134. *
  135. * History:
  136. *
  137. \**************************************************************************/
  138. LPAMOVIESETUP_FILTER
  139. CMpegVideoCodec::GetSetupData()
  140. {
  141.   return &sudMPEGVideo;
  142. }
  143.  
  144.  
  145. CMpegVideoCodec::~CMpegVideoCodec(
  146.     )
  147. {
  148.     CTimePosition   *pTimePos;
  149.  
  150.     DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::~CMpegVideoCodec")));
  151.  
  152.     delete m_pVideoDecoder;
  153.     m_pVideoDecoder = NULL;
  154.  
  155.     delete [] m_pFrameBuff;
  156.     m_pFrameBuff = NULL;
  157.  
  158.     delete [] m_Buffer;
  159.     m_Buffer = NULL;
  160.  
  161.  
  162.     //
  163.     // Purge the PTS queue.
  164.     //
  165.     while( (pTimePos = m_PtsQueue.RemoveHead()) != NULL) {
  166.         delete pTimePos;
  167.     }
  168.  
  169.     //
  170.     // This should have been deleted in BreakConnect
  171.     //
  172.     ASSERT(m_Buffer == NULL);
  173. }
  174.  
  175.  
  176.  
  177. /******************************Public*Routine******************************\
  178. * CreateInstance
  179. *
  180. * This goes in the factory template table to create new instances
  181. *
  182. \**************************************************************************/
  183. CUnknown *
  184. CMpegVideoCodec::CreateInstance(
  185.     LPUNKNOWN pUnk,
  186.     HRESULT * phr
  187.     )
  188. {
  189.     DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::CreateInstance")));
  190.     return new CMpegVideoCodec(TEXT("MPEG Video codec filter"), pUnk, phr);
  191. }
  192.  
  193.  
  194. /******************************Public*Routine******************************\
  195. * NonDelegatingQueryInterface
  196. *
  197. * Here we would reveal ISpecifyPropertyPages and IMpegVideoDecoder if
  198. * the framework had a property page.
  199. *
  200. \**************************************************************************/
  201. STDMETHODIMP
  202. CMpegVideoCodec::NonDelegatingQueryInterface(
  203.     REFIID riid,
  204.     void ** ppv
  205.     )
  206. {
  207.     return CTransformFilter::NonDelegatingQueryInterface(riid, ppv);
  208. }
  209.  
  210.  
  211. /******************************Public*Routine******************************\
  212. * EndOfStream
  213. *
  214. *
  215. *
  216. \**************************************************************************/
  217. HRESULT
  218. CMpegVideoCodec::EndOfStream()
  219. {
  220.     DbgLog((LOG_TRACE, 2, TEXT("End of stream called")));
  221.     CAutoLock lck(&m_csReceive);
  222.  
  223.     if (m_pVideoDecoder == NULL) {
  224.         return VFW_E_WRONG_STATE;
  225.     }
  226.  
  227.     DecodeUntilBufferEmpty();
  228.     ResetVideoDecoder();
  229.     return CTransformFilter::EndOfStream();
  230. }
  231.  
  232.  
  233. /******************************Public*Routine******************************\
  234. * EndFlush
  235. *
  236. *
  237. *
  238. \**************************************************************************/
  239. HRESULT
  240. CMpegVideoCodec::EndFlush()
  241. {
  242.     DbgLog((LOG_TRACE, 2, TEXT("End flush called")));
  243.     CAutoLock lck(&m_csReceive);
  244.     ResetVideoDecoder();
  245.     return CTransformFilter::EndFlush();
  246. }
  247.  
  248.  
  249. /******************************Public*Routine******************************\
  250. * Receive
  251. *
  252. * Copy the input sample into our buffer.  Loop while the buffer size is
  253. * greater than or equal to the size given in the Vbv for the next picture
  254. * decode the picture and pass it along to the output pin for rendering.
  255. *
  256. \**************************************************************************/
  257. HRESULT
  258. CMpegVideoCodec::Receive(
  259.     IMediaSample *pSample
  260.     )
  261. {
  262.     //
  263.     //  Make sure the pin doesn't go inactive on us
  264.     //
  265.  
  266.     HRESULT   hr;
  267.     CAutoLock lck(&m_csReceive);
  268.  
  269.     if (m_pVideoDecoder == NULL || m_pFrameBuff == NULL) {
  270.         return E_UNEXPECTED;
  271.     }
  272.  
  273.     //
  274.     // Check for a discontinuity, if one is found decode and display any
  275.     // frames left in the circular buffer, reset the decoder and then continue
  276.     // processing the current sample.
  277.     //
  278.     if (pSample->IsDiscontinuity() == S_OK) {
  279.  
  280.         DecodeUntilBufferEmpty();
  281.         ResetVideoDecoder();
  282.  
  283.         //
  284.         //  Find out what the current stop time is...
  285.         //  ... get logical duration from upstream
  286.         //
  287.         HRESULT hrPos;
  288.         REFTIME dStart, dStop;
  289.         IMediaPosition *pPosition = NULL;
  290.  
  291.         hrPos = m_pInput->GetConnected()->QueryInterface(IID_IMediaPosition,
  292.                                                          (void **)&pPosition);
  293.  
  294.         if ( SUCCEEDED(hrPos)
  295.           && pPosition != NULL
  296.           && SUCCEEDED(pPosition->get_CurrentPosition(&dStart))
  297.           && SUCCEEDED(pPosition->get_StopTime(&dStop)))
  298.         {
  299.             m_tStop =
  300.                 (CRefTime)(COARefTime)dStop - (CRefTime)(COARefTime)dStart;
  301.         }
  302.         else {
  303.             m_tStop = 0x7FFFFFFFFFFFFFFF;
  304.         }
  305.  
  306.         if (pPosition != NULL) {
  307.             pPosition->Release();
  308.         }
  309.  
  310.         DbgLog((LOG_TRACE, 2,
  311.                 TEXT("Receive() : Discontinuity - setting stop time to %s"),
  312.                 (LPCTSTR)CDisp(m_tStop)));
  313.     }
  314.  
  315.     m_pSample = NULL;
  316.     m_LenLeftInPacket = 0L;
  317.  
  318.     //
  319.     // If this sample is a sync point we need to
  320.     // update our clock and reset the count of
  321.     // samples received since the last sync point.
  322.     //
  323.  
  324.     if (pSample->IsSyncPoint() == S_OK) {
  325.  
  326.         CRefTime        tStart, tStop;
  327.         CTimePosition   *pTimePos;
  328.  
  329.         pSample->GetTime((REFERENCE_TIME*)&tStart,
  330.                          (REFERENCE_TIME*)&tStop);
  331.  
  332.         pTimePos = new CTimePosition(&tStart,
  333.                                      m_BufferCurr + m_BufferFullness >= m_BufferStart + m_VBlockSize ?
  334.                                      m_BufferCurr + m_BufferFullness - m_VBlockSize : m_BufferCurr + m_BufferFullness);
  335.  
  336.         DbgLog(( LOG_TRACE, 4, TEXT("PTS: %s  Buffer pos: %ld"),
  337.                  (LPCTSTR)CDisp(tStart), m_BufferCurr + m_BufferFullness ));
  338.         m_PtsQueue.AddTail(pTimePos);
  339.  
  340.     }
  341.  
  342.     //
  343.     // Decode and if necessary display as many frames as
  344.     // possible until we exhaust our circular buffer.
  345.     //
  346.  
  347.     do {
  348.  
  349.         hr = CopySampleToBuffer(pSample);
  350.  
  351.         while (SUCCEEDED(hr) && (m_BufferFullness >= m_seqInfo.lvbv)) {
  352.  
  353.             hr = DecodeNextPicture();
  354.         }
  355.  
  356.     } while (S_OK == hr && (m_LenLeftInPacket != 0L));
  357.  
  358.     return hr;
  359. }
  360.  
  361.  
  362. /*****************************Private*Routine******************************\
  363. * ResetVideoDecoder
  364. *
  365. *
  366. *
  367. \**************************************************************************/
  368. void
  369. CMpegVideoCodec::ResetVideoDecoder()
  370. {
  371.     //
  372.     // Make him eat our sequence header
  373.     //
  374.     // m_BufferStart = m_BufferCurr = m_Buffer->GetPointer();
  375.     m_BufferStart = m_BufferCurr = m_Buffer;
  376.     m_BufferFullness = m_seqInfo.lActualHeaderLen;
  377.  
  378.     CopyMemory(m_BufferStart, m_seqInfo.RawHeader, m_seqInfo.lActualHeaderLen);
  379.  
  380.     m_TimeSinceLastSyncPoint = 0L;
  381.     m_pOutSample = NULL;
  382.  
  383.     //
  384.     // Don't play anything until we get a sync point
  385.     // but don't make it too negative or we'll overflow!
  386.     //
  387.     m_TimeAtLastSyncPoint = (LONGLONG)-0x7FFFFFFFFFFFFF;
  388.     m_tStopPrev = m_TimeAtLastSyncPoint;
  389.  
  390.     m_pVideoDecoder->ResetVideo();
  391.  
  392.  
  393.     //
  394.     // Purge the PTS queue.
  395.     //
  396.     CTimePosition *pTimePos;
  397.     while( (pTimePos = m_PtsQueue.RemoveHead()) != NULL) {
  398.         delete pTimePos;
  399.     }
  400.  
  401.  
  402.     //
  403.     // Reset IP tracking
  404.     //
  405.     m_NextIP.Reset();
  406.  
  407. }
  408.  
  409.  
  410. /*****************************Private*Routine******************************\
  411. * DecodeUntilBufferEmpty
  412. *
  413. *
  414. *
  415. \**************************************************************************/
  416. void
  417. CMpegVideoCodec::DecodeUntilBufferEmpty()
  418. {
  419.     HRESULT hr = S_OK;
  420.  
  421.     while (SUCCEEDED(hr) && (m_BufferFullness > 0)) {
  422.  
  423.         LPBYTE pCurrentCurr = m_BufferCurr;
  424.  
  425.         DbgLog((LOG_TRACE, 3, TEXT("Forcing out a frame")));
  426.         hr = DecodeNextPicture();
  427.  
  428.         if (S_OK != hr || m_BufferCurr == pCurrentCurr) {
  429.  
  430.             //
  431.             // We're not making any progress!
  432.             //
  433.             DbgLog((LOG_ERROR, 2,
  434.                     TEXT("CMpegVideoCodec::DecodeUntilBufferEmpty() ")
  435.                     TEXT("- Stuck with %d bytes in buffer"),
  436.                     m_BufferFullness));
  437.             break;
  438.         }
  439.     }
  440.  
  441.     //
  442.     // Now see if there's a frame decoded but not presented
  443.     //
  444.     if (m_NextIP.TimeToDraw()) {
  445.  
  446.         DbgLog((LOG_TRACE, 2, TEXT("Trying to get last frame")));
  447.  
  448.         DWORD dwCtrl = m_dwCtrl;
  449.         m_dwCtrl &= 0xFFFF0000;
  450.         m_dwCtrl |= DECODE_DIS;
  451.  
  452.         if (S_OK != DecodeNextPicture()) {
  453.             DbgLog((LOG_ERROR, 2, TEXT("Failed to display last frame")));
  454.         }
  455.  
  456.         m_dwCtrl = dwCtrl; // Restore
  457.     }
  458. }
  459.  
  460.  
  461. /*****************************Private*Routine******************************\
  462. * GetDecodeBufferAndFormat
  463. *
  464. * This function is called by the mpeg decoder when it is time to determine
  465. * the colour conversion format and the destination buffer pointer for the
  466. * frame.
  467. *
  468. \**************************************************************************/
  469. LPBYTE
  470. CMpegVideoCodec::GetDecodeBufferAndFormat()
  471. {
  472.     unsigned char   *pDst;
  473.     AM_MEDIA_TYPE      *pmt;
  474.     CRefTime        tStartTime(m_tStopPrev);
  475.     CRefTime        tStopTime;
  476.  
  477.     // Don't ask for a buffer with a negative start time.
  478.     if (tStartTime < (LONGLONG)0) {
  479.         tStartTime = (LONGLONG)0;
  480.     }
  481.  
  482.     //
  483.     // this may block for an indeterminate amount of time
  484.     //
  485.     tStopTime = tStartTime + m_seqInfo.tPictureTime;
  486.     hrCallback = m_pOutput->GetDeliveryBuffer(&m_pOutSample,
  487.                                               (REFERENCE_TIME*)&tStartTime,
  488.                                               (REFERENCE_TIME*)&tStopTime,
  489.                                               0 // Must set proper flag
  490.                                                 // if prev frame skipped
  491.                                               );
  492.     if (FAILED(hrCallback)) {
  493.         return NULL;
  494.     }
  495.     ASSERT(m_pOutSample);
  496.  
  497.     hrCallback = m_pOutSample->GetPointer(&pDst);
  498.     if (FAILED(hrCallback)) {
  499.         return NULL;
  500.     }
  501.     ASSERT(pDst);
  502.  
  503.     //
  504.     // If the media type has changed then pmt is NOT NULL
  505.     //
  506.     m_pOutSample->GetMediaType(&pmt);
  507.     if (pmt != NULL) {
  508.         CMediaType cmt(*pmt);
  509.         DeleteMediaType(pmt);
  510.         SetOutputPinMediaType(&cmt);
  511.     }
  512.     return pDst;
  513. }
  514.  
  515.  
  516. /*****************************Private*Routine******************************\
  517. * DecodeNextPicture
  518. *
  519. * Decodes the next picture stored in the circular buffer.  If the picture
  520. * is not "skipped" it is passed to the output pin.  Updates m_BufferStart,
  521. * m_BufferCurr and m_BufferFullness to reflect any emptying of the buffer that
  522. * has taken place.
  523. *
  524. \**************************************************************************/
  525. HRESULT
  526. CMpegVideoCodec::DecodeNextPicture()
  527. {
  528.     DWORD   rc;
  529.     HRESULT hr = S_OK;
  530.  
  531.     //
  532.     // ParthaSr.
  533.     // trying to recover from the absence of quality messages
  534.     // when I do a skip - so I am predictively skipping
  535.     // frames.  - Snap back to default if I have already
  536.     // skipped enough frames
  537.     //
  538.     if (m_dwLateBy < 750000L) {
  539.         m_dwCtrl = m_dwCtrlDefault | m_dwQualDefault;
  540.     }
  541.  
  542.     m_VideoControl.dwCtrl = m_dwCtrl;
  543.  
  544.     //
  545.     // If we're within 1 second of the end do all IP
  546.     //
  547.     if (m_tStop - m_tStopPrev < CRefTime(1000L)) {
  548.  
  549.         //
  550.         // But are we almost at the end? in which case we need to decode
  551.         // everything
  552.         //
  553.         if (m_tStop - m_tStopPrev < CRefTime(m_seqInfo.tPictureTime) +
  554.                                     CRefTime(m_seqInfo.tPictureTime)) {
  555.  
  556.             if ((m_dwCtrl & 0xFFFF) != DECODE_DIS) {
  557.                 m_VideoControl.dwCtrl = (m_dwCtrl & 0xFFFF0000) | DECODE_IPB;
  558.             }
  559.         }
  560.         else {
  561.  
  562.             if ((m_dwCtrl & 0xFFFF) < DECODE_IP) {
  563.                 m_VideoControl.dwCtrl = (m_dwCtrl & 0xFFFF0000) | DECODE_IP;
  564.             }
  565.         }
  566.     }
  567.     else {
  568.  
  569.         //
  570.         // Only do IP if we're before the start
  571.         //
  572.         if ((m_dwCtrl & 0x3F) > DECODE_IP) {
  573.  
  574.             if (m_tStopPrev
  575.               + CRefTime(m_seqInfo.tPictureTime)
  576.               + CRefTime(m_seqInfo.tPictureTime) < CRefTime(0L)) {
  577.  
  578.                 m_VideoControl.dwCtrl = (m_dwCtrl & 0xFFFF0000) | DECODE_IP;
  579.             }
  580.  
  581.         }
  582.     }
  583.     DbgLog((LOG_TRACE, 4, TEXT("Decode flags = %X"), m_VideoControl.dwCtrl));
  584.  
  585.  
  586.     //
  587.     // Initialize the video codec with the new video data buffer.  I am
  588.     // assuming that there is at least one video frame in the data
  589.     // buffer.  When this function gets called to force out the frames
  590.     // left in the buffer it needs to guarded with a try except block.
  591.     //
  592.     m_VideoControl.pCmprWrite  = m_BufferCurr + m_BufferFullness;
  593.     m_VideoControl.pCmprRead   = m_BufferCurr;
  594.  
  595.     //
  596.     // This is where the action starts, call the codec and let it do it stuff.
  597.     //
  598.  
  599.     //  Don't die if Windows NT takes away the DCI surface
  600.     try {
  601.  
  602.         MSR_START(m_PerfDecode);
  603.         rc = m_pVideoDecoder->DecodeFrame(&m_VideoControl);
  604.         MSR_STOP(m_PerfDecode);
  605.     }
  606.     except(EXCEPTION_EXECUTE_HANDLER) {
  607.  
  608.         DbgLog((LOG_ERROR, 1, TEXT("Exception in decoder!")));
  609.         rc = DECODE_ERR_DATA;
  610.     }
  611.  
  612.     //
  613.     // Did the frame decode OK
  614.     //
  615.  
  616.     if (rc == DECODE_SUCCESS) {
  617.  
  618. #ifdef DEBUG
  619.         static char *ft[4] = { "Dummy", "I", "P", "B" };
  620. #endif
  621.  
  622.         //
  623.         // Record frames stats
  624.         //
  625.         MSR_INTEGER(m_FrameType, m_VideoControl.dwFrameType);
  626.         if (m_VideoControl.dwSkipFlag) {
  627.  
  628.             DbgLog((LOG_TRACE, 2, TEXT("%hs Frame skipped"),
  629.                     ft[m_VideoControl.dwFrameType]));
  630.  
  631.             m_dwFramesSkipped[m_VideoControl.dwFrameType]++;
  632.  
  633.             LARGE_INTEGER li;
  634.             li.QuadPart = m_seqInfo.tPictureTime;
  635.             if (m_dwLateBy > li.LowPart) {
  636.                 m_dwLateBy -= li.LowPart;
  637.             }
  638.         }
  639.         else {
  640.             m_dwFramesDecoded[m_VideoControl.dwFrameType]++;
  641.         }
  642.  
  643.         if (m_VideoControl.dwFrameType == FTYPE_I ||
  644.             m_VideoControl.dwFrameType == FTYPE_P) {
  645.  
  646.             //
  647.             //  Do I/P - we're actually going to draw the I/P we
  648.             //  decoded last time we got one, not the present one
  649.             //
  650.  
  651.             if (m_NextIP.GetTime((REFERENCE_TIME *)&m_TimeAtLastSyncPoint)) {
  652.                 m_TimeSinceLastSyncPoint = 0;
  653.             }
  654.  
  655.             REFERENCE_TIME t;
  656.             BOOL bIFrame = m_VideoControl.dwFrameType == FTYPE_I;
  657.  
  658.             if (UpdateTimeSyncPoint(m_VideoControl.pFrameStartPos, &t)) {
  659.                 m_NextIP.Set(m_VideoControl.dwSkipFlag, bIFrame,
  660.                              TRUE, t, m_VideoControl.dwTemporalReference);
  661.             }
  662.             else {
  663.                 m_NextIP.Set(m_VideoControl.dwSkipFlag, bIFrame,
  664.                              FALSE, t, m_VideoControl.dwTemporalReference);
  665.             }
  666.         }
  667.         else {
  668.  
  669.             //
  670.             //  Do B
  671.             //
  672.             m_NextIP.NextRef(m_VideoControl.dwTemporalReference);
  673.             if ( UpdateTimeSyncPoint(m_VideoControl.pFrameStartPos,
  674.                                      (REFERENCE_TIME*)&m_TimeAtLastSyncPoint) ) {
  675.                 m_TimeSinceLastSyncPoint = 0;
  676.             }
  677.         }
  678.  
  679.         CRefTime tStop(m_TimeAtLastSyncPoint + m_TimeSinceLastSyncPoint +
  680.                        m_seqInfo.tPictureTime);
  681.  
  682.         if (!m_VideoControl.dwSkipFlag) {
  683.  
  684.             LPBITMAPINFOHEADER  lpbiDst = HEADER(m_pOutput->CurrentMediaType().Format());
  685.  
  686.             //
  687.             // if the time is < 0, then this is preroll to get from keyframe to
  688.             // the current frame. We decompress it into the output buffer but
  689.             // don't deliver it.
  690.             //
  691.             // In order that there are no gaps we actually start the next
  692.             // frame where we predicted it would start, rather than the
  693.             // actual synch point
  694.             //
  695.  
  696.             CRefTime tStart(m_tStopPrev);
  697.  
  698.             DbgLog((LOG_TRACE, 2,
  699.                     TEXT("%hs Frame decoded - tStart = %s, tStop = %s"),
  700.                     ft[m_VideoControl.dwFrameType],
  701.                     (LPCTSTR)CDisp(tStart), (LPCTSTR)CDisp(tStop)));
  702.  
  703.  
  704.             #pragma message (REMIND("Do Preroll right"))
  705.             if (tStop > 0L && tStart <= m_tStop) {
  706.  
  707.                 // decompressed frames are always key
  708.                 m_pOutSample->SetSyncPoint(TRUE);
  709.                 m_pOutSample->SetActualDataLength(lpbiDst->biSizeImage);
  710.                 m_pOutSample->SetTime((REFERENCE_TIME*)&tStart,
  711.                                       (REFERENCE_TIME*)&tStop);
  712.  
  713.                 DbgLog((LOG_TRACE, 2, TEXT("%hs Frame sent to next filter"),
  714.                         ft[m_VideoControl.dwFrameType]));
  715.  
  716.  
  717.                 hr = m_pOutput->Deliver(m_pOutSample);
  718.                 MSR_NOTE(m_FrameDrawn);
  719.             }
  720.         }
  721.  
  722.         //
  723.         // We have successfully decoded a frame.
  724.         // Set the new position
  725.         //
  726.         m_tStopPrev = tStop;
  727.         UpdateBufferPosition(m_VideoControl.pCmprRead);
  728.         m_TimeSinceLastSyncPoint += m_seqInfo.tPictureTime;
  729.     }
  730.     else if (rc == DECODE_ERR_QUARTZ) {
  731.  
  732.         DbgLog((LOG_ERROR, 2,
  733.                 TEXT("Could not get buffer from down stream filter")));
  734.         hr = hrCallback;
  735.     }
  736.     else if (rc == DECODE_ERR_DATA) {
  737.  
  738.         //
  739.         // We did not have enough data available to decode the
  740.         // current frame, so save the data for next time.
  741.         //
  742.         // Since this can only happen at a discontinuity, end of
  743.         // stream or undecipherable data we'll just throw the data
  744.         // away if it can't be eaten
  745.         DbgLog((LOG_ERROR, 2, TEXT("Buffer underflow") ));
  746.  
  747.         UpdateBufferPosition(m_VideoControl.pCmprRead);
  748.  
  749.         //
  750.         //  Notify the filter graph of stream errors
  751.         //
  752.         NotifyEvent(EC_STREAM_ERROR_STILLPLAYING, hr, 0);
  753.     }
  754.     else {
  755.  
  756.         //
  757.         // Some sort of error occurred, throw the remainder of the
  758.         // buffer away and skip this packet.
  759.         //
  760.         DbgLog((LOG_ERROR, 2,
  761.                 TEXT("Bad return code %d from MediaMatics video codec!"), rc ));
  762.         UpdateBufferPosition(m_VideoControl.pCmprRead);
  763.  
  764.         //
  765.         //  Notify the filter graph of stream errors
  766.         //
  767.         NotifyEvent(EC_STREAM_ERROR_STILLPLAYING, hr, 0);
  768.     }
  769.  
  770.  
  771.     //
  772.     // release the output buffer. If the connected pin still needs it,
  773.     // it will have addrefed it itself.
  774.     //
  775.     if (m_pOutSample != NULL) {
  776.         m_pOutSample->Release();
  777.         m_pOutSample = NULL;
  778.     }
  779.  
  780.     return hr;
  781. }
  782.  
  783.  
  784. /*****************************Private*Routine******************************\
  785. * CopySampleToBuffer
  786. *
  787. * Copies the sample to the input buffer and returns the number of bytes
  788. * present in the buffer.  Updates m_BufferStart, m_BufferCurr and
  789. * m_BufferFullness to reflect any wrapping in the buffer
  790. * that may have occurred.
  791. *
  792. \**************************************************************************/
  793. HRESULT
  794. CMpegVideoCodec::CopySampleToBuffer(
  795.     IMediaSample *pSample
  796.     )
  797. {
  798.     BYTE    *pSrc;
  799.     long    LenLeftInBuffer;
  800.     long    AmountToCopy;
  801.     HRESULT hr;
  802.  
  803.     if (m_pSample == NULL) {
  804.  
  805.         hr = pSample->GetPointer(&pSrc);
  806.         if (FAILED(hr)) {
  807.             return hr;
  808.         }
  809.         ASSERT(pSrc);
  810.  
  811.         // Skip pass the stream header and extract the packet length.
  812.         //
  813.         if (m_bPayloadOnly) {
  814.             m_pSample = pSrc;
  815.             m_LenLeftInPacket = pSample->GetActualDataLength();
  816.         }
  817.         else {
  818.             m_pSample = SkipToPacketData(pSrc, m_LenLeftInPacket);
  819.             if (m_pSample == NULL) {
  820.                 return E_INVALIDARG;
  821.             }
  822.         }
  823.     }
  824.  
  825.  
  826.     //
  827.     // Move what remains in the video data buffer to the top of the buffer
  828.     // and append the new video data to it.
  829.     // Don't ever let it fill up completely or we'll have to worry about
  830.     // full vs empty
  831.     //
  832.     LenLeftInBuffer = m_VBlockSize - m_BufferFullness;
  833.  
  834.     AmountToCopy = min(LenLeftInBuffer, m_LenLeftInPacket);
  835.     CopyMemory(m_BufferCurr + m_BufferFullness, m_pSample, AmountToCopy);
  836.  
  837.  
  838.     m_LenLeftInPacket -= AmountToCopy;
  839.     m_pSample         += AmountToCopy;
  840.     m_BufferFullness  += AmountToCopy;
  841.  
  842.     return S_OK;
  843. }
  844.  
  845.  
  846. /*****************************Private*Routine******************************\
  847. * UpdateBufferPosition
  848. *
  849. * Updates m_BufferCurr from the new position passed in.
  850. * Checks if m_BufferCurr is in the 'virtual' space at the end of the buffer
  851. * and if it is adjusts m_BufferCurrent and m_BufferFullness down by the real
  852. * buffer size
  853. *
  854. \**************************************************************************/
  855. void
  856. CMpegVideoCodec::UpdateBufferPosition(
  857.     LPBYTE lpNewCurrent
  858.     )
  859. {
  860.     ASSERT(lpNewCurrent >= m_BufferCurr);
  861.  
  862.     //
  863.     // Sometimes the position gets reported as 1 too many (!)
  864.     //
  865.     if (lpNewCurrent > m_BufferCurr + m_BufferFullness) {
  866.         lpNewCurrent = m_BufferCurr + m_BufferFullness;
  867.     }
  868.     m_BufferFullness -= lpNewCurrent - m_BufferCurr;
  869.     if (lpNewCurrent >= (m_BufferStart + m_VBlockSize)) {
  870.         lpNewCurrent -= m_VBlockSize;
  871.     }
  872.  
  873.     //
  874.     // Fix up the time code list
  875.     //
  876.     while (TRUE) {
  877.  
  878.         POSITION pos = m_PtsQueue.GetHeadPosition();
  879.         if (pos == NULL) {
  880.             break;
  881.         }
  882.  
  883.         CTimePosition *pTimePos = m_PtsQueue.Get(pos);
  884.  
  885.         if (BuffOffset(pTimePos->m_BufferPosition) < BuffOffset(lpNewCurrent)) {
  886.             delete pTimePos;
  887.             m_PtsQueue.RemoveHead();
  888.         }
  889.         else {
  890.             break;
  891.         }
  892.     }
  893.  
  894.     //
  895.     //  Advance to the new position
  896.     //
  897.     // m_BufferCurr = lpNewCurrent;
  898.     MoveMemory(m_BufferCurr, lpNewCurrent, m_BufferFullness);
  899. }
  900.  
  901.  
  902.  
  903.  
  904. /*****************************Private*Routine******************************\
  905. * UpdateTimeSyncPoint
  906. *
  907. * Each time we get a media sample with a Pts
  908. * time stamp we add a TIMEPOSITION entry to a queue of time positions.
  909. * Each time we decode an I frame we record the starting and ending position
  910. * of the I frame picture within the input buffer, this information is
  911. * then used to find a suitable time stamp to associate with the frame.  If
  912. * a suitable time stamp cannot be found or the frame is not an I frame we
  913. * calculate a suitable time code by extrapolation.
  914. *
  915. \**************************************************************************/
  916. BOOL
  917. CMpegVideoCodec::UpdateTimeSyncPoint(
  918.     LPBYTE lpPicStart,
  919.     REFERENCE_TIME *Time
  920.     )
  921. {
  922.     POSITION  pos = m_PtsQueue.GetHeadPosition();
  923.     BOOL      bFound;
  924.  
  925.     for (bFound = FALSE; pos != NULL; ) {
  926.         CTimePosition *pTimePos = m_PtsQueue.GetNext(pos);
  927.  
  928.         if (BuffOffset(pTimePos->m_BufferPosition) <= BuffOffset(lpPicStart)) {
  929.  
  930.             //  Buffer start time stamp could be for us (but keep looking
  931.             //  in case there's a better one)
  932.             //
  933.             //  NOTE this ASSUMES there are no packets with time stamps but no
  934.             //  start code so in fact this one should be ours
  935.  
  936.             bFound = TRUE;
  937.             *Time  = pTimePos->m_PtsTimeStamp;
  938.             delete pTimePos;
  939.             m_PtsQueue.RemoveHead();
  940.         }
  941.         else {
  942.             break;
  943.         }
  944.     }
  945.  
  946.     if (bFound) {
  947.         DbgLog((LOG_TRACE, 3,
  948.                 TEXT("CMpegVideoCodec::UpdateTimeSyncPoint() : Found time %s"),
  949.                 (LPCTSTR)CDisp(*Time) ));
  950.     }
  951.  
  952.     return bFound;
  953. }
  954.  
  955.  
  956.  
  957. /*****************************Private*Routine******************************\
  958. * BuffOffset
  959. *
  960. * Adjusts the supplied offset so that is based upon m_BufferCurr
  961. *
  962. \**************************************************************************/
  963. inline ptrdiff_t
  964. CMpegVideoCodec::BuffOffset(
  965.     LPBYTE Offset
  966.     )
  967. {
  968.     ptrdiff_t x = Offset - m_BufferCurr;
  969.     if (x < 0) {
  970.         x += m_VBlockSize;
  971.     }
  972.     return x;
  973. }
  974.  
  975.  
  976. /******************************Public*Routine******************************\
  977.  
  978. * CheckInputType
  979. *
  980. * Check if you can support mtIn
  981. *
  982. \**************************************************************************/
  983. HRESULT
  984. CMpegVideoCodec::CheckInputType(
  985.     const CMediaType* pmtIn
  986.     )
  987. {
  988.     DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::CheckInputType")));
  989.  
  990.     //
  991.     //  Check for native streams
  992.     //
  993.  
  994.     if (*pmtIn->Type() == MEDIATYPE_Stream &&
  995.         *pmtIn->Subtype() == MEDIASUBTYPE_MPEG1Video) {
  996.  
  997.         //
  998.         //  If there's no format block we'll read the stream during
  999.         //  CompleteConnect()
  1000.         //
  1001.         if (pmtIn->cbFormat == 0) {
  1002.             return S_OK;
  1003.         }
  1004.     }
  1005.     else {
  1006.         //
  1007.         // check this is an MPEG video format type
  1008.         //
  1009.         if (*pmtIn->FormatType() != FORMAT_MPEGVideo) {
  1010.             return E_INVALIDARG;
  1011.         }
  1012.  
  1013.         //
  1014.         // we only support MEDIATYPE_Video
  1015.         //
  1016.         if (*pmtIn->Type() != MEDIATYPE_Video) {
  1017.             return E_INVALIDARG;
  1018.         }
  1019.  
  1020.         if (*pmtIn->Subtype() != MEDIASUBTYPE_MPEG1Packet &&
  1021.             *pmtIn->Subtype() != MEDIASUBTYPE_MPEG1Payload) {
  1022.             return E_INVALIDARG;
  1023.         }
  1024.     }
  1025.  
  1026.     if (pmtIn->cbFormat < SIZE_VIDEOHEADER + sizeof(DWORD) ||
  1027.         pmtIn->cbFormat < SIZE_MPEG1VIDEOINFO((MPEG1VIDEOINFO *)pmtIn->pbFormat)) {
  1028.         return E_INVALIDARG;
  1029.     }
  1030.  
  1031.     //
  1032.     // Check the sequence header and save the info
  1033.     //
  1034.  
  1035.     MPEG1VIDEOINFO* videoInfo = (MPEG1VIDEOINFO *)pmtIn->pbFormat;
  1036.     if (!ParseSequenceHeader(videoInfo->bSequenceHeader,
  1037.                              videoInfo->cbSequenceHeader, &m_seqInfo)) {
  1038.         return E_INVALIDARG;
  1039.     }
  1040.  
  1041.     return S_OK;
  1042. }
  1043.  
  1044.  
  1045. /******************************Public*Routine******************************\
  1046. * CheckTransform
  1047. *
  1048. * Check if you can support the transform from this input to this output
  1049. *
  1050. \**************************************************************************/
  1051. HRESULT
  1052. CMpegVideoCodec::CheckTransform(
  1053.     const CMediaType* pmtIn,
  1054.     const CMediaType* pmtOut
  1055.     )
  1056. {
  1057.     DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::CheckTransform")));
  1058.  
  1059.     // we only output video
  1060.     if (*pmtOut->Type() != MEDIATYPE_Video) {
  1061.         return VFW_E_TYPE_NOT_ACCEPTED;
  1062.     }
  1063.  
  1064.     // Check there is a format block
  1065.     if (*pmtOut->FormatType() != FORMAT_VideoInfo) {
  1066.         return VFW_E_TYPE_NOT_ACCEPTED;
  1067.     }
  1068.  
  1069.     //
  1070.     // See if we can use dci/direct draw.
  1071.     // First check that there is a non empty target rectangle.
  1072.     //
  1073.  
  1074.     VIDEOINFO *videoInfo = (VIDEOINFO *)pmtOut->pbFormat;
  1075.     if (!IsRectEmpty(&videoInfo->rcTarget)) {
  1076.  
  1077.         //
  1078.         // Next, check that the source rectangle is the entire movie.
  1079.         //
  1080.  
  1081.         if ( videoInfo->rcSource.left   == 0
  1082.           && videoInfo->rcSource.top    == 0
  1083.           && videoInfo->rcSource.right  == m_seqInfo.lWidth
  1084.           && videoInfo->rcSource.bottom == m_seqInfo.lHeight) {
  1085.  
  1086.             //
  1087.             // Now check that the target rectangles size is the same as
  1088.             // the movies, that is there is no stretching or shrinking.
  1089.             //
  1090.  
  1091.             if ( (videoInfo->rcTarget.right - videoInfo->rcTarget.left)
  1092.                     == m_seqInfo.lWidth
  1093.               && (videoInfo->rcTarget.bottom - videoInfo->rcTarget.top)
  1094.                     == m_seqInfo.lHeight) {
  1095. #ifndef _X86_
  1096.                 // On Risc machines make sure we are DWORD aligned
  1097.                 if ((videoInfo->rcTarget.left & 0x03) == 0x00)
  1098. #endif
  1099.                 {
  1100.                     DbgLog((LOG_TRACE, 2, TEXT("Using DCI")));
  1101.                     return S_OK;
  1102.                 }
  1103.             }
  1104.         }
  1105.         DbgLog((LOG_TRACE, 2, TEXT("NOT Using DCI")));
  1106.         return E_FAIL;
  1107.     }
  1108.  
  1109.  
  1110.     return S_OK;
  1111. }
  1112.  
  1113.  
  1114. /******************************Public*Routine******************************\
  1115. * SetMediaType
  1116. *
  1117. * Overriden to know when the media type is actually set
  1118. *
  1119. \**************************************************************************/
  1120. HRESULT
  1121. CMpegVideoCodec::SetMediaType(
  1122.     PIN_DIRECTION direction,
  1123.     const CMediaType *pmt
  1124.     )
  1125. {
  1126.     DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::SetMediaType")));
  1127.  
  1128.     if (direction == PINDIR_INPUT) {
  1129.  
  1130.         //
  1131.         // Get the data type
  1132.         //
  1133.         if (*pmt->Subtype() == MEDIASUBTYPE_MPEG1Packet) {
  1134.             m_bPayloadOnly = FALSE;
  1135.         }
  1136.         else {
  1137.             ASSERT(*pmt->Subtype() == MEDIASUBTYPE_MPEG1Payload ||
  1138.                    *pmt->Subtype() == MEDIASUBTYPE_MPEG1Video);
  1139.             m_bPayloadOnly = TRUE;
  1140.         }
  1141.     }
  1142.     else {
  1143.         SetOutputPinMediaType(pmt);
  1144.     }
  1145.     return S_OK;
  1146. }
  1147.  
  1148.  
  1149. /*****************************Private*Routine******************************\
  1150. * SetOutputPinMediaType
  1151. *
  1152. * This function is a static member function of CMpegVideoCodec, this is so that
  1153. * it can be called from SetMediaType (above) and from the static member
  1154. * function GetDecodeBufferAndFormat.  Note that we pass in the "this" pointer
  1155. * explicitly.
  1156. *
  1157. \**************************************************************************/
  1158. void
  1159. CMpegVideoCodec::SetOutputPinMediaType(
  1160.     const CMediaType *pmt
  1161.     )
  1162. {
  1163.     VIDEOINFO   *pvi;
  1164.     LONG        lStride;
  1165.     LONG        lOffset;
  1166.  
  1167.     if (*pmt->Subtype() == MEDIASUBTYPE_Y41P) {
  1168.         m_dwOutputFormatDib = MM_411PK;
  1169.         m_dwOutputFormatDdb = MM_411PK;
  1170.     }
  1171.     else if (*pmt->Subtype() == MEDIASUBTYPE_YUY2) {
  1172.         m_dwOutputFormatDib = MM_422PK;
  1173.         m_dwOutputFormatDdb = MM_422PK;
  1174.     }
  1175.     else if (*pmt->Subtype() == MEDIASUBTYPE_UYVY) {
  1176.         m_dwOutputFormatDib = MM_422SPK;
  1177.         m_dwOutputFormatDdb = MM_422SPK;
  1178.     }
  1179.     else if (*pmt->Subtype() == MEDIASUBTYPE_RGB24) {
  1180.         m_dwOutputFormatDib = MM_RGB24_DIB;
  1181.         m_dwOutputFormatDdb = MM_RGB24_DDB;
  1182.     }
  1183.     else if (*pmt->Subtype() == MEDIASUBTYPE_RGB565) {
  1184.         m_dwOutputFormatDib = MM_RGB565_DIB;
  1185.         m_dwOutputFormatDdb = MM_RGB565_DDB;
  1186.     }
  1187.     else if (*pmt->Subtype() == MEDIASUBTYPE_RGB555) {
  1188.         m_dwOutputFormatDib = MM_RGB555_DIB;
  1189.         m_dwOutputFormatDdb = MM_RGB555_DDB;
  1190.     }
  1191.     else {
  1192.         ASSERT(*pmt->Subtype() == MEDIASUBTYPE_RGB8);
  1193.         if (m_PaletteType == COLOUR_PALETTE) {
  1194.             m_dwOutputFormatDib = MM_RGB8_DIB;
  1195.             m_dwOutputFormatDdb = MM_RGB8_DDB;
  1196.         }
  1197.         else {
  1198.             m_dwOutputFormatDib = MM_Y_DIB;
  1199.             m_dwOutputFormatDdb = MM_Y_DDB;
  1200.         }
  1201.     }
  1202.  
  1203.     //
  1204.     // lStride is the distance between in bytes between a pel on the
  1205.     // screen and the pel directly underneath it.
  1206.     //
  1207.  
  1208.     pvi = (VIDEOINFO *)pmt->pbFormat;
  1209.     lStride = ((pvi->bmiHeader.biWidth * pvi->bmiHeader.biBitCount) + 7) / 8;
  1210.     lStride = (lStride + 3) & ~3;
  1211.  
  1212.  
  1213.     //
  1214.     // lOffset is the distance in bytes from the top corner of the
  1215.     // target bitmap to the top corner of the video image.  When we are
  1216.     // using DIBs this value allways be zero.
  1217.     //
  1218.     // When we are using DCI/DirectDraw this value will only be zero if
  1219.     // we are drawing the video image at the top left hand corner of the
  1220.     // display.
  1221.     //
  1222.  
  1223.     lOffset = (((pvi->rcTarget.left * pvi->bmiHeader.biBitCount) + 7) / 8) +
  1224.                 (pvi->rcTarget.top * lStride);
  1225.  
  1226.     m_VideoControl.dwOutStride = lStride;
  1227.     m_VideoControl.dwOutOffset = lOffset;
  1228.  
  1229.  
  1230.     //
  1231.     // See what orientation we need to use when colour converting
  1232.     // the frame.
  1233.     //
  1234.  
  1235.     if (pvi->bmiHeader.biHeight > 0) {
  1236.         m_VideoControl.dwOutputFormat = m_dwOutputFormatDib;
  1237.     }
  1238.     else {
  1239.         m_VideoControl.dwOutputFormat = m_dwOutputFormatDdb;
  1240.     }
  1241. }
  1242.  
  1243.  
  1244. /******************************Public*Routine******************************\
  1245. * GetMediaType
  1246. *
  1247. * Return our preferred output media types (in order)
  1248. *
  1249. \**************************************************************************/
  1250. HRESULT
  1251. CMpegVideoCodec::GetMediaType(
  1252.     int iPosition,
  1253.     CMediaType *pmt
  1254.     )
  1255. {
  1256.     VIDEOINFO   *pVideoInfo;
  1257.     CMediaType  cmt;
  1258.  
  1259.     DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::GetMediaType")));
  1260.  
  1261.     if (iPosition < 0) {
  1262.         return E_INVALIDARG;
  1263.     }
  1264.  
  1265.     //
  1266.     // Quick hack to enable greyscale for Robin
  1267.     //
  1268.     if (m_PaletteType == GREY_PALETTE) {
  1269.  
  1270.         if (iPosition > 0) {
  1271.             return VFW_S_NO_MORE_ITEMS;
  1272.         }
  1273.  
  1274.         iPosition = MT_RGB8;
  1275.     }
  1276.  
  1277.     //
  1278.     // We copy the proposed output format so that we can play around with
  1279.     // it all we like and still leave the original preferred format
  1280.     // untouched.  We try each of the known BITMAPINFO types in turn
  1281.     // starting off with the best quality moving through to the worst
  1282.     // (palettised) format
  1283.     //
  1284.  
  1285.     cmt = m_pInput->CurrentMediaType();
  1286.  
  1287.     if (*cmt.Type() != MEDIATYPE_Video) {
  1288.         pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_PREHEADER);
  1289.         if (pVideoInfo == NULL) {
  1290.             return E_OUTOFMEMORY;
  1291.         }
  1292.         pVideoInfo->rcSource.top = 0;
  1293.         pVideoInfo->rcSource.left = 0;
  1294.         pVideoInfo->rcSource.right = m_seqInfo.lWidth;
  1295.         pVideoInfo->rcSource.bottom = m_seqInfo.lHeight;
  1296.         pVideoInfo->AvgTimePerFrame = m_seqInfo.tPictureTime;
  1297.         pVideoInfo->rcTarget = pVideoInfo->rcSource;
  1298.     }
  1299.     else {
  1300.         pVideoInfo = (VIDEOINFO *) cmt.Format();
  1301.         ASSERT(pVideoInfo != NULL);
  1302.     }
  1303.  
  1304.     //
  1305.     // Fill in the output format according to requested position, see the
  1306.     // Media Type enum in mpgvideo.h for the list of supported types and
  1307.     // their positions.
  1308.     //
  1309.     switch (iPosition) {
  1310.     case MT_Y41P:
  1311.         pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_VIDEOHEADER);
  1312.         if (pVideoInfo == NULL) {
  1313.             return E_OUTOFMEMORY;
  1314.         }
  1315.         InitDestinationVideoInfo(pVideoInfo, MAKEFOURCC('Y','4','1','P'), 12);
  1316.  
  1317.         *pmt = cmt;
  1318.         pmt->SetSubtype(&MEDIASUBTYPE_Y41P);
  1319.         break;
  1320.  
  1321.     case MT_YUY2:
  1322.         pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_VIDEOHEADER);
  1323.         if (pVideoInfo == NULL) {
  1324.             return E_OUTOFMEMORY;
  1325.         }
  1326.         InitDestinationVideoInfo(pVideoInfo, MAKEFOURCC('Y','U','Y','2'), 16);
  1327.  
  1328.         *pmt = cmt;
  1329.         pmt->SetSubtype(&MEDIASUBTYPE_YUY2);
  1330.         break;
  1331.  
  1332.     case MT_UYVY:
  1333.         pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_VIDEOHEADER);
  1334.         if (pVideoInfo == NULL) {
  1335.             return E_OUTOFMEMORY;
  1336.         }
  1337.         InitDestinationVideoInfo(pVideoInfo, MAKEFOURCC('U','Y','V','Y'), 16);
  1338.  
  1339.         *pmt = cmt;
  1340.         pmt->SetSubtype(&MEDIASUBTYPE_UYVY);
  1341.         break;
  1342.  
  1343.     case MT_RGB24:
  1344.         pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_VIDEOHEADER);
  1345.         if (pVideoInfo == NULL) {
  1346.             return E_OUTOFMEMORY;
  1347.         }
  1348.         InitDestinationVideoInfo(pVideoInfo, BI_RGB, 24);
  1349.  
  1350.         *pmt = cmt;
  1351.         pmt->SetSubtype(&MEDIASUBTYPE_RGB24);
  1352.         break;
  1353.  
  1354.     case MT_RGB565:
  1355.         pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_VIDEOHEADER +
  1356.                                                           SIZE_MASKS);
  1357.         if (pVideoInfo == NULL) {
  1358.             return E_OUTOFMEMORY;
  1359.         }
  1360.  
  1361.         InitDestinationVideoInfo(pVideoInfo, BI_BITFIELDS, 16);
  1362.  
  1363.         DWORD *pdw;
  1364.         pdw = (DWORD *)(HEADER(pVideoInfo) + 1);
  1365.         pdw[iRED]   = bits565[iRED];
  1366.         pdw[iGREEN] = bits565[iGREEN];
  1367.         pdw[iBLUE]  = bits565[iBLUE];
  1368.  
  1369.         *pmt = cmt;
  1370.         pmt->SetSubtype(&MEDIASUBTYPE_RGB565);
  1371.         break;
  1372.  
  1373.     case MT_RGB555:
  1374.         pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_VIDEOHEADER);
  1375.         if (pVideoInfo == NULL) {
  1376.             return E_OUTOFMEMORY;
  1377.         }
  1378.         InitDestinationVideoInfo(pVideoInfo, BI_RGB, 16);
  1379.  
  1380.         *pmt = cmt;
  1381.         pmt->SetSubtype(&MEDIASUBTYPE_RGB555);
  1382.         break;
  1383.  
  1384.     case MT_RGB8:
  1385.         pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(
  1386.                                            SIZE_VIDEOHEADER + SIZE_PALETTE);
  1387.         if (pVideoInfo == NULL) {
  1388.             return E_OUTOFMEMORY;
  1389.         }
  1390.         InitDestinationVideoInfo(pVideoInfo, BI_RGB, 8);
  1391.         InitDestinationPalette(pVideoInfo);
  1392.  
  1393.         *pmt = cmt;
  1394.         pmt->SetSubtype(&MEDIASUBTYPE_RGB8);
  1395.         break;
  1396.  
  1397.     default:
  1398.         return VFW_S_NO_MORE_ITEMS;
  1399.  
  1400.     }
  1401.  
  1402.     //
  1403.     // This block assumes that lpbi has been set up to point to a valid
  1404.     // bitmapinfoheader and that cmt has been copied into *pmt.
  1405.     // This is taken care of in the switch statement above.  This should
  1406.     // kept in mind when new formats are added.
  1407.     //
  1408.     pmt->SetType(&MEDIATYPE_Video);
  1409.     pmt->SetFormatType(&FORMAT_VideoInfo);
  1410.  
  1411.     //
  1412.     // we assume the output format is uncompressed
  1413.     //
  1414.     pmt->SetTemporalCompression(FALSE);
  1415.     pmt->SetSampleSize(HEADER(pVideoInfo)->biSizeImage);
  1416.     return S_OK;
  1417. }
  1418.  
  1419.  
  1420. /*****************************Private*Routine******************************\
  1421. * InitDestinationVideoInfo
  1422. *
  1423. * Fills in common video and bitmap info header fields
  1424. *
  1425. \**************************************************************************/
  1426. void
  1427. CMpegVideoCodec::InitDestinationVideoInfo(
  1428.     VIDEOINFO *pVideoInfo,
  1429.     DWORD dwComppression,
  1430.     int nBitCount
  1431.     )
  1432. {
  1433.     LPBITMAPINFOHEADER lpbi = HEADER(pVideoInfo);
  1434.     lpbi->biSize          = sizeof(BITMAPINFOHEADER);
  1435.     lpbi->biWidth         = m_seqInfo.lWidth;
  1436.     lpbi->biHeight        = m_seqInfo.lHeight;
  1437.     lpbi->biPlanes        = 1;
  1438.     lpbi->biBitCount      = nBitCount;
  1439.     lpbi->biXPelsPerMeter = 0;
  1440.     lpbi->biYPelsPerMeter = 0;
  1441.     lpbi->biCompression   = dwComppression;
  1442.     lpbi->biSizeImage     = GetBitmapSize(lpbi);
  1443.  
  1444.     //
  1445.     // The "bit" rate is image size in bytes times 8 (to convert to bits)
  1446.     // divided by the AvgTimePerFrame.  This result is in bits per 100 nSec,
  1447.     // so we multiply by 10000000 to convert to bits per second, this multiply
  1448.     // is combined with "times" 8 above so the calculations becomes:
  1449.     //
  1450.     // BitRate = (biSizeImage * 80000000) / AvgTimePerFrame
  1451.     //
  1452.     LARGE_INTEGER li;
  1453.     li.QuadPart = pVideoInfo->AvgTimePerFrame;
  1454.     pVideoInfo->dwBitRate = MulDiv(lpbi->biSizeImage, 80000000, li.LowPart);
  1455.     pVideoInfo->dwBitErrorRate = 0L;
  1456.  
  1457. }
  1458.  
  1459.  
  1460. /*****************************Private*Routine******************************\
  1461. * InitDestinationPalette
  1462. *
  1463. * Creates a standard colour palette or gray scale palette as determined
  1464. * by the PaletteType parameter.
  1465. *
  1466. \**************************************************************************/
  1467. void
  1468. CMpegVideoCodec::InitDestinationPalette(
  1469.     VIDEOINFO *pVideoInfo
  1470.     )
  1471. {
  1472.     int             i;
  1473.     int             iPalLowEnd;
  1474.     int             iPalHiStart;
  1475.     PALETTEENTRY    pal[24];
  1476.     HDC             hDC;
  1477.  
  1478.     if (m_PaletteType == COLOUR_PALETTE) {
  1479.         for ( i = 0; i < 256; i++ ) {
  1480.             pVideoInfo->bmiColors[i].rgbRed      = PaletteData[i].r;
  1481.             pVideoInfo->bmiColors[i].rgbBlue     = PaletteData[i].b;
  1482.             pVideoInfo->bmiColors[i].rgbGreen    = PaletteData[i].g;
  1483.             pVideoInfo->bmiColors[i].rgbReserved = 0;
  1484.         }
  1485.         iPalLowEnd  = 16;
  1486.         iPalHiStart = 232;
  1487.     }
  1488.     else {
  1489.         for ( i = 0; i < 256; i++ ) {
  1490.             pVideoInfo->bmiColors[i].rgbRed      = i;
  1491.             pVideoInfo->bmiColors[i].rgbBlue     = i;
  1492.             pVideoInfo->bmiColors[i].rgbGreen    = i;
  1493.             pVideoInfo->bmiColors[i].rgbReserved = 0;
  1494.         }
  1495.         iPalLowEnd  = 10;
  1496.         iPalHiStart = 246;
  1497.     }
  1498.  
  1499.     hDC = GetDC(GetDesktopWindow());
  1500.     GetSystemPaletteEntries(hDC, 0, 16, &pal[0] );
  1501.     for ( i = 0; i < iPalLowEnd; i++ ) {
  1502.  
  1503.         pVideoInfo->bmiColors[i].rgbRed   = pal[i].peRed;
  1504.         pVideoInfo->bmiColors[i].rgbGreen = pal[i].peGreen;
  1505.         pVideoInfo->bmiColors[i].rgbBlue  = pal[i].peBlue;
  1506.     }
  1507.  
  1508.     GetSystemPaletteEntries(hDC, iPalHiStart, 256 - iPalHiStart, &pal[0] );
  1509.     for ( i = iPalHiStart; i < 256; i++ ) {
  1510.  
  1511.         pVideoInfo->bmiColors[i].rgbRed   = pal[i - iPalHiStart].peRed;
  1512.         pVideoInfo->bmiColors[i].rgbGreen = pal[i - iPalHiStart].peGreen;
  1513.         pVideoInfo->bmiColors[i].rgbBlue  = pal[i - iPalHiStart].peBlue;
  1514.     }
  1515.     ReleaseDC(GetDesktopWindow(), hDC);
  1516.  
  1517.  
  1518.     HEADER(pVideoInfo)->biClrUsed = 256;
  1519.     HEADER(pVideoInfo)->biClrImportant = 0;
  1520. }
  1521.  
  1522.  
  1523. /******************************Public*Routine******************************\
  1524. * DecideBufferSize
  1525. *
  1526. * Called from CBaseOutputPin to prepare the allocator's count
  1527. * of buffers and sizes
  1528. *
  1529. \**************************************************************************/
  1530. HRESULT
  1531. CMpegVideoCodec::DecideBufferSize(
  1532.     IMemAllocator * pAllocator,
  1533.     ALLOCATOR_PROPERTIES * pProperties
  1534.     )
  1535. {
  1536.     DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::DecideBufferSize")));
  1537.  
  1538.     ASSERT(pAllocator);
  1539.     ASSERT(pProperties);
  1540.     HRESULT hr = NOERROR;
  1541.  
  1542.     pProperties->cBuffers = 1;
  1543.     pProperties->cbBuffer = m_pOutput->CurrentMediaType().GetSampleSize();
  1544.  
  1545.     ASSERT(pProperties->cbBuffer);
  1546.     DbgLog((LOG_TRACE, 2, TEXT("Sample size = %ld\n"), pProperties->cbBuffer));
  1547.  
  1548.     // Ask the allocator to reserve us some sample memory, NOTE the function
  1549.     // can succeed (that is return NOERROR) but still not have allocated the
  1550.     // memory that we requested, so we must check we got whatever we wanted
  1551.  
  1552.     ALLOCATOR_PROPERTIES Actual;
  1553.     hr = pAllocator->SetProperties(pProperties,&Actual);
  1554.     if (FAILED(hr)) {
  1555.         return hr;
  1556.     }
  1557.  
  1558.     ASSERT(Actual.cbAlign == 1);
  1559.     ASSERT(Actual.cbPrefix == 0);
  1560.  
  1561.     if (Actual.cbBuffer < pProperties->cbBuffer ||
  1562.         Actual.cBuffers < pProperties->cBuffers) {
  1563.  
  1564.             // can't use this allocator
  1565.             return E_INVALIDARG;
  1566.     }
  1567.     return S_OK;
  1568. }
  1569.  
  1570.  
  1571. /******************************Public*Routine******************************\
  1572. * StartStreaming
  1573. *
  1574. *
  1575. *
  1576. \**************************************************************************/
  1577. HRESULT
  1578. CMpegVideoCodec::StartStreaming(
  1579.     void
  1580.     )
  1581. {
  1582.     CAutoLock   lock(&m_csFilter);
  1583.     long        Size;
  1584.     // HRESULT     hr;
  1585.  
  1586.     ASSERT(MEDIASUBTYPE_RGB8   == *m_pOutput->CurrentMediaType().Subtype() ||
  1587.            MEDIASUBTYPE_RGB555 == *m_pOutput->CurrentMediaType().Subtype() ||
  1588.            MEDIASUBTYPE_RGB565 == *m_pOutput->CurrentMediaType().Subtype() ||
  1589.            MEDIASUBTYPE_Y41P   == *m_pOutput->CurrentMediaType().Subtype() ||
  1590.            MEDIASUBTYPE_YUY2   == *m_pOutput->CurrentMediaType().Subtype() ||
  1591.            MEDIASUBTYPE_UYVY   == *m_pOutput->CurrentMediaType().Subtype() ||
  1592.            MEDIASUBTYPE_RGB24  == *m_pOutput->CurrentMediaType().Subtype());
  1593.  
  1594.     ASSERT(m_pFrameBuff == NULL);
  1595.     ASSERT(m_pVideoDecoder == NULL);
  1596.     ASSERT(m_Buffer == NULL);
  1597.  
  1598.     //
  1599.     // Create the video codec - if we fail to open the codec it is
  1600.     // probably because the codec was unable to allocate memory for its
  1601.     // decoding tables.
  1602.     //
  1603.     m_pVideoDecoder = new CVideoDecoder(this);
  1604.     if (m_pVideoDecoder == NULL) {
  1605.         return E_OUTOFMEMORY;
  1606.     }
  1607.  
  1608.  
  1609.     //
  1610.     // Allocate some space for the codecs I and P frame buffer store
  1611.     //
  1612.     Size = m_seqInfo.lWidth * m_seqInfo.lHeight;
  1613.     m_pFrameBuff = new BYTE[ 3 * (Size + (2 * (Size / 4)))];
  1614.     if (m_pFrameBuff == NULL) {
  1615.  
  1616.         delete m_pVideoDecoder;
  1617.         m_pVideoDecoder = NULL;
  1618.  
  1619.         return E_OUTOFMEMORY;
  1620.     }
  1621.  
  1622.     m_VBlockSize = m_seqInfo.lvbv;
  1623.     m_VBlockSize +=  ((1 << 16) - 1);
  1624.     m_VBlockSize &= ~((1 << 16) - 1);
  1625.  
  1626.     // m_Buffer = new CCircularBuffer(m_VBlockSize, m_VBlockSize, hr);
  1627.     m_Buffer = new BYTE[m_VBlockSize];
  1628.     if (m_Buffer == NULL) {
  1629.  
  1630.         delete [] m_pFrameBuff;
  1631.         m_pFrameBuff = NULL;
  1632.  
  1633.         delete m_pVideoDecoder;
  1634.         m_pVideoDecoder = NULL;
  1635.  
  1636.         return E_OUTOFMEMORY;
  1637.     }
  1638.  
  1639.     //
  1640.     // Initialize the mpeg video codec
  1641.     //
  1642.     m_dwLateBy = 0;
  1643.     m_dwCtrl = (m_dwCtrlDefault | m_dwQualDefault);
  1644.     m_VideoControl.dwCtrl = m_dwCtrl;
  1645.     m_VideoControl.dwYStride = m_seqInfo.lWidth;
  1646.     m_VideoControl.dwYLines = m_seqInfo.lHeight;
  1647.  
  1648.     ZeroMemory(m_pFrameBuff, Size);
  1649.     m_VideoControl.pFrameBuff = m_pFrameBuff;
  1650.  
  1651.  
  1652.     //
  1653.     // Now reset the mpeg video decoder
  1654.     //
  1655.     ResetVideoDecoder();
  1656.  
  1657.  
  1658.     //
  1659.     // Reset frame stats
  1660.     //
  1661.     ZeroMemory(m_dwFramesSkipped, sizeof(m_dwFramesSkipped));
  1662.     ZeroMemory(m_dwFramesDecoded, sizeof(m_dwFramesDecoded));
  1663.  
  1664.     return S_OK;
  1665. }
  1666.  
  1667.  
  1668. /******************************Public*Routine******************************\
  1669. * StopStreaming
  1670. *
  1671. *
  1672. *
  1673. \**************************************************************************/
  1674. HRESULT
  1675. CMpegVideoCodec::StopStreaming(
  1676.     void
  1677.     )
  1678. {
  1679.     CAutoLock       lock(&m_csFilter);
  1680.     CAutoLock       lck(&m_csReceive);
  1681.  
  1682.     CTimePosition   *pTimePos;
  1683.  
  1684.     ASSERT(m_pFrameBuff != NULL);
  1685.     ASSERT(m_pVideoDecoder != NULL);
  1686.     ASSERT(m_Buffer != NULL);
  1687.  
  1688.     delete m_pVideoDecoder;
  1689.     m_pVideoDecoder = NULL;
  1690.  
  1691.     delete [] m_pFrameBuff;
  1692.     m_pFrameBuff = NULL;
  1693.  
  1694.     delete [] m_Buffer;
  1695.     m_Buffer = NULL;
  1696.  
  1697.  
  1698.     //
  1699.     // Purge the PTS queue.
  1700.     //
  1701.     DbgLog((LOG_TRACE, 2,
  1702.             TEXT("Freeing %d time entries"), m_PtsQueue.GetCount()));
  1703.  
  1704.     while( (pTimePos = m_PtsQueue.RemoveHead()) != NULL) {
  1705.         delete pTimePos;
  1706.     }
  1707.  
  1708.     return S_OK;
  1709. }
  1710.  
  1711. /******************************Public*Routine******************************\
  1712. * Notify
  1713. *
  1714. * Handle quality control notifications sent to us
  1715. *
  1716. \**************************************************************************/
  1717. HRESULT
  1718. CMpegVideoCodec::AlterQuality(
  1719.     Quality q
  1720.     )
  1721. {
  1722.     DWORD dwNewCtrl;
  1723.     LARGE_INTEGER li;
  1724.     li.QuadPart = q.Late;
  1725.     DWORD dwTimeLate = li.LowPart;
  1726.  
  1727.     MSR_INTEGER(m_QualMsg, dwTimeLate);
  1728.     li.QuadPart = m_seqInfo.tPictureTime;
  1729.  
  1730.     DbgLog((LOG_TRACE, 2,
  1731.             TEXT("Q = %s Prop = %4.4ld Late = %8.8ld Fram = %8.8ld"),
  1732.             q.Type == Famine ? TEXT("Famine") : TEXT("Flood "),
  1733.             q.Proportion, dwTimeLate,
  1734.             li.LowPart));
  1735.  
  1736.     //
  1737.     // See if the user has overidden quality messages
  1738.     //
  1739.     if (m_IgnoreQualityMessage) {
  1740.         return S_OK;
  1741.     }
  1742.  
  1743.     //
  1744.     // Turn off the old option and then bring in the new.
  1745.     //
  1746.  
  1747.     m_dwLateBy = dwTimeLate;
  1748.  
  1749.     if (dwTimeLate <= 750000L) {
  1750.         DbgLog((LOG_TRACE, 2, TEXT("Default QL")));
  1751.         dwNewCtrl = m_dwCtrlDefault;
  1752.     }
  1753.     else if (dwTimeLate <= (7L * 330000L)) {
  1754.         DbgLog((LOG_TRACE, 2, TEXT("IP")));
  1755.         dwNewCtrl = DECODE_IP;
  1756.     }
  1757.     else {
  1758.         DbgLog((LOG_TRACE, 2, TEXT("I")));
  1759.         dwNewCtrl = DECODE_I;
  1760.     }
  1761.  
  1762.     m_dwCtrl = (m_dwQualDefault | dwNewCtrl);
  1763.  
  1764.     return S_OK;
  1765. }
  1766.  
  1767.  
  1768. // -------------------------------------------------------------------------
  1769. // IP Tracking class
  1770. // -------------------------------------------------------------------------
  1771. //
  1772. inline CMpegVideoCodec::CNextIP::CNextIP()
  1773. {
  1774.     Reset();
  1775. }
  1776.  
  1777. inline void
  1778. CMpegVideoCodec::CNextIP::Set(
  1779.     DWORD dwSkipFlag,
  1780.     BOOL bIFrame,
  1781.     BOOL bTimeSet,
  1782.     REFERENCE_TIME t,
  1783.     DWORD dwTemporalReference
  1784.     )
  1785. {
  1786.     if (m_bGotFirst) {
  1787.  
  1788.         m_bTimeToDraw = FALSE;
  1789.         NextRef(dwTemporalReference); // Might already be time if no Bs
  1790.     }
  1791.     else {
  1792.         if (bIFrame) {
  1793.             m_bGotFirst   = TRUE;
  1794.             m_bTimeToDraw = TRUE;
  1795.         }
  1796.     }
  1797.     m_dwSkipFlag          = dwSkipFlag;
  1798.     m_bTimeSet            = bTimeSet;
  1799.     m_t                   = t;
  1800.     m_dwTemporalReference = dwTemporalReference;
  1801.  
  1802. }
  1803.  
  1804. inline BOOL
  1805. CMpegVideoCodec::CNextIP::GotFirst()
  1806. {
  1807.     return m_bGotFirst;
  1808. }
  1809.  
  1810. inline void
  1811. CMpegVideoCodec::CNextIP::NextRef(
  1812.     DWORD dwTemporalReference
  1813.     )
  1814. {
  1815.     //  See if we're next after this one
  1816.     //  Don't set m_bTimeToDraw = FALSE here because in the case
  1817.     //  where we're stepping through undrawable B-frames before the
  1818.     //  first I-Frame we've already set m_bTimeToDraw = TRUE
  1819.     if (((dwTemporalReference + 1) & 1023) == m_dwTemporalReference) {
  1820.         m_bTimeToDraw = TRUE;
  1821.     }
  1822.     DbgLog((LOG_TRACE, 3,
  1823.             TEXT("New Temporal Reference %d, NextIP = %d, TimeToDraw = %d"),
  1824.             dwTemporalReference, m_dwTemporalReference,
  1825.             m_bTimeToDraw));
  1826. }
  1827.  
  1828.  
  1829. inline BOOL
  1830. CMpegVideoCodec::CNextIP::GetTime(
  1831.     REFERENCE_TIME *pt
  1832.     )
  1833. {
  1834.     if (m_bTimeSet) {
  1835.         *pt = m_t;
  1836.     }
  1837.     return m_bTimeSet;
  1838. }
  1839.  
  1840. inline BOOL
  1841. CMpegVideoCodec::CNextIP::TimeToDraw()  const
  1842. {
  1843.     return !m_dwSkipFlag && m_bTimeToDraw;
  1844. }
  1845.  
  1846. inline void
  1847. CMpegVideoCodec::CNextIP::Reset()
  1848. {
  1849.     m_bGotFirst = FALSE;
  1850.     m_bTimeSet = FALSE;
  1851.     m_dwTemporalReference = 0;
  1852.     m_bTimeToDraw = FALSE;
  1853. }
  1854.  
  1855.  
  1856.  
  1857.  
  1858.  
  1859. /******************************Public*Routine******************************\
  1860. * SkipToPacketData
  1861. *
  1862. *
  1863. *
  1864. \**************************************************************************/
  1865. LPBYTE
  1866. SkipToPacketData(
  1867.     LPBYTE pSrc,
  1868.     long &LenLeftInPacket
  1869.     )
  1870. {
  1871.     LPBYTE  lpPacketStart;
  1872.     DWORD   bData;
  1873.     long    Length;
  1874.  
  1875.  
  1876.     //
  1877.     // Skip the stream ID and extract the packet length
  1878.     //
  1879.     pSrc += 4;
  1880.     bData = *pSrc++;
  1881.     Length = (long)((bData << 8) + *pSrc++);
  1882.     DbgLog((LOG_TRACE, 3, TEXT("Packet length %ld"), Length ));
  1883.  
  1884.  
  1885.     //
  1886.     // Record position of first byte after packet length
  1887.     //
  1888.     lpPacketStart = pSrc;
  1889.  
  1890.  
  1891.     //
  1892.     // Remove stuffing bytes
  1893.     //
  1894.     for (; ; ) {
  1895.         bData = *pSrc++;
  1896.         if (!(bData & 0x80)) {
  1897.             break;
  1898.         }
  1899.     }
  1900.  
  1901.     if ((bData & 0xC0) == 0x40) {
  1902.         pSrc++;
  1903.         bData = *pSrc++;
  1904.     }
  1905.  
  1906.     switch (bData & 0xF1) {
  1907.  
  1908.     case 0x21:
  1909.         pSrc += 4;
  1910.         break;
  1911.  
  1912.     case 0x31:
  1913.         pSrc += 9;
  1914.         break;
  1915.  
  1916.     default:
  1917.         if (bData != 0x0F) {
  1918.             DbgLog((LOG_TRACE, 2, TEXT("Invalid packet - 0x%2.2X\n"), bData));
  1919.             return NULL;
  1920.         }
  1921.     }
  1922.  
  1923.     //
  1924.     // The length left in the packet is the original length of the packet
  1925.     // less those bytes that we have just skipped over.
  1926.     //
  1927.     LenLeftInPacket = Length - (pSrc - lpPacketStart);
  1928.     return pSrc;
  1929. }
  1930.  
  1931.  
  1932.  
  1933. #ifdef DEBUG
  1934. LPCTSTR PictureTypes[8] = {
  1935.     TEXT("forbidden frame type"),
  1936.     TEXT("I-Frame"),
  1937.     TEXT("P-Frame"),
  1938.     TEXT("B-Frame"),
  1939.     TEXT("D-Frame"),
  1940.     TEXT("Reserved frame type"),
  1941.     TEXT("Reserved frame type"),
  1942.     TEXT("Reserved frame type")
  1943. };
  1944.  
  1945. LPCTSTR PelAspectRatios[16] = {
  1946.     TEXT("Forbidden"),
  1947.     TEXT("1.0000 - VGA etc"),
  1948.     TEXT("0.6735"),
  1949.     TEXT("0.7031 - 16:9, 625 line"),
  1950.     TEXT("0.7615"),
  1951.     TEXT("0.8055"),
  1952.     TEXT("0.8437 - 16:9, 525 line"),
  1953.     TEXT("0.8935"),
  1954.     TEXT("0.9375 - CCIR601, 625 line"),
  1955.     TEXT("0.9815"),
  1956.     TEXT("1.0255"),
  1957.     TEXT("1.0695"),
  1958.     TEXT("1.1250 - CCIR601, 525 line"),
  1959.     TEXT("1.1575"),
  1960.     TEXT("1.2015"),
  1961.     TEXT("Reserved")
  1962. };
  1963.  
  1964. LPCTSTR PictureRates[16] = {
  1965.     TEXT("Forbidden"),
  1966.     TEXT("23.976"),
  1967.     TEXT("24"),
  1968.     TEXT("25"),
  1969.     TEXT("29.97"),
  1970.     TEXT("30"),
  1971.     TEXT("50"),
  1972.     TEXT("59.94"),
  1973.     TEXT("60"),
  1974.     TEXT("Reserved"),
  1975.     TEXT("Reserved"),
  1976.     TEXT("Reserved"),
  1977.     TEXT("Reserved"),
  1978.     TEXT("Reserved"),
  1979.     TEXT("Reserved"),
  1980.     TEXT("Reserved")
  1981. };
  1982. #endif // DEBUG
  1983.  
  1984. const LONG PictureTimes[16] = {
  1985.     0,
  1986.     (LONG)((double)10000000 / 23.976),
  1987.     (LONG)((double)10000000 / 24),
  1988.     (LONG)((double)10000000 / 25),
  1989.     (LONG)((double)10000000 / 29.97),
  1990.     (LONG)((double)10000000 / 30),
  1991.     (LONG)((double)10000000 / 50),
  1992.     (LONG)((double)10000000 / 59.94),
  1993.     (LONG)((double)10000000 / 60)
  1994. };
  1995.  
  1996. const LONG AspectRatios[16] = {
  1997.     0,
  1998.     393700,
  1999.     (LONG)(393700.0 * 0.6735),
  2000.     (LONG)(393700.0 * 0.7031),
  2001.     (LONG)(393700.0 * 0.7615),
  2002.     (LONG)(393700.0 * 0.8055),
  2003.     (LONG)(393700.0 * 0.8437),
  2004.     (LONG)(393700.0 * 0.8935),
  2005.     (LONG)(393700.0 * 0.9375),
  2006.     (LONG)(393700.0 * 0.9815),
  2007.     (LONG)(393700.0 * 1.0255),
  2008.     (LONG)(393700.0 * 1.0695),
  2009.     (LONG)(393700.0 * 1.1250),
  2010.     (LONG)(393700.0 * 1.1575),
  2011.     (LONG)(393700.0 * 1.2015),
  2012.     0
  2013. };
  2014.  
  2015. /******************************Public*Routine******************************\
  2016. * ParseSequenceHeader
  2017. *
  2018. *
  2019. *
  2020. \**************************************************************************/
  2021. BOOL
  2022. CMpegVideoCodec::ParseSequenceHeader(
  2023.     const BYTE *pbData,
  2024.     LONG lData,
  2025.     SEQHDR_INFO *pInfo
  2026.     )
  2027. {
  2028.     ASSERT(*(UNALIGNED DWORD *)pbData == ByteSwap(SEQUENCE_HEADER_CODE));
  2029.  
  2030.     //
  2031.     // Check random marker bit
  2032.     //
  2033.     if (!(pbData[10] & 0x20)) {
  2034.         DbgLog((LOG_ERROR, 2, TEXT("Sequence header invalid marker bit")));
  2035.         return FALSE;
  2036.     }
  2037.  
  2038.     DWORD dwWidthAndHeight = ((DWORD)pbData[4] << 16) + ((DWORD)pbData[5] << 8) +
  2039.                              ((DWORD)pbData[6]);
  2040.  
  2041.     pInfo->lWidth = dwWidthAndHeight >> 12;
  2042.     pInfo->lHeight = dwWidthAndHeight & 0xFFF;
  2043.  
  2044.     DbgLog((LOG_TRACE, 2, TEXT("Width = %d, Height = %d"),
  2045.             pInfo->lWidth, pInfo->lHeight));
  2046.  
  2047.     //
  2048.     // the '8' bit is the scramble flag used by sigma designs - ignore
  2049.     //
  2050.     BYTE PelAspectRatioAndPictureRate = pbData[7];
  2051.  
  2052.     if ((PelAspectRatioAndPictureRate & 0x0F) > 8) {
  2053.         PelAspectRatioAndPictureRate &= 0xF7;
  2054.     }
  2055.  
  2056.     DbgLog((LOG_TRACE, 2, TEXT("Pel Aspect Ratio = %s"),
  2057.         PelAspectRatios[PelAspectRatioAndPictureRate >> 4]));
  2058.     DbgLog((LOG_TRACE, 2, TEXT("Picture Rate = %s"),
  2059.         PictureRates[PelAspectRatioAndPictureRate & 0x0F]));
  2060.  
  2061.     if ((PelAspectRatioAndPictureRate & 0xF0) == 0 ||
  2062.         (PelAspectRatioAndPictureRate & 0x0F) == 0) {
  2063.  
  2064.         DbgLog((LOG_ERROR, 2, TEXT("Sequence header invalid ratio/rate")));
  2065.         return FALSE;
  2066.     }
  2067.  
  2068.     pInfo->tPictureTime =
  2069.             (LONGLONG)PictureTimes[PelAspectRatioAndPictureRate & 0x0F];
  2070.  
  2071.     pInfo->lTimePerFrame =
  2072.             MulDiv((LONG)pInfo->tPictureTime, 9, 1000);
  2073.  
  2074.     /*  Pull out the bit rate and aspect ratio for the type */
  2075.     pInfo->dwBitRate = ((((DWORD)pbData[8] << 16) + ((DWORD)pbData[9] << 8) +
  2076.                           (DWORD)pbData[10]) >> 6);
  2077.  
  2078.     if (pInfo->dwBitRate == 0x3FFFF) {
  2079.  
  2080.         DbgLog((LOG_TRACE, 2, TEXT("Variable video bit rate")));
  2081.         pInfo->dwBitRate = 0;
  2082.     }
  2083.     else {
  2084.  
  2085.         pInfo->dwBitRate *= 400;
  2086.         DbgLog((LOG_TRACE, 2, TEXT("Video bit rate is %d bits per second"),
  2087.                pInfo->dwBitRate));
  2088.     }
  2089.  
  2090.     //
  2091.     // Get a DC
  2092.     //
  2093.     HDC hdc = GetDC(GetDesktopWindow());
  2094.     ASSERT(hdc != NULL);
  2095.  
  2096.     //
  2097.     //  Guess (randomly) 39.37 inches per meter
  2098.     //
  2099.     LONG lNotionalPelsPerMeter =
  2100.             MulDiv((LONG)GetDeviceCaps(hdc, LOGPIXELSX), 3937, 100);
  2101.  
  2102.     pInfo->lXPelsPerMeter = lNotionalPelsPerMeter;
  2103.  
  2104.     pInfo->lYPelsPerMeter = MulDiv(
  2105.                               lNotionalPelsPerMeter,
  2106.                               AspectRatios[PelAspectRatioAndPictureRate >> 4],
  2107.                               10000);
  2108.     //
  2109.     // Pull out the vbv
  2110.     //
  2111.     pInfo->lvbv = ((((LONG)pbData[10] & 0x1F) << 5) |
  2112.                     ((LONG)pbData[11] >> 3)) * 2048;
  2113.  
  2114.     DbgLog((LOG_TRACE, 2, TEXT("vbv size is %d bytes"), pInfo->lvbv));
  2115.  
  2116.     //
  2117.     // Check constrained parameter stuff
  2118.     //
  2119.     if (pbData[11] & 0x04) {
  2120.  
  2121.         DbgLog((LOG_TRACE, 2, TEXT("Constrained parameter video stream")));
  2122.  
  2123.         if (pInfo->lvbv > 40960) {
  2124.  
  2125.             DbgLog((LOG_ERROR, 1,
  2126.                     TEXT("Invalid vbv (%d) for Constrained stream"),
  2127.                     pInfo->lvbv));
  2128.  
  2129.             //
  2130.             //  Have to let this through too!  bisp.mpg has this
  2131.             //  But constrain it since it might be random
  2132.             //
  2133.             pInfo->lvbv = 40960;
  2134.  
  2135.         }
  2136.  
  2137.     }
  2138.     else {
  2139.         DbgLog((LOG_TRACE, 2, TEXT("Non-Constrained parameter video stream")));
  2140.     }
  2141.  
  2142.     pInfo->lActualHeaderLen = lData;
  2143.     CopyMemory((PVOID)pInfo->RawHeader, (PVOID)pbData, pInfo->lActualHeaderLen);
  2144.     return TRUE;
  2145. }
  2146. /******************************Public*Routine******************************\
  2147. * exported entry points for registration and
  2148. * unregistration (in this case they only call
  2149. * through to default implmentations).
  2150. *
  2151. *
  2152. *
  2153. * History:
  2154. *
  2155. \**************************************************************************/
  2156. HRESULT
  2157. DllRegisterServer()
  2158. {
  2159.   return AMovieDllRegisterServer();
  2160. }
  2161.  
  2162. HRESULT
  2163. DllUnregisterServer()
  2164. {
  2165.   return AMovieDllUnregisterServer();
  2166. }
  2167.  
  2168.  
  2169.