123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- #if !defined(_WIN32_WCE)
- //------------------------------------------------------------------------------
- // File: PushSourceDesktop.cpp
- //
- // Desc: DirectShow sample code - In-memory push mode source filter
- // Provides an image of the user's desktop as a continuously updating stream.
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------------------------
- #include <streams.h>
- #include "DSPushSource.h"
- #include "DSDibHelper.h"
- #include "DSUtils.h"
- /**********************************************
- *
- * CPushPinDesktop Class
- *
- *
- **********************************************/
- CPushPinDesktop::CPushPinDesktop(HRESULT *phr, CSource *pFilter)
- : CSourceStream(NAME("Push Source Desktop"), phr, pFilter, L"Out"),
- m_FramesWritten(0),
- m_bZeroMemory(0),
- m_iFrameNumber(0),
- m_rtFrameLength(FPS_5), // Capture and display desktop 5 times per second
- m_nCurrentBitDepth(24),
- m_hSrcHwnd(NULL)
- {
- // The main point of this sample is to demonstrate how to take a DIB
- // in host memory and insert it into a video stream.
- // To keep this sample as simple as possible, we just read the desktop image
- // from a file and copy it into every frame that we send downstream.
- //
- // In the filter graph, we connect this filter to the AVI Mux, which creates
- // the AVI file with the video frames we pass to it. In this case,
- // the end result is a screen capture video (GDI images only, with no
- // support for overlay surfaces).
- // Get the device context of the main display
- HDC hDC;
- hDC = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
- // Get the dimensions of the main desktop window
- m_rScreen.left = m_rScreen.top = 0;
- m_rScreen.right = GetDeviceCaps(hDC, HORZRES);
- m_rScreen.bottom = GetDeviceCaps(hDC, VERTRES);
- // Save dimensions for later use in FillBuffer()
- m_iImageWidth = m_rScreen.right - m_rScreen.left;
- m_iImageHeight = m_rScreen.bottom - m_rScreen.top;
- // Release the device context
- DeleteDC(hDC);
- }
- CPushPinDesktop::~CPushPinDesktop()
- {
- DbgLog((LOG_TRACE, 3, TEXT("Frames written %d"), m_iFrameNumber));
- }
- //
- // GetMediaType
- //
- // Prefer 5 formats - 8, 16 (*2), 24 or 32 bits per pixel
- //
- // Prefered types should be ordered by quality, with zero as highest quality.
- // Therefore, iPosition =
- // 0 Return a 32bit mediatype
- // 1 Return a 24bit mediatype
- // 2 Return 16bit RGB565
- // 3 Return a 16bit mediatype (rgb555)
- // 4 Return 8 bit palettised format
- // >4 Invalid
- //
- HRESULT CPushPinDesktop::GetMediaType(int iPosition, CMediaType *pmt)
- {
- CheckPointer(pmt,E_POINTER);
- CAutoLock cAutoLock(m_pFilter->pStateLock());
- if(iPosition < 0) {
- return E_INVALIDARG;
- }
- // Have we run off the end of types?
- if(iPosition > 4) {
- return VFW_S_NO_MORE_ITEMS;
- }
- VIDEOINFO *pvi = (VIDEOINFO *) pmt->AllocFormatBuffer(sizeof(VIDEOINFO));
- if(NULL == pvi) {
- return(E_OUTOFMEMORY);
- }
- // Initialize the VideoInfo structure before configuring its members
- ZeroMemory(pvi, sizeof(VIDEOINFO));
- switch(iPosition) {
- case 0: {
- // Return our highest quality 32bit format
- // Since we use RGB888 (the default for 32 bit), there is
- // no reason to use BI_BITFIELDS to specify the RGB
- // masks. Also, not everything supports BI_BITFIELDS
- pvi->bmiHeader.biCompression = BI_RGB;
- pvi->bmiHeader.biBitCount = 32;
- break;
- }
- case 1: {
- // Return our 24bit format
- pvi->bmiHeader.biCompression = BI_RGB;
- pvi->bmiHeader.biBitCount = 24;
- break;
- }
- case 2: {
- // 16 bit per pixel RGB565
- // Place the RGB masks as the first 3 doublewords in the palette area
- for(int i = 0; i < 3; i++) {
- pvi->TrueColorInfo.dwBitMasks[i] = bits565[i];
- }
- pvi->bmiHeader.biCompression = BI_BITFIELDS;
- pvi->bmiHeader.biBitCount = 16;
- break;
- }
- case 3: {
- // 16 bits per pixel RGB555
- // Place the RGB masks as the first 3 doublewords in the palette area
- for(int i = 0; i < 3; i++) {
- pvi->TrueColorInfo.dwBitMasks[i] = bits555[i];
- }
- pvi->bmiHeader.biCompression = BI_BITFIELDS;
- pvi->bmiHeader.biBitCount = 16;
- break;
- }
- case 4: {
- // 8 bit palettised
- pvi->bmiHeader.biCompression = BI_RGB;
- pvi->bmiHeader.biBitCount = 8;
- pvi->bmiHeader.biClrUsed = iPALETTE_COLORS;
- break;
- }
- }
- // Adjust the parameters common to all formats
- pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- pvi->bmiHeader.biWidth = m_iImageWidth;
- pvi->bmiHeader.biHeight = m_iImageHeight;
- pvi->bmiHeader.biPlanes = 1;
- pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader);
- pvi->bmiHeader.biClrImportant = 0;
- SetRectEmpty(&(pvi->rcSource)); // we want the whole image area rendered.
- SetRectEmpty(&(pvi->rcTarget)); // no particular destination rectangle
- pmt->SetType(&MEDIATYPE_Video);
- pmt->SetFormatType(&FORMAT_VideoInfo);
- pmt->SetTemporalCompression(FALSE);
- // Work out the GUID for the subtype from the header info.
- const GUID SubTypeGUID = GetBitmapSubtype(&pvi->bmiHeader);
- pmt->SetSubtype(&SubTypeGUID);
- pmt->SetSampleSize(pvi->bmiHeader.biSizeImage);
- return NOERROR;
- } // GetMediaType
- //
- // CheckMediaType
- //
- // We will accept 8, 16, 24 or 32 bit video formats, in any
- // image size that gives room to bounce.
- // Returns E_INVALIDARG if the mediatype is not acceptable
- //
- HRESULT CPushPinDesktop::CheckMediaType(const CMediaType *pMediaType)
- {
- CheckPointer(pMediaType,E_POINTER);
- if((*(pMediaType->Type()) != MEDIATYPE_Video) || // we only output video
- !(pMediaType->IsFixedSize())) { // in fixed size samples
- return E_INVALIDARG;
- }
- // Check for the subtypes we support
- const GUID *SubType = pMediaType->Subtype();
- if (SubType == NULL) {
- return E_INVALIDARG;
- }
- if( (*SubType != MEDIASUBTYPE_RGB24)
- #if 0
- && (*SubType != MEDIASUBTYPE_RGB565)
- && (*SubType != MEDIASUBTYPE_RGB555)
- && (*SubType != MEDIASUBTYPE_RGB32)
- && (*SubType != MEDIASUBTYPE_RGB8)
- #endif
- ) {
- return E_INVALIDARG;
- }
- // Get the format area of the media type
- VIDEOINFO *pvi = (VIDEOINFO *) pMediaType->Format();
- if(pvi == NULL) {
- return E_INVALIDARG;
- }
- // Check if the image width & height have changed
- if( pvi->bmiHeader.biWidth != m_iImageWidth ||
- abs(pvi->bmiHeader.biHeight) != m_iImageHeight) {
- // If the image width/height is changed, fail CheckMediaType() to force
- // the renderer to resize the image.
- return E_INVALIDARG;
- }
- // Don't accept formats with negative height, which would cause the desktop
- // image to be displayed upside down.
- if (pvi->bmiHeader.biHeight < 0) {
- return E_INVALIDARG;
- }
- return S_OK; // This format is acceptable.
- } // CheckMediaType
- //
- // DecideBufferSize
- //
- // This will always be called after the format has been sucessfully
- // negotiated. So we have a look at m_mt to see what size image we agreed.
- // Then we can ask for buffers of the correct size to contain them.
- //
- HRESULT CPushPinDesktop::DecideBufferSize(IMemAllocator *pAlloc,
- ALLOCATOR_PROPERTIES *pProperties)
- {
- CheckPointer(pAlloc,E_POINTER);
- CheckPointer(pProperties,E_POINTER);
- CAutoLock cAutoLock(m_pFilter->pStateLock());
- HRESULT hr = NOERROR;
- VIDEOINFO *pvi = (VIDEOINFO *) m_mt.Format();
- pProperties->cBuffers = 1;
- pProperties->cbBuffer = pvi->bmiHeader.biSizeImage;
- ASSERT(pProperties->cbBuffer);
- // Ask the allocator to reserve us some sample memory. NOTE: the function
- // can succeed (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 = pAlloc->SetProperties(pProperties,&Actual);
- if(FAILED(hr)) {
- return hr;
- }
- // Is this allocator unsuitable?
- if(Actual.cbBuffer < pProperties->cbBuffer) {
- return E_FAIL;
- }
- // Make sure that we have only 1 buffer (we erase the ball in the
- // old buffer to save having to zero a 200k+ buffer every time
- // we draw a frame)
- ASSERT(Actual.cBuffers == 1);
- return NOERROR;
- } // DecideBufferSize
- //
- // SetMediaType
- //
- // Called when a media type is agreed between filters
- //
- HRESULT CPushPinDesktop::SetMediaType(const CMediaType *pMediaType)
- {
- CAutoLock cAutoLock(m_pFilter->pStateLock());
- // Pass the call up to my base class
- HRESULT hr = CSourceStream::SetMediaType(pMediaType);
- if(SUCCEEDED(hr)) {
- VIDEOINFO * pvi = (VIDEOINFO *) m_mt.Format();
- if (pvi == NULL) {
- return E_UNEXPECTED;
- }
- switch(pvi->bmiHeader.biBitCount) {
- case 8: // 8-bit palettized
- case 16: // RGB565, RGB555
- case 24: // RGB24
- case 32: // RGB32
- // Save the current media type and bit depth
- m_MediaType = *pMediaType;
- m_nCurrentBitDepth = pvi->bmiHeader.biBitCount;
- hr = S_OK;
- break;
- default:
- // We should never agree any other media types
- ASSERT(FALSE);
- hr = E_INVALIDARG;
- break;
- }
- }
- return hr;
- } // SetMediaType
- // This is where we insert the DIB bits into the video stream.
- // FillBuffer is called once for every sample in the stream.
- HRESULT CPushPinDesktop::FillBuffer(IMediaSample *pSample)
- {
- BYTE *pData;
- long cbData;
- CheckPointer(pSample, E_POINTER);
- CAutoLock cAutoLockShared(&m_cSharedState);
- // Access the sample's data buffer
- pSample->GetPointer(&pData);
- cbData = pSample->GetSize();
- // Check that we're still using video
- ASSERT(m_mt.formattype == FORMAT_VideoInfo);
- VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)m_mt.pbFormat;
- // Copy the DIB bits over into our filter's output buffer.
- // Since sample size may be larger than the image size, bound the copy size.
- int nSize = min(pVih->bmiHeader.biSizeImage, (DWORD) cbData);
- HDIB hDib = CopyScreenToBitmap(&m_rScreen, pData, (BITMAPINFO *) &(pVih->bmiHeader));
- if (hDib) {
- DeleteObject(hDib);
- }
- // Set the timestamps that will govern playback frame rate.
- // If this file is getting written out as an AVI,
- // then you'll also need to configure the AVI Mux filter to
- // set the Average Time Per Frame for the AVI Header.
- // The current time is the sample's start.
- REFERENCE_TIME rtStart = m_iFrameNumber * m_rtFrameLength;
- REFERENCE_TIME rtStop = rtStart + m_rtFrameLength;
- pSample->SetTime(&rtStart, &rtStop);
- m_iFrameNumber++;
- // Set TRUE on every sample for uncompressed frames
- pSample->SetSyncPoint(TRUE);
- return S_OK;
- }
- /**********************************************
- *
- * CPushSourceDesktop Class
- *
- **********************************************/
- CPushSourceDesktop::CPushSourceDesktop(IUnknown *pUnk, HRESULT *phr)
- : CSource(NAME("PushSourceDesktop"), pUnk, CLSID_PushSourceDesktop)
- {
- // The pin magically adds itself to our pin array.
- m_pPin = new CPushPinDesktop(phr, this);
- if (phr) {
- if (m_pPin == NULL) {
- *phr = E_OUTOFMEMORY;
- }
- else {
- *phr = S_OK;
- }
- }
- }
- CPushSourceDesktop::~CPushSourceDesktop()
- {
- if (m_pPin) {
- delete m_pPin;
- m_pPin = NULL;
- }
- }
- CUnknown * WINAPI CPushSourceDesktop::CreateInstance(IUnknown *pUnk, HRESULT *phr)
- {
- CPushSourceDesktop *pNewFilter = new CPushSourceDesktop(pUnk, phr );
- if (phr) {
- if (pNewFilter == NULL) {
- *phr = E_OUTOFMEMORY;
- }
- else {
- *phr = S_OK;
- }
- }
- return pNewFilter;
- }
- HRESULT CPushSourceDesktop::SetSrcHwnd(HWND hWnd)
- {
- if (m_pPin) {
- return m_pPin->SetSrcHwnd(hWnd);
- }
- return E_FAIL;
- }
- #endif /* _WIN32_WCE */
|