home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / DMO / DMOSample / sample.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  12.9 KB  |  396 lines

  1. //------------------------------------------------------------------------------
  2. // File: Sample.cpp
  3. //
  4. // Desc: DirectShow sample code - implementation of CSample class.
  5. //
  6. // Copyright (c) 2000-2001 Microsoft Corporation.  All rights reserved.
  7. //------------------------------------------------------------------------------
  8.  
  9.  
  10. #include "stdafx.h"
  11.  
  12. #define FIX_LOCK_NAME
  13. #include <dmo.h>
  14.  
  15. #include <limits.h>     //  _I64_MAX
  16. #include <crtdbg.h>
  17. #include <dmoimpl.h>
  18. #include <uuids.h>      // DirectShow media type guids
  19. #include <amvideo.h>    // VIDEOINFOHEADER definition
  20. #include "resource.h"
  21. #include "state.h"
  22. #include "Sample.h"
  23. #include "util.h"       // Helpers
  24.  
  25. #pragma warning(disable:4100)  // Disable C4100: unreferenced formal parameter
  26.  
  27.  
  28. HRESULT CSample::InternalGetInputStreamInfo(DWORD dwInputStreamIndex, DWORD *pdwFlags)
  29. {
  30.     //  We can process data on any boundary
  31.     *pdwFlags = 0;
  32.     return S_OK;
  33. }
  34.  
  35. HRESULT CSample::InternalGetOutputStreamInfo(DWORD dwOutputStreamIndex, DWORD *pdwFlags)
  36. {
  37.     //  We output single frames
  38.     if (0 == dwOutputStreamIndex) {
  39.         *pdwFlags = DMO_OUTPUT_STREAMF_WHOLE_SAMPLES |
  40.                     DMO_OUTPUT_STREAMF_SINGLE_SAMPLE_PER_BUFFER |
  41.                     DMO_OUTPUT_STREAMF_FIXED_SAMPLE_SIZE;
  42.     } else {
  43.         //  Stream 1
  44.         //  Just text, no special buffering but 1 sample per sample
  45.         *pdwFlags = DMO_OUTPUT_STREAMF_SINGLE_SAMPLE_PER_BUFFER |
  46.                     DMO_OUTPUT_STREAMF_OPTIONAL;
  47.     }
  48.     return S_OK;
  49. }
  50.  
  51. HRESULT CSample::InternalCheckInputType(DWORD dwInputStreamIndex, const DMO_MEDIA_TYPE *pmt)
  52. {
  53.     //  Check if the type is already set and if so reject any type that's not identical
  54.     if (InputTypeSet(dwInputStreamIndex)) {
  55.         if (!TypesMatch(pmt, InputType(dwInputStreamIndex))) {
  56.             return DMO_E_INVALIDTYPE;
  57.         } else {
  58.             return S_OK;
  59.         }
  60.     }
  61.     
  62.     //  We accept MEDIATYPE_Video, MEDIASUBTYPE_MPEG1Video
  63.     //  Check the format is defined
  64.     if (pmt->majortype == MEDIATYPE_Video &&
  65.         pmt->subtype == MEDIASUBTYPE_MPEG1Payload &&
  66.         pmt->formattype == FORMAT_MPEGVideo &&
  67.         pmt->pbFormat != NULL) {
  68.         return S_OK;
  69.     } else {
  70.         return DMO_E_INVALIDTYPE;
  71.     }
  72. }
  73.  
  74. HRESULT CSample::InternalCheckOutputType(DWORD dwOutputStreamIndex, const DMO_MEDIA_TYPE *pmt)
  75. {
  76.     //  Check if the type is already set and if so reject any type that's not identical
  77.     if (OutputTypeSet(dwOutputStreamIndex)) {
  78.         if (!TypesMatch(pmt, OutputType(dwOutputStreamIndex))) {
  79.             return DMO_E_INVALIDTYPE;
  80.         } else {
  81.             return S_OK;
  82.         }
  83.     }
  84.     //  We output frames on stream 1
  85.     if (dwOutputStreamIndex == 0) {
  86.         if (!InputTypeSet(0)) {
  87.             return DMO_E_INVALIDTYPE;
  88.         }
  89.         if (pmt->majortype == MEDIATYPE_Video &&
  90.             pmt->subtype == MEDIASUBTYPE_RGB565 &&
  91.             pmt->formattype == FORMAT_VideoInfo &&
  92.             pmt->pbFormat != NULL) {
  93.             const VIDEOINFOHEADER *pvihInput = (const VIDEOINFOHEADER *)InputType(0)->pbFormat;
  94.             const VIDEOINFOHEADER *pvihOutput = (const VIDEOINFOHEADER *)pmt->pbFormat;
  95.  
  96.             LONG lWidth, lHeight;
  97.             if (IsRectEmpty(&pvihOutput->rcTarget)) {
  98.                 lWidth = pvihOutput->bmiHeader.biWidth;
  99.                 lHeight = pvihOutput->bmiHeader.biHeight;
  100.             } else {
  101.                 lWidth = pvihOutput->rcTarget.right - pvihOutput->rcTarget.left;
  102.                 lHeight = pvihOutput->rcTarget.bottom - pvihOutput->rcTarget.top;
  103.             }
  104.             if (pvihInput->bmiHeader.biWidth == lWidth &&
  105.                 pvihInput->bmiHeader.biHeight == lHeight) {
  106.                 return S_OK;
  107.             }
  108.         }
  109.         return DMO_E_INVALIDTYPE;
  110.     } else {
  111.         //  Stream 1
  112.         if (pmt->majortype == MEDIATYPE_Text && pmt->subtype == GUID_NULL) {
  113.             return S_OK;
  114.         } else {
  115.             return DMO_E_INVALIDTYPE;
  116.         }
  117.     }
  118. }
  119.  
  120.  
  121. HRESULT CSample::InternalGetInputType(DWORD dwInputStreamIndex, DWORD dwTypeIndex,
  122.                              DMO_MEDIA_TYPE *pmt)
  123. {
  124.     //  No types to all indices for dwTypeIndex are out of range.
  125.     return DMO_E_NO_MORE_ITEMS;
  126. }
  127.  
  128. HRESULT CSample::InternalGetOutputType(DWORD dwOutputStreamIndex, DWORD dwTypeIndex,
  129.                              DMO_MEDIA_TYPE *pmt)
  130. {
  131.     if (!InputTypeSet(0)) {
  132.         return DMO_E_TYPE_NOT_SET;
  133.     }
  134.  
  135.     if (dwTypeIndex != 0) {
  136.         return DMO_E_NO_MORE_ITEMS;
  137.     }
  138.  
  139.     // If GetOutputType()'s pmt parameter is NULL, return S_OK if the type exists.
  140.     // Return DMO_E_NO_MORE_ITEMS if the type does not exists.  See the 
  141.     // documentation for IMediaObject::GetOutputType() for more information.
  142.     if (NULL != pmt) {
  143.         if (dwOutputStreamIndex == 0) {
  144.  
  145.             //  Create our media type
  146.             HRESULT hr = MoInitMediaType(pmt, FIELD_OFFSET(VIDEOINFO, dwBitMasks[3]));
  147.             if (FAILED(hr)) {
  148.                 return hr;
  149.             }
  150.  
  151.             const VIDEOINFOHEADER *pvihInput = (const VIDEOINFOHEADER *)InputType(0)->pbFormat;
  152.             LONG lWidth  = pvihInput->bmiHeader.biWidth;
  153.             LONG lHeight = pvihInput->bmiHeader.biHeight;
  154.  
  155.             //  Initialize the media type structure (MoInitMediaType initalized cbFormat
  156.             //  and pbFormat)
  157.             pmt->majortype            = MEDIATYPE_Video;
  158.             pmt->subtype              = MEDIASUBTYPE_RGB565;
  159.             pmt->bFixedSizeSamples    = TRUE;
  160.             pmt->bTemporalCompression = FALSE;
  161.             pmt->lSampleSize          = lWidth * lHeight * 2;
  162.             pmt->formattype           = FORMAT_VideoInfo;
  163.             pmt->pUnk                 = NULL;
  164.             
  165.             //  Initialize the format
  166.             VIDEOINFO *pviOutput = (VIDEOINFO *)pmt->pbFormat;
  167.             ZeroMemory(pviOutput, FIELD_OFFSET(VIDEOINFO, dwBitMasks[3]));
  168.             pviOutput->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  169.             pviOutput->bmiHeader.biCompression = BI_BITFIELDS;
  170.             pviOutput->bmiHeader.biBitCount = 16;
  171.             pviOutput->bmiHeader.biPlanes = 1;
  172.             pviOutput->bmiHeader.biWidth = lWidth;
  173.             pviOutput->bmiHeader.biHeight = lHeight;
  174.             pviOutput->bmiHeader.biSizeImage = pmt->lSampleSize;
  175.             pviOutput->TrueColorInfo.dwBitMasks[0] = 0xF800;
  176.             pviOutput->TrueColorInfo.dwBitMasks[1] = 0x07E0;
  177.             pviOutput->TrueColorInfo.dwBitMasks[2] = 0x001F;
  178.             pviOutput->AvgTimePerFrame = pvihInput->AvgTimePerFrame;
  179.         } else {
  180.             ZeroMemory(pmt, sizeof(*pmt));
  181.             pmt->majortype            = MEDIATYPE_Text;
  182.         }
  183.     }
  184.  
  185.     return S_OK;
  186. }
  187. HRESULT CSample::InternalGetInputSizeInfo(DWORD dwInputStreamIndex, DWORD *pcbSize,
  188.                              DWORD *pcbMaxLookahead, DWORD *pcbAlignment)
  189. {
  190.     *pcbSize = 1;
  191.     *pcbMaxLookahead = 0;
  192.     *pcbAlignment = 1;
  193.     return S_OK;
  194. }
  195. HRESULT CSample::InternalGetOutputSizeInfo(DWORD dwOutputStreamIndex, DWORD *pcbSize,
  196.                               DWORD *pcbAlignment)
  197. {
  198.     *pcbAlignment = 1;
  199.     if (dwOutputStreamIndex == 0) {
  200.         *pcbSize = OutputType(0)->lSampleSize;
  201.         return S_OK;
  202.     } else {
  203.         *pcbSize = sizeof(L"hh:mm:ss:ff"); //  hh:mm:ss:ff
  204.         return S_OK;
  205.     }
  206. }
  207. HRESULT CSample::InternalGetInputMaxLatency(DWORD dwInputStreamIndex, REFERENCE_TIME *prtMaxLatency)
  208. {
  209.     return E_NOTIMPL;
  210. }
  211. HRESULT CSample::InternalSetInputMaxLatency(DWORD dwInputStreamIndex, REFERENCE_TIME rtMaxLatency)
  212. {
  213.     return E_NOTIMPL;
  214. }
  215. HRESULT CSample::InternalFlush()
  216. {
  217.     InternalDiscontinuity(0);
  218.  
  219.     //  Release buffer
  220.     m_pBuffer = NULL;
  221.  
  222.     return S_OK;
  223. }
  224. HRESULT CSample::InternalDiscontinuity(DWORD dwInputStreamIndex)
  225. {
  226.     //  Zero our timestamp
  227.     m_rtFrame = 0;
  228.  
  229.     //  No pictures yet
  230.    m_bPicture   = false;
  231.  
  232.    //  Reset state machine
  233.    m_StreamState.Reset();
  234.     return S_OK;
  235. }
  236. HRESULT CSample::InternalAllocateStreamingResources()
  237. {
  238.     //  Reinitialize variables
  239.     InternalDiscontinuity(0);
  240.  
  241.     //  Allocate our bitmap
  242.     return S_OK;
  243. }
  244. HRESULT CSample::InternalFreeStreamingResources()
  245. {
  246.     return S_OK;
  247. }
  248. HRESULT CSample::InternalProcessInput(DWORD dwInputStreamIndex, IMediaBuffer *pBuffer,
  249.                                 DWORD dwFlags, REFERENCE_TIME rtTimestamp,
  250.                                 REFERENCE_TIME rtTimelength)
  251. {
  252.     //  Check parameters
  253.     _ASSERTE(m_pBuffer == NULL);
  254.     HRESULT hr = pBuffer->GetBufferAndLength(&m_pbData, &m_cbData);
  255.     if (FAILED(hr)) {
  256.         return hr;
  257.     }
  258.     m_pBuffer        = pBuffer;
  259.  
  260.     if (0 == (dwFlags & DMO_INPUT_DATA_BUFFERF_TIME)) {
  261.         rtTimestamp = INVALID_TIME;
  262.     }
  263.  
  264.     m_StreamState.TimeStamp(rtTimestamp);
  265.  
  266.     //  Process() returns S_FALSE if there is no output, S_OK otherwise
  267.     hr = Process();
  268.     return hr;
  269. }
  270.  
  271. HRESULT CSample::InternalProcessOutput(DWORD dwFlags,
  272.                                        DWORD cOutputBufferCount,
  273.                                        DMO_OUTPUT_DATA_BUFFER *pOutputBuffers,
  274.                                        DWORD *pdwStatus)
  275. {
  276.     //  Check buffer
  277.     PBYTE pbData;
  278.     DWORD cbData;
  279.     DWORD cbCurrent;
  280.  
  281.     //  Do we have any output?
  282.     if (!m_bPicture) {
  283.         return S_FALSE;
  284.     }
  285.     HRESULT hr = pOutputBuffers[0].pBuffer->GetBufferAndLength(
  286.                        &pbData, &cbCurrent);
  287.     if (FAILED(hr)) {
  288.         return hr;
  289.     }
  290.     hr = pOutputBuffers[0].pBuffer->GetMaxLength(&cbData);
  291.     if (FAILED(hr)) {
  292.         return hr;
  293.     }
  294.  
  295.     if (cbData < cbCurrent + (DWORD)OutputType(0)->lSampleSize) {
  296.         return E_INVALIDARG;
  297.     }
  298.  
  299.     //  Say we've filled the buffer
  300.     hr = pOutputBuffers[0].pBuffer->SetLength(cbCurrent + (DWORD)OutputType(0)->lSampleSize);
  301.  
  302.     cbData -= cbCurrent;
  303.     pbData += cbCurrent;
  304.  
  305.     //  Generate our data
  306.     DWORD dwTimeCode;
  307.     REFERENCE_TIME rt = m_StreamState.PictureTime(&dwTimeCode);
  308.     TCHAR szBuffer[20];
  309.     wsprintf(szBuffer, TEXT("%2.2d:%2.2d:%2.2d:%2.2d"),
  310.              (dwTimeCode >> 19) & 0x1F,
  311.              (dwTimeCode >> 13) & 0x3F,
  312.              (dwTimeCode >> 6) & 0x3F,
  313.              dwTimeCode & 0x3F);
  314.  
  315.     //  Update our bitmap with turquoise
  316.     OurFillRect((const VIDEOINFOHEADER *)OutputType(0)->pbFormat, pbData, 0x03EF);
  317.  
  318.     //  Draw our text
  319.     DrawOurText((const VIDEOINFOHEADER *)OutputType(0)->pbFormat, pbData, szBuffer);
  320.  
  321.     pOutputBuffers[0].dwStatus = DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT;
  322.  
  323.     //  Set the timestamp
  324.     if (rt != INVALID_TIME) {
  325.         pOutputBuffers[0].rtTimestamp = rt;
  326.  
  327.     } else {
  328.         pOutputBuffers[0].rtTimestamp = m_rtFrame;
  329.     }
  330.     REFERENCE_TIME rtLength = ((const VIDEOINFOHEADER *)OutputType(0)->pbFormat)->AvgTimePerFrame;
  331.     pOutputBuffers[0].rtTimelength = rtLength;
  332.     m_rtFrame = pOutputBuffers[0].rtTimestamp + rtLength;
  333.  
  334.     //  Uncompressed video must always have a timestamp
  335.     pOutputBuffers[0].dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIME | DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH;
  336.  
  337.     //  Update our state
  338.     m_bPicture = false;
  339.  
  340.     //  Is there any more data to output at this point?
  341.     if (S_OK == Process()) {
  342.         pOutputBuffers[0].dwStatus = DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE;
  343.     }
  344.  
  345.     //  Is there an output buffer for stream 1?
  346.     if (pOutputBuffers[1].pBuffer) {
  347.         PBYTE pbData;
  348.         DWORD cbLength;
  349.         DWORD cbMax;            
  350.         DWORD dwLen = lstrlen(szBuffer) * sizeof(WCHAR);
  351.         if (S_OK == pOutputBuffers[1].pBuffer->GetBufferAndLength(&pbData, &cbLength) &&
  352.             S_OK == pOutputBuffers[1].pBuffer->GetMaxLength(&cbMax) &&
  353.             cbLength + dwLen <= cbMax) {
  354.  
  355.             //  Convert to UNICODE!
  356.             USES_CONVERSION;
  357.             LPWSTR lpsz = T2W(szBuffer);
  358.  
  359.             CopyMemory(pbData + cbLength, lpsz, dwLen);
  360.             pOutputBuffers[1].pBuffer->SetLength(cbLength + dwLen);
  361.             pOutputBuffers[1].dwStatus = pOutputBuffers[0].dwStatus;
  362.             pOutputBuffers[1].rtTimestamp = pOutputBuffers[0].rtTimestamp;
  363.             pOutputBuffers[1].rtTimelength = rtLength;
  364.         }
  365.     }
  366.     return S_OK;
  367. }
  368. HRESULT CSample::InternalAcceptingInput(DWORD dwInputStreamIndex)
  369. {
  370.     return m_pBuffer == NULL ? S_OK : S_FALSE;
  371. }
  372.  
  373. //  Scan input data until either we're exhausted or we find
  374. //  a picture start code
  375. //  Note GOP time codes as we encounter them so we can
  376. //  output time codes
  377.  
  378. HRESULT CSample::Process()
  379. {
  380.     //  Process bytes and update our state machine
  381.     while (m_cbData && !m_bPicture) {
  382.         m_bPicture = m_StreamState.NextByte(*m_pbData);
  383.         m_cbData--;
  384.         m_pbData++;
  385.     }
  386.  
  387.     //  Release buffer if we're done with it
  388.     if (m_cbData == 0) {
  389.         m_pBuffer = NULL;
  390.     }
  391.  
  392.     //  assert that if have no picture to output then we ate all the data
  393.     _ASSERTE(m_bPicture || m_cbData == 0);
  394.     return m_bPicture ? S_OK : S_FALSE;
  395. }
  396.