?? vtrans.cpp
字號:
//------------------------------------------------------------------------------
// File: Vtrans.cpp
//
// Desc: DirectShow base classes.
//
// Copyright (c) 1992-2002 Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
#include <streams.h>
#include <measure.h>
// #include <vtransfr.h> // now in precomp file streams.h
CVideoTransformFilter::CVideoTransformFilter
( TCHAR *pName, LPUNKNOWN pUnk, REFCLSID clsid)
: CTransformFilter(pName, pUnk, clsid)
, m_itrLate(0)
, m_nKeyFramePeriod(0) // No QM until we see at least 2 key frames
, m_nFramesSinceKeyFrame(0)
, m_bSkipping(FALSE)
, m_tDecodeStart(0)
, m_itrAvgDecode(300000) // 30mSec - probably allows skipping
, m_bQualityChanged(FALSE)
{
#ifdef PERF
RegisterPerfId();
#endif // PERF
}
CVideoTransformFilter::~CVideoTransformFilter()
{
// nothing to do
}
// Reset our quality management state
HRESULT CVideoTransformFilter::StartStreaming()
{
m_itrLate = 0;
m_nKeyFramePeriod = 0; // No QM until we see at least 2 key frames
m_nFramesSinceKeyFrame = 0;
m_bSkipping = FALSE;
m_tDecodeStart = 0;
m_itrAvgDecode = 300000; // 30mSec - probably allows skipping
m_bQualityChanged = FALSE;
m_bSampleSkipped = FALSE;
return NOERROR;
}
// Overriden to reset quality management information
HRESULT CVideoTransformFilter::EndFlush()
{
{
// Synchronize
CAutoLock lck(&m_csReceive);
// Reset our stats
//
// Note - we don't want to call derived classes here,
// we only want to reset our internal variables and this
// is a convenient way to do it
CVideoTransformFilter::StartStreaming();
}
return CTransformFilter::EndFlush();
}
HRESULT CVideoTransformFilter::AbortPlayback(HRESULT hr)
{
NotifyEvent(EC_ERRORABORT, hr, 0);
m_pOutput->DeliverEndOfStream();
return hr;
}
// Receive()
//
// Accept a sample from upstream, decide whether to process it
// or drop it. If we process it then get a buffer from the
// allocator of the downstream connection, transform it into the
// new buffer and deliver it to the downstream filter.
// If we decide not to process it then we do not get a buffer.
// Remember that although this code will notice format changes coming into
// the input pin, it will NOT change its output format if that results
// in the filter needing to make a corresponding output format change. Your
// derived filter will have to take care of that. (eg. a palette change if
// the input and output is an 8 bit format). If the input sample is discarded
// and nothing is sent out for this Receive, please remember to put the format
// change on the first output sample that you actually do send.
// If your filter will produce the same output type even when the input type
// changes, then this base class code will do everything you need.
HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample)
{
// If the next filter downstream is the video renderer, then it may
// be able to operate in DirectDraw mode which saves copying the data
// and gives higher performance. In that case the buffer which we
// get from GetDeliveryBuffer will be a DirectDraw buffer, and
// drawing into this buffer draws directly onto the display surface.
// This means that any waiting for the correct time to draw occurs
// during GetDeliveryBuffer, and that once the buffer is given to us
// the video renderer will count it in its statistics as a frame drawn.
// This means that any decision to drop the frame must be taken before
// calling GetDeliveryBuffer.
ASSERT(CritCheckIn(&m_csReceive));
AM_MEDIA_TYPE *pmtOut, *pmt;
#ifdef DEBUG
FOURCCMap fccOut;
#endif
HRESULT hr;
ASSERT(pSample);
IMediaSample * pOutSample;
// If no output pin to deliver to then no point sending us data
ASSERT (m_pOutput != NULL) ;
// The source filter may dynamically ask us to start transforming from a
// different media type than the one we're using now. If we don't, we'll
// draw garbage. (typically, this is a palette change in the movie,
// but could be something more sinister like the compression type changing,
// or even the video size changing)
#define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource
#define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget
pSample->GetMediaType(&pmt);
if (pmt != NULL && pmt->pbFormat != NULL) {
// spew some debug output
ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL));
#ifdef DEBUG
fccOut.SetFOURCC(&pmt->subtype);
LONG lCompression = HEADER(pmt->pbFormat)->biCompression;
LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount;
LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8;
lStride = (lStride + 3) & ~3;
DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to")));
DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"),
fccOut.GetFOURCC(), lCompression, lBitCount));
DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"),
HEADER(pmt->pbFormat)->biHeight,
rcT1.left, rcT1.top, rcT1.right, rcT1.bottom));
DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"),
rcS1.left, rcS1.top, rcS1.right, rcS1.bottom,
lStride));
#endif
// now switch to using the new format. I am assuming that the
// derived filter will do the right thing when its media type is
// switched and streaming is restarted.
StopStreaming();
m_pInput->CurrentMediaType() = *pmt;
DeleteMediaType(pmt);
// if this fails, playback will stop, so signal an error
hr = StartStreaming();
if (FAILED(hr)) {
return AbortPlayback(hr);
}
}
// Now that we have noticed any format changes on the input sample, it's
// OK to discard it.
if (ShouldSkipFrame(pSample)) {
MSR_NOTE(m_idSkip);
m_bSampleSkipped = TRUE;
return NOERROR;
}
// Set up the output sample
hr = InitializeOutputSample(pSample, &pOutSample);
if (FAILED(hr)) {
return hr;
}
m_bSampleSkipped = FALSE;
// The renderer may ask us to on-the-fly to start transforming to a
// different format. If we don't obey it, we'll draw garbage
#define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource
#define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget
pOutSample->GetMediaType(&pmtOut);
if (pmtOut != NULL && pmtOut->pbFormat != NULL) {
// spew some debug output
ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL));
#ifdef DEBUG
fccOut.SetFOURCC(&pmtOut->subtype);
LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression;
LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount;
LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8;
lStride = (lStride + 3) & ~3;
DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to")));
DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"),
fccOut.GetFOURCC(), lCompression, lBitCount));
DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"),
HEADER(pmtOut->pbFormat)->biHeight,
rcT.left, rcT.top, rcT.right, rcT.bottom));
DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"),
rcS.left, rcS.top, rcS.right, rcS.bottom,
lStride));
#endif
// now switch to using the new format. I am assuming that the
// derived filter will do the right thing when its media type is
// switched and streaming is restarted.
StopStreaming();
m_pOutput->CurrentMediaType() = *pmtOut;
DeleteMediaType(pmtOut);
hr = StartStreaming();
if (SUCCEEDED(hr)) {
// a new format, means a new empty buffer, so wait for a keyframe
// before passing anything on to the renderer.
// !!! a keyframe may never come, so give up after 30 frames
DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe")));
m_nWaitForKey = 30;
// if this fails, playback will stop, so signal an error
} else {
// Must release the sample before calling AbortPlayback
// because we might be holding the win16 lock or
// ddraw lock
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -