home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Game Programming for Teens / VBGPFT.cdr / DirectX8 / dx8a_sdk.exe / samples / multimedia / directshow / dmo / dmosample / sample.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-02  |  12.9 KB  |  394 lines

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