home *** CD-ROM | disk | FTP | other *** search
- //==========================================================================;
- //
- // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
- // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
- // PURPOSE.
- //
- // Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved.
- //
- //--------------------------------------------------------------------------;
- //
- /******************************Module*Header*******************************\
- * Module Name: MpgVideo.cpp
- *
- * Implements a prototype Mpeg Video Software codec. It just consumes
- * the passed in packets.
- *
- \**************************************************************************/
- #include "MpgVideo.h"
-
- // define the GUIDs for streams and my CLSID in this file
- #include <initguid.h>
- #include "mpegUids.h"
- #include "palette.h"
-
-
- // setup data
-
- AMOVIESETUP_MEDIATYPE psudIpPinTypes[] = { { &MEDIATYPE_Video // clsMajorType
- , &MEDIASUBTYPE_MPEG1Packet } // clsMinorType
- , { &MEDIATYPE_Video // clsMajorType
- , &MEDIASUBTYPE_MPEG1Payload } }; // clsMinorType
-
- AMOVIESETUP_MEDIATYPE sudOpPinTypes = { &MEDIATYPE_Video // clsMajorType
- , &MEDIASUBTYPE_NULL }; // clsMinorType
-
- AMOVIESETUP_PIN psudPins[] = { { L"Input" // strName
- , FALSE // bRendered
- , FALSE // bOutput
- , FALSE // bZero
- , FALSE // bMany
- , &CLSID_NULL // clsConnectsToFilter
- , L"Output" // strConnectsToPin
- , 2 // nTypes
- , psudIpPinTypes } // lpTypes
- , { L"Output" // strName
- , FALSE // bRendered
- , TRUE // bOutput
- , FALSE // bZero
- , FALSE // bMany
- , &CLSID_NULL // clsConnectsToFilter
- , L"Input" // strConnectsToPin
- , 1 // nTypes
- , &sudOpPinTypes } }; // lpTypes
-
-
-
- AMOVIESETUP_FILTER sudMPEGVideo = { &CLSID_CMpegFrameworkVideoCodec // clsID
- , L"MPEG Framework Audio Codec" // strName
- , 0x00600000 // dwMerit
- , 2 // nPins
- , psudPins }; // lpPin
-
- /* -------------------------------------------------------------------------
- ** list of class ids and creator functions for class factory
- ** -------------------------------------------------------------------------
- */
- CFactoryTemplate g_Templates[] =
- {
- {L"MPEG Framework Video Codec", &CLSID_CMpegFrameworkVideoCodec, CMpegVideoCodec::CreateInstance, NULL}
- };
-
- int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
-
-
- /* -------------------------------------------------------------------------
- ** CMpegVideoCodec
- ** -------------------------------------------------------------------------
- */
- CMpegVideoCodec::CMpegVideoCodec(
- TCHAR *pName,
- LPUNKNOWN pUnk,
- HRESULT *phr
- )
- : CTransformFilter(pName, pUnk, CLSID_CMpegVideoCodec, phr),
- m_pVideoDecoder(NULL),
- m_PtsQueue(NAME("Pts queue"), 30, FALSE, FALSE),
- m_pFrameBuff(NULL),
- m_Buffer(NULL),
- m_pOutSample(NULL)
- {
- //
- // Pick up any user preferences - this should get moved to the register
- //
- m_IgnoreQualityMessage = GetProfileInt(TEXT("Quartz"),
- TEXT("IgnoreQMessages"), FALSE);
-
- m_dwCtrlDefault = GetProfileInt(TEXT("Quartz"),
- TEXT("VideoFramesDecoded"), DECODE_IPB);
- m_dwCtrlDefault &= 0x3F;
- m_dwQualDefault = GetProfileInt(TEXT("Quartz"),
- TEXT("VideoQuality"), 0);
- m_dwQualDefault &= 0x30000000;
- m_dwCtrl = (m_dwCtrlDefault | m_dwQualDefault);
-
-
- if (GetProfileInt(TEXT("Quartz"), TEXT("GreyScale"), 0)) {
- m_PaletteType = GREY_PALETTE;
- m_dwOutputFormatDib = MM_Y_DIB;
- m_dwOutputFormatDdb = MM_Y_DDB;
- }
- else {
- m_PaletteType = COLOUR_PALETTE;
- m_dwOutputFormatDib = MM_RGB8_DIB;
- m_dwOutputFormatDdb = MM_RGB8_DDB;
- }
-
- //
- // Reset frame stats
- //
- ZeroMemory(m_dwFramesSkipped, sizeof(m_dwFramesSkipped));
- ZeroMemory(m_dwFramesDecoded, sizeof(m_dwFramesDecoded));
-
- m_PerfDecode = MSR_REGISTER(TEXT("Decode Time - Start/Stop"));
- m_QualMsg = MSR_REGISTER(TEXT("Quality Message"));
- m_FrameDrawn = MSR_REGISTER(TEXT("Frame Drawn"));
- m_FrameType = MSR_REGISTER(TEXT("Frame Type"));
- }
-
- /******************************Public*Routine******************************\
- * GetSetupData
- *
- *
- *
- * History:
- *
- \**************************************************************************/
- LPAMOVIESETUP_FILTER
- CMpegVideoCodec::GetSetupData()
- {
- return &sudMPEGVideo;
- }
-
-
- CMpegVideoCodec::~CMpegVideoCodec(
- )
- {
- CTimePosition *pTimePos;
-
- DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::~CMpegVideoCodec")));
-
- delete m_pVideoDecoder;
- m_pVideoDecoder = NULL;
-
- delete [] m_pFrameBuff;
- m_pFrameBuff = NULL;
-
- delete [] m_Buffer;
- m_Buffer = NULL;
-
-
- //
- // Purge the PTS queue.
- //
- while( (pTimePos = m_PtsQueue.RemoveHead()) != NULL) {
- delete pTimePos;
- }
-
- //
- // This should have been deleted in BreakConnect
- //
- ASSERT(m_Buffer == NULL);
- }
-
-
-
- /******************************Public*Routine******************************\
- * CreateInstance
- *
- * This goes in the factory template table to create new instances
- *
- \**************************************************************************/
- CUnknown *
- CMpegVideoCodec::CreateInstance(
- LPUNKNOWN pUnk,
- HRESULT * phr
- )
- {
- DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::CreateInstance")));
- return new CMpegVideoCodec(TEXT("MPEG Video codec filter"), pUnk, phr);
- }
-
-
- /******************************Public*Routine******************************\
- * NonDelegatingQueryInterface
- *
- * Here we would reveal ISpecifyPropertyPages and IMpegVideoDecoder if
- * the framework had a property page.
- *
- \**************************************************************************/
- STDMETHODIMP
- CMpegVideoCodec::NonDelegatingQueryInterface(
- REFIID riid,
- void ** ppv
- )
- {
- return CTransformFilter::NonDelegatingQueryInterface(riid, ppv);
- }
-
-
- /******************************Public*Routine******************************\
- * EndOfStream
- *
- *
- *
- \**************************************************************************/
- HRESULT
- CMpegVideoCodec::EndOfStream()
- {
- DbgLog((LOG_TRACE, 2, TEXT("End of stream called")));
- CAutoLock lck(&m_csReceive);
-
- if (m_pVideoDecoder == NULL) {
- return VFW_E_WRONG_STATE;
- }
-
- DecodeUntilBufferEmpty();
- ResetVideoDecoder();
- return CTransformFilter::EndOfStream();
- }
-
-
- /******************************Public*Routine******************************\
- * EndFlush
- *
- *
- *
- \**************************************************************************/
- HRESULT
- CMpegVideoCodec::EndFlush()
- {
- DbgLog((LOG_TRACE, 2, TEXT("End flush called")));
- CAutoLock lck(&m_csReceive);
- ResetVideoDecoder();
- return CTransformFilter::EndFlush();
- }
-
-
- /******************************Public*Routine******************************\
- * Receive
- *
- * Copy the input sample into our buffer. Loop while the buffer size is
- * greater than or equal to the size given in the Vbv for the next picture
- * decode the picture and pass it along to the output pin for rendering.
- *
- \**************************************************************************/
- HRESULT
- CMpegVideoCodec::Receive(
- IMediaSample *pSample
- )
- {
- //
- // Make sure the pin doesn't go inactive on us
- //
-
- HRESULT hr;
- CAutoLock lck(&m_csReceive);
-
- if (m_pVideoDecoder == NULL || m_pFrameBuff == NULL) {
- return E_UNEXPECTED;
- }
-
- //
- // Check for a discontinuity, if one is found decode and display any
- // frames left in the circular buffer, reset the decoder and then continue
- // processing the current sample.
- //
- if (pSample->IsDiscontinuity() == S_OK) {
-
- DecodeUntilBufferEmpty();
- ResetVideoDecoder();
-
- //
- // Find out what the current stop time is...
- // ... get logical duration from upstream
- //
- HRESULT hrPos;
- REFTIME dStart, dStop;
- IMediaPosition *pPosition = NULL;
-
- hrPos = m_pInput->GetConnected()->QueryInterface(IID_IMediaPosition,
- (void **)&pPosition);
-
- if ( SUCCEEDED(hrPos)
- && pPosition != NULL
- && SUCCEEDED(pPosition->get_CurrentPosition(&dStart))
- && SUCCEEDED(pPosition->get_StopTime(&dStop)))
- {
- m_tStop =
- (CRefTime)(COARefTime)dStop - (CRefTime)(COARefTime)dStart;
- }
- else {
- m_tStop = 0x7FFFFFFFFFFFFFFF;
- }
-
- if (pPosition != NULL) {
- pPosition->Release();
- }
-
- DbgLog((LOG_TRACE, 2,
- TEXT("Receive() : Discontinuity - setting stop time to %s"),
- (LPCTSTR)CDisp(m_tStop)));
- }
-
- m_pSample = NULL;
- m_LenLeftInPacket = 0L;
-
- //
- // If this sample is a sync point we need to
- // update our clock and reset the count of
- // samples received since the last sync point.
- //
-
- if (pSample->IsSyncPoint() == S_OK) {
-
- CRefTime tStart, tStop;
- CTimePosition *pTimePos;
-
- pSample->GetTime((REFERENCE_TIME*)&tStart,
- (REFERENCE_TIME*)&tStop);
-
- pTimePos = new CTimePosition(&tStart,
- m_BufferCurr + m_BufferFullness >= m_BufferStart + m_VBlockSize ?
- m_BufferCurr + m_BufferFullness - m_VBlockSize : m_BufferCurr + m_BufferFullness);
-
- DbgLog(( LOG_TRACE, 4, TEXT("PTS: %s Buffer pos: %ld"),
- (LPCTSTR)CDisp(tStart), m_BufferCurr + m_BufferFullness ));
- m_PtsQueue.AddTail(pTimePos);
-
- }
-
- //
- // Decode and if necessary display as many frames as
- // possible until we exhaust our circular buffer.
- //
-
- do {
-
- hr = CopySampleToBuffer(pSample);
-
- while (SUCCEEDED(hr) && (m_BufferFullness >= m_seqInfo.lvbv)) {
-
- hr = DecodeNextPicture();
- }
-
- } while (S_OK == hr && (m_LenLeftInPacket != 0L));
-
- return hr;
- }
-
-
- /*****************************Private*Routine******************************\
- * ResetVideoDecoder
- *
- *
- *
- \**************************************************************************/
- void
- CMpegVideoCodec::ResetVideoDecoder()
- {
- //
- // Make him eat our sequence header
- //
- // m_BufferStart = m_BufferCurr = m_Buffer->GetPointer();
- m_BufferStart = m_BufferCurr = m_Buffer;
- m_BufferFullness = m_seqInfo.lActualHeaderLen;
-
- CopyMemory(m_BufferStart, m_seqInfo.RawHeader, m_seqInfo.lActualHeaderLen);
-
- m_TimeSinceLastSyncPoint = 0L;
- m_pOutSample = NULL;
-
- //
- // Don't play anything until we get a sync point
- // but don't make it too negative or we'll overflow!
- //
- m_TimeAtLastSyncPoint = (LONGLONG)-0x7FFFFFFFFFFFFF;
- m_tStopPrev = m_TimeAtLastSyncPoint;
-
- m_pVideoDecoder->ResetVideo();
-
-
- //
- // Purge the PTS queue.
- //
- CTimePosition *pTimePos;
- while( (pTimePos = m_PtsQueue.RemoveHead()) != NULL) {
- delete pTimePos;
- }
-
-
- //
- // Reset IP tracking
- //
- m_NextIP.Reset();
-
- }
-
-
- /*****************************Private*Routine******************************\
- * DecodeUntilBufferEmpty
- *
- *
- *
- \**************************************************************************/
- void
- CMpegVideoCodec::DecodeUntilBufferEmpty()
- {
- HRESULT hr = S_OK;
-
- while (SUCCEEDED(hr) && (m_BufferFullness > 0)) {
-
- LPBYTE pCurrentCurr = m_BufferCurr;
-
- DbgLog((LOG_TRACE, 3, TEXT("Forcing out a frame")));
- hr = DecodeNextPicture();
-
- if (S_OK != hr || m_BufferCurr == pCurrentCurr) {
-
- //
- // We're not making any progress!
- //
- DbgLog((LOG_ERROR, 2,
- TEXT("CMpegVideoCodec::DecodeUntilBufferEmpty() ")
- TEXT("- Stuck with %d bytes in buffer"),
- m_BufferFullness));
- break;
- }
- }
-
- //
- // Now see if there's a frame decoded but not presented
- //
- if (m_NextIP.TimeToDraw()) {
-
- DbgLog((LOG_TRACE, 2, TEXT("Trying to get last frame")));
-
- DWORD dwCtrl = m_dwCtrl;
- m_dwCtrl &= 0xFFFF0000;
- m_dwCtrl |= DECODE_DIS;
-
- if (S_OK != DecodeNextPicture()) {
- DbgLog((LOG_ERROR, 2, TEXT("Failed to display last frame")));
- }
-
- m_dwCtrl = dwCtrl; // Restore
- }
- }
-
-
- /*****************************Private*Routine******************************\
- * GetDecodeBufferAndFormat
- *
- * This function is called by the mpeg decoder when it is time to determine
- * the colour conversion format and the destination buffer pointer for the
- * frame.
- *
- \**************************************************************************/
- LPBYTE
- CMpegVideoCodec::GetDecodeBufferAndFormat()
- {
- unsigned char *pDst;
- AM_MEDIA_TYPE *pmt;
- CRefTime tStartTime(m_tStopPrev);
- CRefTime tStopTime;
-
- // Don't ask for a buffer with a negative start time.
- if (tStartTime < (LONGLONG)0) {
- tStartTime = (LONGLONG)0;
- }
-
- //
- // this may block for an indeterminate amount of time
- //
- tStopTime = tStartTime + m_seqInfo.tPictureTime;
- hrCallback = m_pOutput->GetDeliveryBuffer(&m_pOutSample,
- (REFERENCE_TIME*)&tStartTime,
- (REFERENCE_TIME*)&tStopTime,
- 0 // Must set proper flag
- // if prev frame skipped
- );
- if (FAILED(hrCallback)) {
- return NULL;
- }
- ASSERT(m_pOutSample);
-
- hrCallback = m_pOutSample->GetPointer(&pDst);
- if (FAILED(hrCallback)) {
- return NULL;
- }
- ASSERT(pDst);
-
- //
- // If the media type has changed then pmt is NOT NULL
- //
- m_pOutSample->GetMediaType(&pmt);
- if (pmt != NULL) {
- CMediaType cmt(*pmt);
- DeleteMediaType(pmt);
- SetOutputPinMediaType(&cmt);
- }
- return pDst;
- }
-
-
- /*****************************Private*Routine******************************\
- * DecodeNextPicture
- *
- * Decodes the next picture stored in the circular buffer. If the picture
- * is not "skipped" it is passed to the output pin. Updates m_BufferStart,
- * m_BufferCurr and m_BufferFullness to reflect any emptying of the buffer that
- * has taken place.
- *
- \**************************************************************************/
- HRESULT
- CMpegVideoCodec::DecodeNextPicture()
- {
- DWORD rc;
- HRESULT hr = S_OK;
-
- //
- // ParthaSr.
- // trying to recover from the absence of quality messages
- // when I do a skip - so I am predictively skipping
- // frames. - Snap back to default if I have already
- // skipped enough frames
- //
- if (m_dwLateBy < 750000L) {
- m_dwCtrl = m_dwCtrlDefault | m_dwQualDefault;
- }
-
- m_VideoControl.dwCtrl = m_dwCtrl;
-
- //
- // If we're within 1 second of the end do all IP
- //
- if (m_tStop - m_tStopPrev < CRefTime(1000L)) {
-
- //
- // But are we almost at the end? in which case we need to decode
- // everything
- //
- if (m_tStop - m_tStopPrev < CRefTime(m_seqInfo.tPictureTime) +
- CRefTime(m_seqInfo.tPictureTime)) {
-
- if ((m_dwCtrl & 0xFFFF) != DECODE_DIS) {
- m_VideoControl.dwCtrl = (m_dwCtrl & 0xFFFF0000) | DECODE_IPB;
- }
- }
- else {
-
- if ((m_dwCtrl & 0xFFFF) < DECODE_IP) {
- m_VideoControl.dwCtrl = (m_dwCtrl & 0xFFFF0000) | DECODE_IP;
- }
- }
- }
- else {
-
- //
- // Only do IP if we're before the start
- //
- if ((m_dwCtrl & 0x3F) > DECODE_IP) {
-
- if (m_tStopPrev
- + CRefTime(m_seqInfo.tPictureTime)
- + CRefTime(m_seqInfo.tPictureTime) < CRefTime(0L)) {
-
- m_VideoControl.dwCtrl = (m_dwCtrl & 0xFFFF0000) | DECODE_IP;
- }
-
- }
- }
- DbgLog((LOG_TRACE, 4, TEXT("Decode flags = %X"), m_VideoControl.dwCtrl));
-
-
- //
- // Initialize the video codec with the new video data buffer. I am
- // assuming that there is at least one video frame in the data
- // buffer. When this function gets called to force out the frames
- // left in the buffer it needs to guarded with a try except block.
- //
- m_VideoControl.pCmprWrite = m_BufferCurr + m_BufferFullness;
- m_VideoControl.pCmprRead = m_BufferCurr;
-
- //
- // This is where the action starts, call the codec and let it do it stuff.
- //
-
- // Don't die if Windows NT takes away the DCI surface
- try {
-
- MSR_START(m_PerfDecode);
- rc = m_pVideoDecoder->DecodeFrame(&m_VideoControl);
- MSR_STOP(m_PerfDecode);
- }
- except(EXCEPTION_EXECUTE_HANDLER) {
-
- DbgLog((LOG_ERROR, 1, TEXT("Exception in decoder!")));
- rc = DECODE_ERR_DATA;
- }
-
- //
- // Did the frame decode OK
- //
-
- if (rc == DECODE_SUCCESS) {
-
- #ifdef DEBUG
- static char *ft[4] = { "Dummy", "I", "P", "B" };
- #endif
-
- //
- // Record frames stats
- //
- MSR_INTEGER(m_FrameType, m_VideoControl.dwFrameType);
- if (m_VideoControl.dwSkipFlag) {
-
- DbgLog((LOG_TRACE, 2, TEXT("%hs Frame skipped"),
- ft[m_VideoControl.dwFrameType]));
-
- m_dwFramesSkipped[m_VideoControl.dwFrameType]++;
-
- LARGE_INTEGER li;
- li.QuadPart = m_seqInfo.tPictureTime;
- if (m_dwLateBy > li.LowPart) {
- m_dwLateBy -= li.LowPart;
- }
- }
- else {
- m_dwFramesDecoded[m_VideoControl.dwFrameType]++;
- }
-
- if (m_VideoControl.dwFrameType == FTYPE_I ||
- m_VideoControl.dwFrameType == FTYPE_P) {
-
- //
- // Do I/P - we're actually going to draw the I/P we
- // decoded last time we got one, not the present one
- //
-
- if (m_NextIP.GetTime((REFERENCE_TIME *)&m_TimeAtLastSyncPoint)) {
- m_TimeSinceLastSyncPoint = 0;
- }
-
- REFERENCE_TIME t;
- BOOL bIFrame = m_VideoControl.dwFrameType == FTYPE_I;
-
- if (UpdateTimeSyncPoint(m_VideoControl.pFrameStartPos, &t)) {
- m_NextIP.Set(m_VideoControl.dwSkipFlag, bIFrame,
- TRUE, t, m_VideoControl.dwTemporalReference);
- }
- else {
- m_NextIP.Set(m_VideoControl.dwSkipFlag, bIFrame,
- FALSE, t, m_VideoControl.dwTemporalReference);
- }
- }
- else {
-
- //
- // Do B
- //
- m_NextIP.NextRef(m_VideoControl.dwTemporalReference);
- if ( UpdateTimeSyncPoint(m_VideoControl.pFrameStartPos,
- (REFERENCE_TIME*)&m_TimeAtLastSyncPoint) ) {
- m_TimeSinceLastSyncPoint = 0;
- }
- }
-
- CRefTime tStop(m_TimeAtLastSyncPoint + m_TimeSinceLastSyncPoint +
- m_seqInfo.tPictureTime);
-
- if (!m_VideoControl.dwSkipFlag) {
-
- LPBITMAPINFOHEADER lpbiDst = HEADER(m_pOutput->CurrentMediaType().Format());
-
- //
- // if the time is < 0, then this is preroll to get from keyframe to
- // the current frame. We decompress it into the output buffer but
- // don't deliver it.
- //
- // In order that there are no gaps we actually start the next
- // frame where we predicted it would start, rather than the
- // actual synch point
- //
-
- CRefTime tStart(m_tStopPrev);
-
- DbgLog((LOG_TRACE, 2,
- TEXT("%hs Frame decoded - tStart = %s, tStop = %s"),
- ft[m_VideoControl.dwFrameType],
- (LPCTSTR)CDisp(tStart), (LPCTSTR)CDisp(tStop)));
-
-
- #pragma message (REMIND("Do Preroll right"))
- if (tStop > 0L && tStart <= m_tStop) {
-
- // decompressed frames are always key
- m_pOutSample->SetSyncPoint(TRUE);
- m_pOutSample->SetActualDataLength(lpbiDst->biSizeImage);
- m_pOutSample->SetTime((REFERENCE_TIME*)&tStart,
- (REFERENCE_TIME*)&tStop);
-
- DbgLog((LOG_TRACE, 2, TEXT("%hs Frame sent to next filter"),
- ft[m_VideoControl.dwFrameType]));
-
-
- hr = m_pOutput->Deliver(m_pOutSample);
- MSR_NOTE(m_FrameDrawn);
- }
- }
-
- //
- // We have successfully decoded a frame.
- // Set the new position
- //
- m_tStopPrev = tStop;
- UpdateBufferPosition(m_VideoControl.pCmprRead);
- m_TimeSinceLastSyncPoint += m_seqInfo.tPictureTime;
- }
- else if (rc == DECODE_ERR_QUARTZ) {
-
- DbgLog((LOG_ERROR, 2,
- TEXT("Could not get buffer from down stream filter")));
- hr = hrCallback;
- }
- else if (rc == DECODE_ERR_DATA) {
-
- //
- // We did not have enough data available to decode the
- // current frame, so save the data for next time.
- //
- // Since this can only happen at a discontinuity, end of
- // stream or undecipherable data we'll just throw the data
- // away if it can't be eaten
- DbgLog((LOG_ERROR, 2, TEXT("Buffer underflow") ));
-
- UpdateBufferPosition(m_VideoControl.pCmprRead);
-
- //
- // Notify the filter graph of stream errors
- //
- NotifyEvent(EC_STREAM_ERROR_STILLPLAYING, hr, 0);
- }
- else {
-
- //
- // Some sort of error occurred, throw the remainder of the
- // buffer away and skip this packet.
- //
- DbgLog((LOG_ERROR, 2,
- TEXT("Bad return code %d from MediaMatics video codec!"), rc ));
- UpdateBufferPosition(m_VideoControl.pCmprRead);
-
- //
- // Notify the filter graph of stream errors
- //
- NotifyEvent(EC_STREAM_ERROR_STILLPLAYING, hr, 0);
- }
-
-
- //
- // release the output buffer. If the connected pin still needs it,
- // it will have addrefed it itself.
- //
- if (m_pOutSample != NULL) {
- m_pOutSample->Release();
- m_pOutSample = NULL;
- }
-
- return hr;
- }
-
-
- /*****************************Private*Routine******************************\
- * CopySampleToBuffer
- *
- * Copies the sample to the input buffer and returns the number of bytes
- * present in the buffer. Updates m_BufferStart, m_BufferCurr and
- * m_BufferFullness to reflect any wrapping in the buffer
- * that may have occurred.
- *
- \**************************************************************************/
- HRESULT
- CMpegVideoCodec::CopySampleToBuffer(
- IMediaSample *pSample
- )
- {
- BYTE *pSrc;
- long LenLeftInBuffer;
- long AmountToCopy;
- HRESULT hr;
-
- if (m_pSample == NULL) {
-
- hr = pSample->GetPointer(&pSrc);
- if (FAILED(hr)) {
- return hr;
- }
- ASSERT(pSrc);
-
- // Skip pass the stream header and extract the packet length.
- //
- if (m_bPayloadOnly) {
- m_pSample = pSrc;
- m_LenLeftInPacket = pSample->GetActualDataLength();
- }
- else {
- m_pSample = SkipToPacketData(pSrc, m_LenLeftInPacket);
- if (m_pSample == NULL) {
- return E_INVALIDARG;
- }
- }
- }
-
-
- //
- // Move what remains in the video data buffer to the top of the buffer
- // and append the new video data to it.
- // Don't ever let it fill up completely or we'll have to worry about
- // full vs empty
- //
- LenLeftInBuffer = m_VBlockSize - m_BufferFullness;
-
- AmountToCopy = min(LenLeftInBuffer, m_LenLeftInPacket);
- CopyMemory(m_BufferCurr + m_BufferFullness, m_pSample, AmountToCopy);
-
-
- m_LenLeftInPacket -= AmountToCopy;
- m_pSample += AmountToCopy;
- m_BufferFullness += AmountToCopy;
-
- return S_OK;
- }
-
-
- /*****************************Private*Routine******************************\
- * UpdateBufferPosition
- *
- * Updates m_BufferCurr from the new position passed in.
- * Checks if m_BufferCurr is in the 'virtual' space at the end of the buffer
- * and if it is adjusts m_BufferCurrent and m_BufferFullness down by the real
- * buffer size
- *
- \**************************************************************************/
- void
- CMpegVideoCodec::UpdateBufferPosition(
- LPBYTE lpNewCurrent
- )
- {
- ASSERT(lpNewCurrent >= m_BufferCurr);
-
- //
- // Sometimes the position gets reported as 1 too many (!)
- //
- if (lpNewCurrent > m_BufferCurr + m_BufferFullness) {
- lpNewCurrent = m_BufferCurr + m_BufferFullness;
- }
- m_BufferFullness -= lpNewCurrent - m_BufferCurr;
- if (lpNewCurrent >= (m_BufferStart + m_VBlockSize)) {
- lpNewCurrent -= m_VBlockSize;
- }
-
- //
- // Fix up the time code list
- //
- while (TRUE) {
-
- POSITION pos = m_PtsQueue.GetHeadPosition();
- if (pos == NULL) {
- break;
- }
-
- CTimePosition *pTimePos = m_PtsQueue.Get(pos);
-
- if (BuffOffset(pTimePos->m_BufferPosition) < BuffOffset(lpNewCurrent)) {
- delete pTimePos;
- m_PtsQueue.RemoveHead();
- }
- else {
- break;
- }
- }
-
- //
- // Advance to the new position
- //
- // m_BufferCurr = lpNewCurrent;
- MoveMemory(m_BufferCurr, lpNewCurrent, m_BufferFullness);
- }
-
-
-
-
- /*****************************Private*Routine******************************\
- * UpdateTimeSyncPoint
- *
- * Each time we get a media sample with a Pts
- * time stamp we add a TIMEPOSITION entry to a queue of time positions.
- * Each time we decode an I frame we record the starting and ending position
- * of the I frame picture within the input buffer, this information is
- * then used to find a suitable time stamp to associate with the frame. If
- * a suitable time stamp cannot be found or the frame is not an I frame we
- * calculate a suitable time code by extrapolation.
- *
- \**************************************************************************/
- BOOL
- CMpegVideoCodec::UpdateTimeSyncPoint(
- LPBYTE lpPicStart,
- REFERENCE_TIME *Time
- )
- {
- POSITION pos = m_PtsQueue.GetHeadPosition();
- BOOL bFound;
-
- for (bFound = FALSE; pos != NULL; ) {
- CTimePosition *pTimePos = m_PtsQueue.GetNext(pos);
-
- if (BuffOffset(pTimePos->m_BufferPosition) <= BuffOffset(lpPicStart)) {
-
- // Buffer start time stamp could be for us (but keep looking
- // in case there's a better one)
- //
- // NOTE this ASSUMES there are no packets with time stamps but no
- // start code so in fact this one should be ours
-
- bFound = TRUE;
- *Time = pTimePos->m_PtsTimeStamp;
- delete pTimePos;
- m_PtsQueue.RemoveHead();
- }
- else {
- break;
- }
- }
-
- if (bFound) {
- DbgLog((LOG_TRACE, 3,
- TEXT("CMpegVideoCodec::UpdateTimeSyncPoint() : Found time %s"),
- (LPCTSTR)CDisp(*Time) ));
- }
-
- return bFound;
- }
-
-
-
- /*****************************Private*Routine******************************\
- * BuffOffset
- *
- * Adjusts the supplied offset so that is based upon m_BufferCurr
- *
- \**************************************************************************/
- inline ptrdiff_t
- CMpegVideoCodec::BuffOffset(
- LPBYTE Offset
- )
- {
- ptrdiff_t x = Offset - m_BufferCurr;
- if (x < 0) {
- x += m_VBlockSize;
- }
- return x;
- }
-
-
- /******************************Public*Routine******************************\
-
- * CheckInputType
- *
- * Check if you can support mtIn
- *
- \**************************************************************************/
- HRESULT
- CMpegVideoCodec::CheckInputType(
- const CMediaType* pmtIn
- )
- {
- DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::CheckInputType")));
-
- //
- // Check for native streams
- //
-
- if (*pmtIn->Type() == MEDIATYPE_Stream &&
- *pmtIn->Subtype() == MEDIASUBTYPE_MPEG1Video) {
-
- //
- // If there's no format block we'll read the stream during
- // CompleteConnect()
- //
- if (pmtIn->cbFormat == 0) {
- return S_OK;
- }
- }
- else {
- //
- // check this is an MPEG video format type
- //
- if (*pmtIn->FormatType() != FORMAT_MPEGVideo) {
- return E_INVALIDARG;
- }
-
- //
- // we only support MEDIATYPE_Video
- //
- if (*pmtIn->Type() != MEDIATYPE_Video) {
- return E_INVALIDARG;
- }
-
- if (*pmtIn->Subtype() != MEDIASUBTYPE_MPEG1Packet &&
- *pmtIn->Subtype() != MEDIASUBTYPE_MPEG1Payload) {
- return E_INVALIDARG;
- }
- }
-
- if (pmtIn->cbFormat < SIZE_VIDEOHEADER + sizeof(DWORD) ||
- pmtIn->cbFormat < SIZE_MPEG1VIDEOINFO((MPEG1VIDEOINFO *)pmtIn->pbFormat)) {
- return E_INVALIDARG;
- }
-
- //
- // Check the sequence header and save the info
- //
-
- MPEG1VIDEOINFO* videoInfo = (MPEG1VIDEOINFO *)pmtIn->pbFormat;
- if (!ParseSequenceHeader(videoInfo->bSequenceHeader,
- videoInfo->cbSequenceHeader, &m_seqInfo)) {
- return E_INVALIDARG;
- }
-
- return S_OK;
- }
-
-
- /******************************Public*Routine******************************\
- * CheckTransform
- *
- * Check if you can support the transform from this input to this output
- *
- \**************************************************************************/
- HRESULT
- CMpegVideoCodec::CheckTransform(
- const CMediaType* pmtIn,
- const CMediaType* pmtOut
- )
- {
- DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::CheckTransform")));
-
- // we only output video
- if (*pmtOut->Type() != MEDIATYPE_Video) {
- return VFW_E_TYPE_NOT_ACCEPTED;
- }
-
- // Check there is a format block
- if (*pmtOut->FormatType() != FORMAT_VideoInfo) {
- return VFW_E_TYPE_NOT_ACCEPTED;
- }
-
- //
- // See if we can use dci/direct draw.
- // First check that there is a non empty target rectangle.
- //
-
- VIDEOINFO *videoInfo = (VIDEOINFO *)pmtOut->pbFormat;
- if (!IsRectEmpty(&videoInfo->rcTarget)) {
-
- //
- // Next, check that the source rectangle is the entire movie.
- //
-
- if ( videoInfo->rcSource.left == 0
- && videoInfo->rcSource.top == 0
- && videoInfo->rcSource.right == m_seqInfo.lWidth
- && videoInfo->rcSource.bottom == m_seqInfo.lHeight) {
-
- //
- // Now check that the target rectangles size is the same as
- // the movies, that is there is no stretching or shrinking.
- //
-
- if ( (videoInfo->rcTarget.right - videoInfo->rcTarget.left)
- == m_seqInfo.lWidth
- && (videoInfo->rcTarget.bottom - videoInfo->rcTarget.top)
- == m_seqInfo.lHeight) {
- #ifndef _X86_
- // On Risc machines make sure we are DWORD aligned
- if ((videoInfo->rcTarget.left & 0x03) == 0x00)
- #endif
- {
- DbgLog((LOG_TRACE, 2, TEXT("Using DCI")));
- return S_OK;
- }
- }
- }
- DbgLog((LOG_TRACE, 2, TEXT("NOT Using DCI")));
- return E_FAIL;
- }
-
-
- return S_OK;
- }
-
-
- /******************************Public*Routine******************************\
- * SetMediaType
- *
- * Overriden to know when the media type is actually set
- *
- \**************************************************************************/
- HRESULT
- CMpegVideoCodec::SetMediaType(
- PIN_DIRECTION direction,
- const CMediaType *pmt
- )
- {
- DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::SetMediaType")));
-
- if (direction == PINDIR_INPUT) {
-
- //
- // Get the data type
- //
- if (*pmt->Subtype() == MEDIASUBTYPE_MPEG1Packet) {
- m_bPayloadOnly = FALSE;
- }
- else {
- ASSERT(*pmt->Subtype() == MEDIASUBTYPE_MPEG1Payload ||
- *pmt->Subtype() == MEDIASUBTYPE_MPEG1Video);
- m_bPayloadOnly = TRUE;
- }
- }
- else {
- SetOutputPinMediaType(pmt);
- }
- return S_OK;
- }
-
-
- /*****************************Private*Routine******************************\
- * SetOutputPinMediaType
- *
- * This function is a static member function of CMpegVideoCodec, this is so that
- * it can be called from SetMediaType (above) and from the static member
- * function GetDecodeBufferAndFormat. Note that we pass in the "this" pointer
- * explicitly.
- *
- \**************************************************************************/
- void
- CMpegVideoCodec::SetOutputPinMediaType(
- const CMediaType *pmt
- )
- {
- VIDEOINFO *pvi;
- LONG lStride;
- LONG lOffset;
-
- if (*pmt->Subtype() == MEDIASUBTYPE_Y41P) {
- m_dwOutputFormatDib = MM_411PK;
- m_dwOutputFormatDdb = MM_411PK;
- }
- else if (*pmt->Subtype() == MEDIASUBTYPE_YUY2) {
- m_dwOutputFormatDib = MM_422PK;
- m_dwOutputFormatDdb = MM_422PK;
- }
- else if (*pmt->Subtype() == MEDIASUBTYPE_UYVY) {
- m_dwOutputFormatDib = MM_422SPK;
- m_dwOutputFormatDdb = MM_422SPK;
- }
- else if (*pmt->Subtype() == MEDIASUBTYPE_RGB24) {
- m_dwOutputFormatDib = MM_RGB24_DIB;
- m_dwOutputFormatDdb = MM_RGB24_DDB;
- }
- else if (*pmt->Subtype() == MEDIASUBTYPE_RGB565) {
- m_dwOutputFormatDib = MM_RGB565_DIB;
- m_dwOutputFormatDdb = MM_RGB565_DDB;
- }
- else if (*pmt->Subtype() == MEDIASUBTYPE_RGB555) {
- m_dwOutputFormatDib = MM_RGB555_DIB;
- m_dwOutputFormatDdb = MM_RGB555_DDB;
- }
- else {
- ASSERT(*pmt->Subtype() == MEDIASUBTYPE_RGB8);
- if (m_PaletteType == COLOUR_PALETTE) {
- m_dwOutputFormatDib = MM_RGB8_DIB;
- m_dwOutputFormatDdb = MM_RGB8_DDB;
- }
- else {
- m_dwOutputFormatDib = MM_Y_DIB;
- m_dwOutputFormatDdb = MM_Y_DDB;
- }
- }
-
- //
- // lStride is the distance between in bytes between a pel on the
- // screen and the pel directly underneath it.
- //
-
- pvi = (VIDEOINFO *)pmt->pbFormat;
- lStride = ((pvi->bmiHeader.biWidth * pvi->bmiHeader.biBitCount) + 7) / 8;
- lStride = (lStride + 3) & ~3;
-
-
- //
- // lOffset is the distance in bytes from the top corner of the
- // target bitmap to the top corner of the video image. When we are
- // using DIBs this value allways be zero.
- //
- // When we are using DCI/DirectDraw this value will only be zero if
- // we are drawing the video image at the top left hand corner of the
- // display.
- //
-
- lOffset = (((pvi->rcTarget.left * pvi->bmiHeader.biBitCount) + 7) / 8) +
- (pvi->rcTarget.top * lStride);
-
- m_VideoControl.dwOutStride = lStride;
- m_VideoControl.dwOutOffset = lOffset;
-
-
- //
- // See what orientation we need to use when colour converting
- // the frame.
- //
-
- if (pvi->bmiHeader.biHeight > 0) {
- m_VideoControl.dwOutputFormat = m_dwOutputFormatDib;
- }
- else {
- m_VideoControl.dwOutputFormat = m_dwOutputFormatDdb;
- }
- }
-
-
- /******************************Public*Routine******************************\
- * GetMediaType
- *
- * Return our preferred output media types (in order)
- *
- \**************************************************************************/
- HRESULT
- CMpegVideoCodec::GetMediaType(
- int iPosition,
- CMediaType *pmt
- )
- {
- VIDEOINFO *pVideoInfo;
- CMediaType cmt;
-
- DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::GetMediaType")));
-
- if (iPosition < 0) {
- return E_INVALIDARG;
- }
-
- //
- // Quick hack to enable greyscale for Robin
- //
- if (m_PaletteType == GREY_PALETTE) {
-
- if (iPosition > 0) {
- return VFW_S_NO_MORE_ITEMS;
- }
-
- iPosition = MT_RGB8;
- }
-
- //
- // We copy the proposed output format so that we can play around with
- // it all we like and still leave the original preferred format
- // untouched. We try each of the known BITMAPINFO types in turn
- // starting off with the best quality moving through to the worst
- // (palettised) format
- //
-
- cmt = m_pInput->CurrentMediaType();
-
- if (*cmt.Type() != MEDIATYPE_Video) {
- pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_PREHEADER);
- if (pVideoInfo == NULL) {
- return E_OUTOFMEMORY;
- }
- pVideoInfo->rcSource.top = 0;
- pVideoInfo->rcSource.left = 0;
- pVideoInfo->rcSource.right = m_seqInfo.lWidth;
- pVideoInfo->rcSource.bottom = m_seqInfo.lHeight;
- pVideoInfo->AvgTimePerFrame = m_seqInfo.tPictureTime;
- pVideoInfo->rcTarget = pVideoInfo->rcSource;
- }
- else {
- pVideoInfo = (VIDEOINFO *) cmt.Format();
- ASSERT(pVideoInfo != NULL);
- }
-
- //
- // Fill in the output format according to requested position, see the
- // Media Type enum in mpgvideo.h for the list of supported types and
- // their positions.
- //
- switch (iPosition) {
- case MT_Y41P:
- pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_VIDEOHEADER);
- if (pVideoInfo == NULL) {
- return E_OUTOFMEMORY;
- }
- InitDestinationVideoInfo(pVideoInfo, MAKEFOURCC('Y','4','1','P'), 12);
-
- *pmt = cmt;
- pmt->SetSubtype(&MEDIASUBTYPE_Y41P);
- break;
-
- case MT_YUY2:
- pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_VIDEOHEADER);
- if (pVideoInfo == NULL) {
- return E_OUTOFMEMORY;
- }
- InitDestinationVideoInfo(pVideoInfo, MAKEFOURCC('Y','U','Y','2'), 16);
-
- *pmt = cmt;
- pmt->SetSubtype(&MEDIASUBTYPE_YUY2);
- break;
-
- case MT_UYVY:
- pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_VIDEOHEADER);
- if (pVideoInfo == NULL) {
- return E_OUTOFMEMORY;
- }
- InitDestinationVideoInfo(pVideoInfo, MAKEFOURCC('U','Y','V','Y'), 16);
-
- *pmt = cmt;
- pmt->SetSubtype(&MEDIASUBTYPE_UYVY);
- break;
-
- case MT_RGB24:
- pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_VIDEOHEADER);
- if (pVideoInfo == NULL) {
- return E_OUTOFMEMORY;
- }
- InitDestinationVideoInfo(pVideoInfo, BI_RGB, 24);
-
- *pmt = cmt;
- pmt->SetSubtype(&MEDIASUBTYPE_RGB24);
- break;
-
- case MT_RGB565:
- pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_VIDEOHEADER +
- SIZE_MASKS);
- if (pVideoInfo == NULL) {
- return E_OUTOFMEMORY;
- }
-
- InitDestinationVideoInfo(pVideoInfo, BI_BITFIELDS, 16);
-
- DWORD *pdw;
- pdw = (DWORD *)(HEADER(pVideoInfo) + 1);
- pdw[iRED] = bits565[iRED];
- pdw[iGREEN] = bits565[iGREEN];
- pdw[iBLUE] = bits565[iBLUE];
-
- *pmt = cmt;
- pmt->SetSubtype(&MEDIASUBTYPE_RGB565);
- break;
-
- case MT_RGB555:
- pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(SIZE_VIDEOHEADER);
- if (pVideoInfo == NULL) {
- return E_OUTOFMEMORY;
- }
- InitDestinationVideoInfo(pVideoInfo, BI_RGB, 16);
-
- *pmt = cmt;
- pmt->SetSubtype(&MEDIASUBTYPE_RGB555);
- break;
-
- case MT_RGB8:
- pVideoInfo = (VIDEOINFO *)cmt.ReallocFormatBuffer(
- SIZE_VIDEOHEADER + SIZE_PALETTE);
- if (pVideoInfo == NULL) {
- return E_OUTOFMEMORY;
- }
- InitDestinationVideoInfo(pVideoInfo, BI_RGB, 8);
- InitDestinationPalette(pVideoInfo);
-
- *pmt = cmt;
- pmt->SetSubtype(&MEDIASUBTYPE_RGB8);
- break;
-
- default:
- return VFW_S_NO_MORE_ITEMS;
-
- }
-
- //
- // This block assumes that lpbi has been set up to point to a valid
- // bitmapinfoheader and that cmt has been copied into *pmt.
- // This is taken care of in the switch statement above. This should
- // kept in mind when new formats are added.
- //
- pmt->SetType(&MEDIATYPE_Video);
- pmt->SetFormatType(&FORMAT_VideoInfo);
-
- //
- // we assume the output format is uncompressed
- //
- pmt->SetTemporalCompression(FALSE);
- pmt->SetSampleSize(HEADER(pVideoInfo)->biSizeImage);
- return S_OK;
- }
-
-
- /*****************************Private*Routine******************************\
- * InitDestinationVideoInfo
- *
- * Fills in common video and bitmap info header fields
- *
- \**************************************************************************/
- void
- CMpegVideoCodec::InitDestinationVideoInfo(
- VIDEOINFO *pVideoInfo,
- DWORD dwComppression,
- int nBitCount
- )
- {
- LPBITMAPINFOHEADER lpbi = HEADER(pVideoInfo);
- lpbi->biSize = sizeof(BITMAPINFOHEADER);
- lpbi->biWidth = m_seqInfo.lWidth;
- lpbi->biHeight = m_seqInfo.lHeight;
- lpbi->biPlanes = 1;
- lpbi->biBitCount = nBitCount;
- lpbi->biXPelsPerMeter = 0;
- lpbi->biYPelsPerMeter = 0;
- lpbi->biCompression = dwComppression;
- lpbi->biSizeImage = GetBitmapSize(lpbi);
-
- //
- // The "bit" rate is image size in bytes times 8 (to convert to bits)
- // divided by the AvgTimePerFrame. This result is in bits per 100 nSec,
- // so we multiply by 10000000 to convert to bits per second, this multiply
- // is combined with "times" 8 above so the calculations becomes:
- //
- // BitRate = (biSizeImage * 80000000) / AvgTimePerFrame
- //
- LARGE_INTEGER li;
- li.QuadPart = pVideoInfo->AvgTimePerFrame;
- pVideoInfo->dwBitRate = MulDiv(lpbi->biSizeImage, 80000000, li.LowPart);
- pVideoInfo->dwBitErrorRate = 0L;
-
- }
-
-
- /*****************************Private*Routine******************************\
- * InitDestinationPalette
- *
- * Creates a standard colour palette or gray scale palette as determined
- * by the PaletteType parameter.
- *
- \**************************************************************************/
- void
- CMpegVideoCodec::InitDestinationPalette(
- VIDEOINFO *pVideoInfo
- )
- {
- int i;
- int iPalLowEnd;
- int iPalHiStart;
- PALETTEENTRY pal[24];
- HDC hDC;
-
- if (m_PaletteType == COLOUR_PALETTE) {
- for ( i = 0; i < 256; i++ ) {
- pVideoInfo->bmiColors[i].rgbRed = PaletteData[i].r;
- pVideoInfo->bmiColors[i].rgbBlue = PaletteData[i].b;
- pVideoInfo->bmiColors[i].rgbGreen = PaletteData[i].g;
- pVideoInfo->bmiColors[i].rgbReserved = 0;
- }
- iPalLowEnd = 16;
- iPalHiStart = 232;
- }
- else {
- for ( i = 0; i < 256; i++ ) {
- pVideoInfo->bmiColors[i].rgbRed = i;
- pVideoInfo->bmiColors[i].rgbBlue = i;
- pVideoInfo->bmiColors[i].rgbGreen = i;
- pVideoInfo->bmiColors[i].rgbReserved = 0;
- }
- iPalLowEnd = 10;
- iPalHiStart = 246;
- }
-
- hDC = GetDC(GetDesktopWindow());
- GetSystemPaletteEntries(hDC, 0, 16, &pal[0] );
- for ( i = 0; i < iPalLowEnd; i++ ) {
-
- pVideoInfo->bmiColors[i].rgbRed = pal[i].peRed;
- pVideoInfo->bmiColors[i].rgbGreen = pal[i].peGreen;
- pVideoInfo->bmiColors[i].rgbBlue = pal[i].peBlue;
- }
-
- GetSystemPaletteEntries(hDC, iPalHiStart, 256 - iPalHiStart, &pal[0] );
- for ( i = iPalHiStart; i < 256; i++ ) {
-
- pVideoInfo->bmiColors[i].rgbRed = pal[i - iPalHiStart].peRed;
- pVideoInfo->bmiColors[i].rgbGreen = pal[i - iPalHiStart].peGreen;
- pVideoInfo->bmiColors[i].rgbBlue = pal[i - iPalHiStart].peBlue;
- }
- ReleaseDC(GetDesktopWindow(), hDC);
-
-
- HEADER(pVideoInfo)->biClrUsed = 256;
- HEADER(pVideoInfo)->biClrImportant = 0;
- }
-
-
- /******************************Public*Routine******************************\
- * DecideBufferSize
- *
- * Called from CBaseOutputPin to prepare the allocator's count
- * of buffers and sizes
- *
- \**************************************************************************/
- HRESULT
- CMpegVideoCodec::DecideBufferSize(
- IMemAllocator * pAllocator,
- ALLOCATOR_PROPERTIES * pProperties
- )
- {
- DbgLog((LOG_TRACE, 2, TEXT("CMpegVideoCodec::DecideBufferSize")));
-
- ASSERT(pAllocator);
- ASSERT(pProperties);
- HRESULT hr = NOERROR;
-
- pProperties->cBuffers = 1;
- pProperties->cbBuffer = m_pOutput->CurrentMediaType().GetSampleSize();
-
- ASSERT(pProperties->cbBuffer);
- DbgLog((LOG_TRACE, 2, TEXT("Sample size = %ld\n"), pProperties->cbBuffer));
-
- // Ask the allocator to reserve us some sample memory, NOTE the function
- // can succeed (that is return NOERROR) but still not have allocated the
- // memory that we requested, so we must check we got whatever we wanted
-
- ALLOCATOR_PROPERTIES Actual;
- hr = pAllocator->SetProperties(pProperties,&Actual);
- if (FAILED(hr)) {
- return hr;
- }
-
- ASSERT(Actual.cbAlign == 1);
- ASSERT(Actual.cbPrefix == 0);
-
- if (Actual.cbBuffer < pProperties->cbBuffer ||
- Actual.cBuffers < pProperties->cBuffers) {
-
- // can't use this allocator
- return E_INVALIDARG;
- }
- return S_OK;
- }
-
-
- /******************************Public*Routine******************************\
- * StartStreaming
- *
- *
- *
- \**************************************************************************/
- HRESULT
- CMpegVideoCodec::StartStreaming(
- void
- )
- {
- CAutoLock lock(&m_csFilter);
- long Size;
- // HRESULT hr;
-
- ASSERT(MEDIASUBTYPE_RGB8 == *m_pOutput->CurrentMediaType().Subtype() ||
- MEDIASUBTYPE_RGB555 == *m_pOutput->CurrentMediaType().Subtype() ||
- MEDIASUBTYPE_RGB565 == *m_pOutput->CurrentMediaType().Subtype() ||
- MEDIASUBTYPE_Y41P == *m_pOutput->CurrentMediaType().Subtype() ||
- MEDIASUBTYPE_YUY2 == *m_pOutput->CurrentMediaType().Subtype() ||
- MEDIASUBTYPE_UYVY == *m_pOutput->CurrentMediaType().Subtype() ||
- MEDIASUBTYPE_RGB24 == *m_pOutput->CurrentMediaType().Subtype());
-
- ASSERT(m_pFrameBuff == NULL);
- ASSERT(m_pVideoDecoder == NULL);
- ASSERT(m_Buffer == NULL);
-
- //
- // Create the video codec - if we fail to open the codec it is
- // probably because the codec was unable to allocate memory for its
- // decoding tables.
- //
- m_pVideoDecoder = new CVideoDecoder(this);
- if (m_pVideoDecoder == NULL) {
- return E_OUTOFMEMORY;
- }
-
-
- //
- // Allocate some space for the codecs I and P frame buffer store
- //
- Size = m_seqInfo.lWidth * m_seqInfo.lHeight;
- m_pFrameBuff = new BYTE[ 3 * (Size + (2 * (Size / 4)))];
- if (m_pFrameBuff == NULL) {
-
- delete m_pVideoDecoder;
- m_pVideoDecoder = NULL;
-
- return E_OUTOFMEMORY;
- }
-
- m_VBlockSize = m_seqInfo.lvbv;
- m_VBlockSize += ((1 << 16) - 1);
- m_VBlockSize &= ~((1 << 16) - 1);
-
- // m_Buffer = new CCircularBuffer(m_VBlockSize, m_VBlockSize, hr);
- m_Buffer = new BYTE[m_VBlockSize];
- if (m_Buffer == NULL) {
-
- delete [] m_pFrameBuff;
- m_pFrameBuff = NULL;
-
- delete m_pVideoDecoder;
- m_pVideoDecoder = NULL;
-
- return E_OUTOFMEMORY;
- }
-
- //
- // Initialize the mpeg video codec
- //
- m_dwLateBy = 0;
- m_dwCtrl = (m_dwCtrlDefault | m_dwQualDefault);
- m_VideoControl.dwCtrl = m_dwCtrl;
- m_VideoControl.dwYStride = m_seqInfo.lWidth;
- m_VideoControl.dwYLines = m_seqInfo.lHeight;
-
- ZeroMemory(m_pFrameBuff, Size);
- m_VideoControl.pFrameBuff = m_pFrameBuff;
-
-
- //
- // Now reset the mpeg video decoder
- //
- ResetVideoDecoder();
-
-
- //
- // Reset frame stats
- //
- ZeroMemory(m_dwFramesSkipped, sizeof(m_dwFramesSkipped));
- ZeroMemory(m_dwFramesDecoded, sizeof(m_dwFramesDecoded));
-
- return S_OK;
- }
-
-
- /******************************Public*Routine******************************\
- * StopStreaming
- *
- *
- *
- \**************************************************************************/
- HRESULT
- CMpegVideoCodec::StopStreaming(
- void
- )
- {
- CAutoLock lock(&m_csFilter);
- CAutoLock lck(&m_csReceive);
-
- CTimePosition *pTimePos;
-
- ASSERT(m_pFrameBuff != NULL);
- ASSERT(m_pVideoDecoder != NULL);
- ASSERT(m_Buffer != NULL);
-
- delete m_pVideoDecoder;
- m_pVideoDecoder = NULL;
-
- delete [] m_pFrameBuff;
- m_pFrameBuff = NULL;
-
- delete [] m_Buffer;
- m_Buffer = NULL;
-
-
- //
- // Purge the PTS queue.
- //
- DbgLog((LOG_TRACE, 2,
- TEXT("Freeing %d time entries"), m_PtsQueue.GetCount()));
-
- while( (pTimePos = m_PtsQueue.RemoveHead()) != NULL) {
- delete pTimePos;
- }
-
- return S_OK;
- }
-
- /******************************Public*Routine******************************\
- * Notify
- *
- * Handle quality control notifications sent to us
- *
- \**************************************************************************/
- HRESULT
- CMpegVideoCodec::AlterQuality(
- Quality q
- )
- {
- DWORD dwNewCtrl;
- LARGE_INTEGER li;
- li.QuadPart = q.Late;
- DWORD dwTimeLate = li.LowPart;
-
- MSR_INTEGER(m_QualMsg, dwTimeLate);
- li.QuadPart = m_seqInfo.tPictureTime;
-
- DbgLog((LOG_TRACE, 2,
- TEXT("Q = %s Prop = %4.4ld Late = %8.8ld Fram = %8.8ld"),
- q.Type == Famine ? TEXT("Famine") : TEXT("Flood "),
- q.Proportion, dwTimeLate,
- li.LowPart));
-
- //
- // See if the user has overidden quality messages
- //
- if (m_IgnoreQualityMessage) {
- return S_OK;
- }
-
- //
- // Turn off the old option and then bring in the new.
- //
-
- m_dwLateBy = dwTimeLate;
-
- if (dwTimeLate <= 750000L) {
- DbgLog((LOG_TRACE, 2, TEXT("Default QL")));
- dwNewCtrl = m_dwCtrlDefault;
- }
- else if (dwTimeLate <= (7L * 330000L)) {
- DbgLog((LOG_TRACE, 2, TEXT("IP")));
- dwNewCtrl = DECODE_IP;
- }
- else {
- DbgLog((LOG_TRACE, 2, TEXT("I")));
- dwNewCtrl = DECODE_I;
- }
-
- m_dwCtrl = (m_dwQualDefault | dwNewCtrl);
-
- return S_OK;
- }
-
-
- // -------------------------------------------------------------------------
- // IP Tracking class
- // -------------------------------------------------------------------------
- //
- inline CMpegVideoCodec::CNextIP::CNextIP()
- {
- Reset();
- }
-
- inline void
- CMpegVideoCodec::CNextIP::Set(
- DWORD dwSkipFlag,
- BOOL bIFrame,
- BOOL bTimeSet,
- REFERENCE_TIME t,
- DWORD dwTemporalReference
- )
- {
- if (m_bGotFirst) {
-
- m_bTimeToDraw = FALSE;
- NextRef(dwTemporalReference); // Might already be time if no Bs
- }
- else {
- if (bIFrame) {
- m_bGotFirst = TRUE;
- m_bTimeToDraw = TRUE;
- }
- }
- m_dwSkipFlag = dwSkipFlag;
- m_bTimeSet = bTimeSet;
- m_t = t;
- m_dwTemporalReference = dwTemporalReference;
-
- }
-
- inline BOOL
- CMpegVideoCodec::CNextIP::GotFirst()
- {
- return m_bGotFirst;
- }
-
- inline void
- CMpegVideoCodec::CNextIP::NextRef(
- DWORD dwTemporalReference
- )
- {
- // See if we're next after this one
- // Don't set m_bTimeToDraw = FALSE here because in the case
- // where we're stepping through undrawable B-frames before the
- // first I-Frame we've already set m_bTimeToDraw = TRUE
- if (((dwTemporalReference + 1) & 1023) == m_dwTemporalReference) {
- m_bTimeToDraw = TRUE;
- }
- DbgLog((LOG_TRACE, 3,
- TEXT("New Temporal Reference %d, NextIP = %d, TimeToDraw = %d"),
- dwTemporalReference, m_dwTemporalReference,
- m_bTimeToDraw));
- }
-
-
- inline BOOL
- CMpegVideoCodec::CNextIP::GetTime(
- REFERENCE_TIME *pt
- )
- {
- if (m_bTimeSet) {
- *pt = m_t;
- }
- return m_bTimeSet;
- }
-
- inline BOOL
- CMpegVideoCodec::CNextIP::TimeToDraw() const
- {
- return !m_dwSkipFlag && m_bTimeToDraw;
- }
-
- inline void
- CMpegVideoCodec::CNextIP::Reset()
- {
- m_bGotFirst = FALSE;
- m_bTimeSet = FALSE;
- m_dwTemporalReference = 0;
- m_bTimeToDraw = FALSE;
- }
-
-
-
-
-
- /******************************Public*Routine******************************\
- * SkipToPacketData
- *
- *
- *
- \**************************************************************************/
- LPBYTE
- SkipToPacketData(
- LPBYTE pSrc,
- long &LenLeftInPacket
- )
- {
- LPBYTE lpPacketStart;
- DWORD bData;
- long Length;
-
-
- //
- // Skip the stream ID and extract the packet length
- //
- pSrc += 4;
- bData = *pSrc++;
- Length = (long)((bData << 8) + *pSrc++);
- DbgLog((LOG_TRACE, 3, TEXT("Packet length %ld"), Length ));
-
-
- //
- // Record position of first byte after packet length
- //
- lpPacketStart = pSrc;
-
-
- //
- // Remove stuffing bytes
- //
- for (; ; ) {
- bData = *pSrc++;
- if (!(bData & 0x80)) {
- break;
- }
- }
-
- if ((bData & 0xC0) == 0x40) {
- pSrc++;
- bData = *pSrc++;
- }
-
- switch (bData & 0xF1) {
-
- case 0x21:
- pSrc += 4;
- break;
-
- case 0x31:
- pSrc += 9;
- break;
-
- default:
- if (bData != 0x0F) {
- DbgLog((LOG_TRACE, 2, TEXT("Invalid packet - 0x%2.2X\n"), bData));
- return NULL;
- }
- }
-
- //
- // The length left in the packet is the original length of the packet
- // less those bytes that we have just skipped over.
- //
- LenLeftInPacket = Length - (pSrc - lpPacketStart);
- return pSrc;
- }
-
-
-
- #ifdef DEBUG
- LPCTSTR PictureTypes[8] = {
- TEXT("forbidden frame type"),
- TEXT("I-Frame"),
- TEXT("P-Frame"),
- TEXT("B-Frame"),
- TEXT("D-Frame"),
- TEXT("Reserved frame type"),
- TEXT("Reserved frame type"),
- TEXT("Reserved frame type")
- };
-
- LPCTSTR PelAspectRatios[16] = {
- TEXT("Forbidden"),
- TEXT("1.0000 - VGA etc"),
- TEXT("0.6735"),
- TEXT("0.7031 - 16:9, 625 line"),
- TEXT("0.7615"),
- TEXT("0.8055"),
- TEXT("0.8437 - 16:9, 525 line"),
- TEXT("0.8935"),
- TEXT("0.9375 - CCIR601, 625 line"),
- TEXT("0.9815"),
- TEXT("1.0255"),
- TEXT("1.0695"),
- TEXT("1.1250 - CCIR601, 525 line"),
- TEXT("1.1575"),
- TEXT("1.2015"),
- TEXT("Reserved")
- };
-
- LPCTSTR PictureRates[16] = {
- TEXT("Forbidden"),
- TEXT("23.976"),
- TEXT("24"),
- TEXT("25"),
- TEXT("29.97"),
- TEXT("30"),
- TEXT("50"),
- TEXT("59.94"),
- TEXT("60"),
- TEXT("Reserved"),
- TEXT("Reserved"),
- TEXT("Reserved"),
- TEXT("Reserved"),
- TEXT("Reserved"),
- TEXT("Reserved"),
- TEXT("Reserved")
- };
- #endif // DEBUG
-
- const LONG PictureTimes[16] = {
- 0,
- (LONG)((double)10000000 / 23.976),
- (LONG)((double)10000000 / 24),
- (LONG)((double)10000000 / 25),
- (LONG)((double)10000000 / 29.97),
- (LONG)((double)10000000 / 30),
- (LONG)((double)10000000 / 50),
- (LONG)((double)10000000 / 59.94),
- (LONG)((double)10000000 / 60)
- };
-
- const LONG AspectRatios[16] = {
- 0,
- 393700,
- (LONG)(393700.0 * 0.6735),
- (LONG)(393700.0 * 0.7031),
- (LONG)(393700.0 * 0.7615),
- (LONG)(393700.0 * 0.8055),
- (LONG)(393700.0 * 0.8437),
- (LONG)(393700.0 * 0.8935),
- (LONG)(393700.0 * 0.9375),
- (LONG)(393700.0 * 0.9815),
- (LONG)(393700.0 * 1.0255),
- (LONG)(393700.0 * 1.0695),
- (LONG)(393700.0 * 1.1250),
- (LONG)(393700.0 * 1.1575),
- (LONG)(393700.0 * 1.2015),
- 0
- };
-
- /******************************Public*Routine******************************\
- * ParseSequenceHeader
- *
- *
- *
- \**************************************************************************/
- BOOL
- CMpegVideoCodec::ParseSequenceHeader(
- const BYTE *pbData,
- LONG lData,
- SEQHDR_INFO *pInfo
- )
- {
- ASSERT(*(UNALIGNED DWORD *)pbData == ByteSwap(SEQUENCE_HEADER_CODE));
-
- //
- // Check random marker bit
- //
- if (!(pbData[10] & 0x20)) {
- DbgLog((LOG_ERROR, 2, TEXT("Sequence header invalid marker bit")));
- return FALSE;
- }
-
- DWORD dwWidthAndHeight = ((DWORD)pbData[4] << 16) + ((DWORD)pbData[5] << 8) +
- ((DWORD)pbData[6]);
-
- pInfo->lWidth = dwWidthAndHeight >> 12;
- pInfo->lHeight = dwWidthAndHeight & 0xFFF;
-
- DbgLog((LOG_TRACE, 2, TEXT("Width = %d, Height = %d"),
- pInfo->lWidth, pInfo->lHeight));
-
- //
- // the '8' bit is the scramble flag used by sigma designs - ignore
- //
- BYTE PelAspectRatioAndPictureRate = pbData[7];
-
- if ((PelAspectRatioAndPictureRate & 0x0F) > 8) {
- PelAspectRatioAndPictureRate &= 0xF7;
- }
-
- DbgLog((LOG_TRACE, 2, TEXT("Pel Aspect Ratio = %s"),
- PelAspectRatios[PelAspectRatioAndPictureRate >> 4]));
- DbgLog((LOG_TRACE, 2, TEXT("Picture Rate = %s"),
- PictureRates[PelAspectRatioAndPictureRate & 0x0F]));
-
- if ((PelAspectRatioAndPictureRate & 0xF0) == 0 ||
- (PelAspectRatioAndPictureRate & 0x0F) == 0) {
-
- DbgLog((LOG_ERROR, 2, TEXT("Sequence header invalid ratio/rate")));
- return FALSE;
- }
-
- pInfo->tPictureTime =
- (LONGLONG)PictureTimes[PelAspectRatioAndPictureRate & 0x0F];
-
- pInfo->lTimePerFrame =
- MulDiv((LONG)pInfo->tPictureTime, 9, 1000);
-
- /* Pull out the bit rate and aspect ratio for the type */
- pInfo->dwBitRate = ((((DWORD)pbData[8] << 16) + ((DWORD)pbData[9] << 8) +
- (DWORD)pbData[10]) >> 6);
-
- if (pInfo->dwBitRate == 0x3FFFF) {
-
- DbgLog((LOG_TRACE, 2, TEXT("Variable video bit rate")));
- pInfo->dwBitRate = 0;
- }
- else {
-
- pInfo->dwBitRate *= 400;
- DbgLog((LOG_TRACE, 2, TEXT("Video bit rate is %d bits per second"),
- pInfo->dwBitRate));
- }
-
- //
- // Get a DC
- //
- HDC hdc = GetDC(GetDesktopWindow());
- ASSERT(hdc != NULL);
-
- //
- // Guess (randomly) 39.37 inches per meter
- //
- LONG lNotionalPelsPerMeter =
- MulDiv((LONG)GetDeviceCaps(hdc, LOGPIXELSX), 3937, 100);
-
- pInfo->lXPelsPerMeter = lNotionalPelsPerMeter;
-
- pInfo->lYPelsPerMeter = MulDiv(
- lNotionalPelsPerMeter,
- AspectRatios[PelAspectRatioAndPictureRate >> 4],
- 10000);
- //
- // Pull out the vbv
- //
- pInfo->lvbv = ((((LONG)pbData[10] & 0x1F) << 5) |
- ((LONG)pbData[11] >> 3)) * 2048;
-
- DbgLog((LOG_TRACE, 2, TEXT("vbv size is %d bytes"), pInfo->lvbv));
-
- //
- // Check constrained parameter stuff
- //
- if (pbData[11] & 0x04) {
-
- DbgLog((LOG_TRACE, 2, TEXT("Constrained parameter video stream")));
-
- if (pInfo->lvbv > 40960) {
-
- DbgLog((LOG_ERROR, 1,
- TEXT("Invalid vbv (%d) for Constrained stream"),
- pInfo->lvbv));
-
- //
- // Have to let this through too! bisp.mpg has this
- // But constrain it since it might be random
- //
- pInfo->lvbv = 40960;
-
- }
-
- }
- else {
- DbgLog((LOG_TRACE, 2, TEXT("Non-Constrained parameter video stream")));
- }
-
- pInfo->lActualHeaderLen = lData;
- CopyMemory((PVOID)pInfo->RawHeader, (PVOID)pbData, pInfo->lActualHeaderLen);
- return TRUE;
- }
- /******************************Public*Routine******************************\
- * exported entry points for registration and
- * unregistration (in this case they only call
- * through to default implmentations).
- *
- *
- *
- * History:
- *
- \**************************************************************************/
- HRESULT
- DllRegisterServer()
- {
- return AMovieDllRegisterServer();
- }
-
- HRESULT
- DllUnregisterServer()
- {
- return AMovieDllUnregisterServer();
- }
-
-
-