📄 winctrl.cpp
字号:
if (FAILED(hr)) {
return hr;
}
return OnUpdateRectangles();
}
// Return the left position for the destination rectangle
STDMETHODIMP CBaseControlVideo::get_DestinationLeft(long *pDestinationLeft)
{
CheckPointer(pDestinationLeft,E_POINTER);
CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
CAutoLock cInterfaceLock(m_pInterfaceLock);
RECT DestinationRect;
GetTargetRect(&DestinationRect);
*pDestinationLeft = DestinationRect.left;
return NOERROR;
}
// Set the destination width
STDMETHODIMP CBaseControlVideo::put_DestinationWidth(long DestinationWidth)
{
CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
CAutoLock cInterfaceLock(m_pInterfaceLock);
RECT DestinationRect;
GetTargetRect(&DestinationRect);
DestinationRect.right = DestinationRect.left + DestinationWidth;
// Check the target rectangle is valid
HRESULT hr = CheckTargetRect(&DestinationRect);
if (FAILED(hr)) {
return hr;
}
// Now set the new target rectangle
hr = SetTargetRect(&DestinationRect);
if (FAILED(hr)) {
return hr;
}
return OnUpdateRectangles();
}
// Return the width for the destination rectangle
STDMETHODIMP CBaseControlVideo::get_DestinationWidth(long *pDestinationWidth)
{
CheckPointer(pDestinationWidth,E_POINTER);
CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
CAutoLock cInterfaceLock(m_pInterfaceLock);
RECT DestinationRect;
GetTargetRect(&DestinationRect);
*pDestinationWidth = WIDTH(&DestinationRect);
return NOERROR;
}
// Set the target top position - changing this property does not affect the
// current target height. So changing this shunts the target rectangle up and
// down appropriately. Changing the height complements this functionality by
// keeping the top position constant and simply changing the target height
STDMETHODIMP CBaseControlVideo::put_DestinationTop(long DestinationTop)
{
CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
CAutoLock cInterfaceLock(m_pInterfaceLock);
RECT DestinationRect;
GetTargetRect(&DestinationRect);
DestinationRect.bottom = DestinationTop + HEIGHT(&DestinationRect);
DestinationRect.top = DestinationTop;
// Check the target rectangle is valid
HRESULT hr = CheckTargetRect(&DestinationRect);
if (FAILED(hr)) {
return hr;
}
// Now set the new target rectangle
hr = SetTargetRect(&DestinationRect);
if (FAILED(hr)) {
return hr;
}
return OnUpdateRectangles();
}
// Return the top position for the destination rectangle
STDMETHODIMP CBaseControlVideo::get_DestinationTop(long *pDestinationTop)
{
CheckPointer(pDestinationTop,E_POINTER);
CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
CAutoLock cInterfaceLock(m_pInterfaceLock);
RECT DestinationRect;
GetTargetRect(&DestinationRect);
*pDestinationTop = DestinationRect.top;
return NOERROR;
}
// Set the destination height
STDMETHODIMP CBaseControlVideo::put_DestinationHeight(long DestinationHeight)
{
CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
CAutoLock cInterfaceLock(m_pInterfaceLock);
RECT DestinationRect;
GetTargetRect(&DestinationRect);
DestinationRect.bottom = DestinationRect.top + DestinationHeight;
// Check the target rectangle is valid
HRESULT hr = CheckTargetRect(&DestinationRect);
if (FAILED(hr)) {
return hr;
}
// Now set the new target rectangle
hr = SetTargetRect(&DestinationRect);
if (FAILED(hr)) {
return hr;
}
return OnUpdateRectangles();
}
// Return the height for the destination rectangle
STDMETHODIMP CBaseControlVideo::get_DestinationHeight(long *pDestinationHeight)
{
CheckPointer(pDestinationHeight,E_POINTER);
CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
CAutoLock cInterfaceLock(m_pInterfaceLock);
RECT DestinationRect;
GetTargetRect(&DestinationRect);
*pDestinationHeight = HEIGHT(&DestinationRect);
return NOERROR;
}
// Reset the source rectangle to the full video dimensions
STDMETHODIMP CBaseControlVideo::SetDefaultSourcePosition()
{
CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
CAutoLock cInterfaceLock(m_pInterfaceLock);
HRESULT hr = SetDefaultSourceRect();
if (FAILED(hr)) {
return hr;
}
return OnUpdateRectangles();
}
// Return S_OK if we're using the default source otherwise S_FALSE
STDMETHODIMP CBaseControlVideo::IsUsingDefaultSource()
{
CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
CAutoLock cInterfaceLock(m_pInterfaceLock);
return IsDefaultSourceRect();
}
// Reset the video renderer to use the entire playback area
STDMETHODIMP CBaseControlVideo::SetDefaultDestinationPosition()
{
CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
CAutoLock cInterfaceLock(m_pInterfaceLock);
HRESULT hr = SetDefaultTargetRect();
if (FAILED(hr)) {
return hr;
}
return OnUpdateRectangles();
}
// Return S_OK if we're using the default target otherwise S_FALSE
STDMETHODIMP CBaseControlVideo::IsUsingDefaultDestination()
{
CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
CAutoLock cInterfaceLock(m_pInterfaceLock);
return IsDefaultTargetRect();
}
// Return a copy of the current image in the video renderer
STDMETHODIMP
CBaseControlVideo::GetCurrentImage(long *pBufferSize,long *pVideoImage)
{
CheckPointer(pBufferSize,E_POINTER);
CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
CAutoLock cInterfaceLock(m_pInterfaceLock);
FILTER_STATE State;
// Make sure we are in a paused state
if (pVideoImage != NULL) {
m_pFilter->GetState(0,&State);
if (State != State_Paused) {
return VFW_E_NOT_PAUSED;
}
return GetStaticImage(pBufferSize,pVideoImage);
}
// Just return the memory required
VIDEOINFOHEADER *pVideoInfo = GetVideoFormat();
if (pVideoInfo == NULL)
return E_OUTOFMEMORY;
RECT SourceRect;
GetSourceRect(&SourceRect);
return GetImageSize(pVideoInfo,pBufferSize,&SourceRect);
}
// An application has two ways of using GetCurrentImage, one is to pass a real
// buffer which should be filled with the current image. The other is to pass
// a NULL buffer pointer which is interpreted as asking us to return how much
// memory is required for the image. The constraints for when the latter can
// be called are much looser. To calculate the memory required we synthesize
// a VIDEOINFO that takes into account the source rectangle that's being used
HRESULT CBaseControlVideo::GetImageSize(VIDEOINFOHEADER *pVideoInfo,
LONG *pBufferSize,
RECT *pSourceRect)
{
NOTE("Entering GetImageSize");
ASSERT(pSourceRect);
// Check we have the correct input parameters
if (pSourceRect == NULL ||
pVideoInfo == NULL ||
pBufferSize == NULL) {
return E_UNEXPECTED;
}
// Is the data format compatible
if (pVideoInfo->bmiHeader.biCompression != BI_RGB) {
if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) {
return E_INVALIDARG;
}
}
ASSERT(IsRectEmpty(pSourceRect) == FALSE);
BITMAPINFOHEADER bih;
bih.biWidth = WIDTH(pSourceRect);
bih.biHeight = HEIGHT(pSourceRect);
bih.biBitCount = pVideoInfo->bmiHeader.biBitCount;
LONG Size = DIBSIZE(bih);
Size += GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER;
*pBufferSize = Size;
return NOERROR;
}
// Given an IMediaSample containing a linear buffer with an image and a type
// describing the bitmap make a rendering of the image into the output buffer
// This may be called by derived classes who render typical video images to
// handle the IBasicVideo GetCurrentImage method. The pVideoImage pointer may
// be NULL when passed to GetCurrentImage in which case GetImageSize will be
// called instead, which will just do the calculation of the memory required
HRESULT CBaseControlVideo::CopyImage(IMediaSample *pMediaSample,
VIDEOINFOHEADER *pVideoInfo,
LONG *pBufferSize,
BYTE *pVideoImage,
RECT *pSourceRect)
{
NOTE("Entering CopyImage");
ASSERT(pSourceRect);
BYTE *pCurrentImage;
// Check we have an image to copy
if (pMediaSample == NULL || pSourceRect == NULL ||
pVideoInfo == NULL || pVideoImage == NULL ||
pBufferSize == NULL) {
return E_UNEXPECTED;
}
// Is the data format compatible
if (pVideoInfo->bmiHeader.biCompression != BI_RGB) {
if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) {
return E_INVALIDARG;
}
}
ASSERT(IsRectEmpty(pSourceRect) == FALSE);
BITMAPINFOHEADER bih;
bih.biWidth = WIDTH(pSourceRect);
bih.biHeight = HEIGHT(pSourceRect);
bih.biBitCount = pVideoInfo->bmiHeader.biBitCount;
LONG Size = GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER;
LONG Total = Size + DIBSIZE(bih);
// Make sure we have a large enough buffer
if (*pBufferSize < Total) {
return E_OUTOFMEMORY;
}
// Copy the BITMAPINFO
CopyMemory((PVOID)pVideoImage, (PVOID)&pVideoInfo->bmiHeader, Size);
((BITMAPINFOHEADER *)pVideoImage)->biWidth = WIDTH(pSourceRect);
((BITMAPINFOHEADER *)pVideoImage)->biHeight = HEIGHT(pSourceRect);
((BITMAPINFOHEADER *)pVideoImage)->biSizeImage = DIBSIZE(bih);
BYTE *pImageData = pVideoImage + Size;
// Get the pointer to it's image data
HRESULT hr = pMediaSample->GetPointer(&pCurrentImage);
if (FAILED(hr)) {
return hr;
}
// Now we are ready to start copying the source scan lines
LONG ScanLine = (pVideoInfo->bmiHeader.biBitCount / 8) * WIDTH(pSourceRect);
LONG LinesToSkip = pVideoInfo->bmiHeader.biHeight;
LinesToSkip -= pSourceRect->top + HEIGHT(pSourceRect);
pCurrentImage += LinesToSkip * DIBWIDTHBYTES(pVideoInfo->bmiHeader);
pCurrentImage += pSourceRect->left * (pVideoInfo->bmiHeader.biBitCount / 8);
// Even money on this GP faulting sometime...
for (LONG Line = 0;Line < HEIGHT(pSourceRect);Line++) {
CopyMemory((PVOID)pImageData, (PVOID)pCurrentImage, ScanLine);
pImageData += DIBWIDTHBYTES(*(BITMAPINFOHEADER *)pVideoImage);
pCurrentImage += DIBWIDTHBYTES(pVideoInfo->bmiHeader);
}
return NOERROR;
}
// Called when we change media types either during connection or dynamically
// We inform the filter graph and therefore the application that the video
// size may have changed, we don't bother looking to see if it really has as
// we leave that to the application - the dimensions are the event parameters
HRESULT CBaseControlVideo::OnVideoSizeChange()
{
// Get the video format from the derived class
VIDEOINFOHEADER *pVideoInfo = GetVideoFormat();
if (pVideoInfo == NULL)
return E_OUTOFMEMORY;
WORD Width = (WORD) pVideoInfo->bmiHeader.biWidth;
WORD Height = (WORD) pVideoInfo->bmiHeader.biHeight;
return m_pFilter->NotifyEvent(EC_VIDEO_SIZE_CHANGED,
MAKELPARAM(Width,Height),
MAKEWPARAM(0,0));
}
// Set the video source rectangle. We must check the source rectangle against
// the actual video dimensions otherwise when we come to draw the pictures we
// get access violations as GDI tries to touch data outside of the image data
// Although we store the rectangle in left, top, right and bottom coordinates
// instead of left, top, width and height as OLE uses we do take into account
// that the rectangle is used up to, but not including, the right column and
// bottom row of pixels, see the Win32 documentation on RECT for more details
HRESULT CBaseControlVideo::CheckSourceRect(RECT *pSourceRect)
{
CheckPointer(pSourceRect,E_POINTER);
LONG Width,Height;
GetVideoSize(&Width,&Height);
// Check the coordinates are greater than zero
// and that the rectangle is valid (left<right, top<bottom)
if ((pSourceRect->left >= pSourceRect->right) ||
(pSourceRect->left
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -