Home | History | Annotate | Download | only in OcvTransform
      1 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
      2 // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
      3 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
      4 // PARTICULAR PURPOSE.
      5 //
      6 // Copyright (c) Microsoft Corporation. All rights reserved.
      7 
      8 #include "OcvTransform.h"
      9 #include "bufferlock.h"
     10 
     11 #include <opencv2\core\core.hpp>
     12 #include <opencv2\imgproc\imgproc.hpp>
     13 #include <opencv2\features2d\features2d.hpp>
     14 
     15 
     16 
     17 using namespace Microsoft::WRL;
     18 
     19 /*
     20 
     21 This sample implements a video effect as a Media Foundation transform (MFT).
     22 
     23 NOTES ON THE MFT IMPLEMENTATION
     24 
     25 1. The MFT has fixed streams: One input stream and one output stream.
     26 
     27 2. The MFT supports NV12 format only.
     28 
     29 3. If the MFT is holding an input sample, SetInputType and SetOutputType both fail.
     30 
     31 4. The input and output types must be identical.
     32 
     33 5. If both types are set, no type can be set until the current type is cleared.
     34 
     35 6. Preferred input types:
     36 
     37      (a) If the output type is set, that's the preferred type.
     38      (b) Otherwise, the preferred types are partial types, constructed from the
     39          list of supported subtypes.
     40 
     41 7. Preferred output types: As above.
     42 
     43 8. Streaming:
     44 
     45     The private BeingStreaming() method is called in response to the
     46     MFT_MESSAGE_NOTIFY_BEGIN_STREAMING message.
     47 
     48     If the client does not send MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, the MFT calls
     49     BeginStreaming inside the first call to ProcessInput or ProcessOutput.
     50 
     51     This is a good approach for allocating resources that your MFT requires for
     52     streaming.
     53 
     54 9. The configuration attributes are applied in the BeginStreaming method. If the
     55    client changes the attributes during streaming, the change is ignored until
     56    streaming is stopped (either by changing the media types or by sending the
     57    MFT_MESSAGE_NOTIFY_END_STREAMING message) and then restarted.
     58 
     59 */
     60 
     61 
     62 // Static array of media types (preferred and accepted).
     63 const GUID g_MediaSubtypes[] =
     64 {
     65     MFVideoFormat_NV12
     66 };
     67 
     68 HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride);
     69 
     70 template <typename T>
     71 inline T clamp(const T& val, const T& minVal, const T& maxVal)
     72 {
     73     return (val < minVal ? minVal : (val > maxVal ? maxVal : val));
     74 }
     75 
     76 OcvImageManipulations::OcvImageManipulations() :
     77     m_pSample(NULL), m_pInputType(NULL), m_pOutputType(NULL),
     78     m_imageWidthInPixels(0), m_imageHeightInPixels(0), m_cbImageSize(0),
     79     m_TransformType(Preview), m_bStreamingInitialized(false),
     80     m_pAttributes(NULL)
     81 {
     82     InitializeCriticalSectionEx(&m_critSec, 3000, 0);
     83 }
     84 
     85 OcvImageManipulations::~OcvImageManipulations()
     86 {
     87     SafeRelease(&m_pInputType);
     88     SafeRelease(&m_pOutputType);
     89     SafeRelease(&m_pSample);
     90     SafeRelease(&m_pAttributes);
     91     DeleteCriticalSection(&m_critSec);
     92 }
     93 
     94 // Initialize the instance.
     95 STDMETHODIMP OcvImageManipulations::RuntimeClassInitialize()
     96 {
     97     // Create the attribute store.
     98     return MFCreateAttributes(&m_pAttributes, 3);
     99 }
    100 
    101 // IMediaExtension methods
    102 
    103 //-------------------------------------------------------------------
    104 // SetProperties
    105 // Sets the configuration of the effect
    106 //-------------------------------------------------------------------
    107 HRESULT OcvImageManipulations::SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration)
    108 {
    109     HRESULT hr = S_OK;
    110 
    111     if (!pConfiguration)
    112         return hr;
    113 
    114     HSTRING key;
    115     WindowsCreateString(L"{698649BE-8EAE-4551-A4CB-3EC98FBD3D86}", 38, &key);
    116     Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable *>> spSetting;
    117     pConfiguration->QueryInterface(IID_PPV_ARGS(&spSetting));
    118     boolean found;
    119     spSetting->HasKey(key, &found);
    120 
    121     if (found)
    122     {
    123         Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValue> spPropVal;
    124         Microsoft::WRL::ComPtr<IInspectable> spInsp;
    125 
    126         spSetting->Lookup(key, spInsp.ReleaseAndGetAddressOf());
    127 
    128         hr = spInsp.As(&spPropVal);
    129         if (hr != S_OK)
    130         {
    131             return hr;
    132         }
    133 
    134         INT32 effect;
    135         hr = spPropVal->GetInt32(&effect);
    136         if (hr != S_OK)
    137         {
    138             return hr;
    139         }
    140 
    141         if ((effect >= 0) && (effect < InvalidEffect))
    142         {
    143             m_TransformType = (ProcessingType)effect;
    144         }
    145     }
    146 
    147     return hr;
    148 }
    149 
    150 // IMFTransform methods. Refer to the Media Foundation SDK documentation for details.
    151 
    152 //-------------------------------------------------------------------
    153 // GetStreamLimits
    154 // Returns the minimum and maximum number of streams.
    155 //-------------------------------------------------------------------
    156 
    157 HRESULT OcvImageManipulations::GetStreamLimits(
    158     DWORD   *pdwInputMinimum,
    159     DWORD   *pdwInputMaximum,
    160     DWORD   *pdwOutputMinimum,
    161     DWORD   *pdwOutputMaximum
    162 )
    163 {
    164     if ((pdwInputMinimum == NULL) ||
    165         (pdwInputMaximum == NULL) ||
    166         (pdwOutputMinimum == NULL) ||
    167         (pdwOutputMaximum == NULL))
    168     {
    169         return E_POINTER;
    170     }
    171 
    172     // This MFT has a fixed number of streams.
    173     *pdwInputMinimum = 1;
    174     *pdwInputMaximum = 1;
    175     *pdwOutputMinimum = 1;
    176     *pdwOutputMaximum = 1;
    177     return S_OK;
    178 }
    179 
    180 
    181 //-------------------------------------------------------------------
    182 // GetStreamCount
    183 // Returns the actual number of streams.
    184 //-------------------------------------------------------------------
    185 
    186 HRESULT OcvImageManipulations::GetStreamCount(
    187     DWORD   *pcInputStreams,
    188     DWORD   *pcOutputStreams
    189 )
    190 {
    191     if ((pcInputStreams == NULL) || (pcOutputStreams == NULL))
    192 
    193     {
    194         return E_POINTER;
    195     }
    196 
    197     // This MFT has a fixed number of streams.
    198     *pcInputStreams = 1;
    199     *pcOutputStreams = 1;
    200     return S_OK;
    201 }
    202 
    203 
    204 
    205 //-------------------------------------------------------------------
    206 // GetStreamIDs
    207 // Returns stream IDs for the input and output streams.
    208 //-------------------------------------------------------------------
    209 
    210 HRESULT OcvImageManipulations::GetStreamIDs(
    211     DWORD   dwInputIDArraySize,
    212     DWORD   *pdwInputIDs,
    213     DWORD   dwOutputIDArraySize,
    214     DWORD   *pdwOutputIDs
    215 )
    216 {
    217     // It is not required to implement this method if the MFT has a fixed number of
    218     // streams AND the stream IDs are numbered sequentially from zero (that is, the
    219     // stream IDs match the stream indexes).
    220 
    221     // In that case, it is OK to return E_NOTIMPL.
    222     return E_NOTIMPL;
    223 }
    224 
    225 
    226 //-------------------------------------------------------------------
    227 // GetInputStreamInfo
    228 // Returns information about an input stream.
    229 //-------------------------------------------------------------------
    230 
    231 HRESULT OcvImageManipulations::GetInputStreamInfo(
    232     DWORD                     dwInputStreamID,
    233     MFT_INPUT_STREAM_INFO *   pStreamInfo
    234 )
    235 {
    236     if (pStreamInfo == NULL)
    237     {
    238         return E_POINTER;
    239     }
    240 
    241     EnterCriticalSection(&m_critSec);
    242 
    243     if (!IsValidInputStream(dwInputStreamID))
    244     {
    245         LeaveCriticalSection(&m_critSec);
    246         return MF_E_INVALIDSTREAMNUMBER;
    247     }
    248 
    249     // NOTE: This method should succeed even when there is no media type on the
    250     //       stream. If there is no media type, we only need to fill in the dwFlags
    251     //       member of MFT_INPUT_STREAM_INFO. The other members depend on having a
    252     //       a valid media type.
    253 
    254     pStreamInfo->hnsMaxLatency = 0;
    255     pStreamInfo->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER;
    256 
    257     if (m_pInputType == NULL)
    258     {
    259         pStreamInfo->cbSize = 0;
    260     }
    261     else
    262     {
    263         pStreamInfo->cbSize = m_cbImageSize;
    264     }
    265 
    266     pStreamInfo->cbMaxLookahead = 0;
    267     pStreamInfo->cbAlignment = 0;
    268 
    269     LeaveCriticalSection(&m_critSec);
    270     return S_OK;
    271 }
    272 
    273 //-------------------------------------------------------------------
    274 // GetOutputStreamInfo
    275 // Returns information about an output stream.
    276 //-------------------------------------------------------------------
    277 
    278 HRESULT OcvImageManipulations::GetOutputStreamInfo(
    279     DWORD                     dwOutputStreamID,
    280     MFT_OUTPUT_STREAM_INFO *  pStreamInfo
    281 )
    282 {
    283     if (pStreamInfo == NULL)
    284     {
    285         return E_POINTER;
    286     }
    287 
    288     EnterCriticalSection(&m_critSec);
    289 
    290     if (!IsValidOutputStream(dwOutputStreamID))
    291     {
    292         LeaveCriticalSection(&m_critSec);
    293         return MF_E_INVALIDSTREAMNUMBER;
    294     }
    295 
    296     // NOTE: This method should succeed even when there is no media type on the
    297     //       stream. If there is no media type, we only need to fill in the dwFlags
    298     //       member of MFT_OUTPUT_STREAM_INFO. The other members depend on having a
    299     //       a valid media type.
    300 
    301     pStreamInfo->dwFlags =
    302         MFT_OUTPUT_STREAM_WHOLE_SAMPLES |
    303         MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
    304         MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE ;
    305 
    306     if (m_pOutputType == NULL)
    307     {
    308         pStreamInfo->cbSize = 0;
    309     }
    310     else
    311     {
    312         pStreamInfo->cbSize = m_cbImageSize;
    313     }
    314 
    315     pStreamInfo->cbAlignment = 0;
    316 
    317     LeaveCriticalSection(&m_critSec);
    318     return S_OK;
    319 }
    320 
    321 
    322 //-------------------------------------------------------------------
    323 // GetAttributes
    324 // Returns the attributes for the MFT.
    325 //-------------------------------------------------------------------
    326 
    327 HRESULT OcvImageManipulations::GetAttributes(IMFAttributes** ppAttributes)
    328 {
    329     if (ppAttributes == NULL)
    330     {
    331         return E_POINTER;
    332     }
    333 
    334     EnterCriticalSection(&m_critSec);
    335 
    336     *ppAttributes = m_pAttributes;
    337     (*ppAttributes)->AddRef();
    338 
    339     LeaveCriticalSection(&m_critSec);
    340     return S_OK;
    341 }
    342 
    343 
    344 //-------------------------------------------------------------------
    345 // GetInputStreamAttributes
    346 // Returns stream-level attributes for an input stream.
    347 //-------------------------------------------------------------------
    348 
    349 HRESULT OcvImageManipulations::GetInputStreamAttributes(
    350     DWORD           dwInputStreamID,
    351     IMFAttributes   **ppAttributes
    352 )
    353 {
    354     // This MFT does not support any stream-level attributes, so the method is not implemented.
    355     return E_NOTIMPL;
    356 }
    357 
    358 
    359 //-------------------------------------------------------------------
    360 // GetOutputStreamAttributes
    361 // Returns stream-level attributes for an output stream.
    362 //-------------------------------------------------------------------
    363 
    364 HRESULT OcvImageManipulations::GetOutputStreamAttributes(
    365     DWORD           dwOutputStreamID,
    366     IMFAttributes   **ppAttributes
    367 )
    368 {
    369     // This MFT does not support any stream-level attributes, so the method is not implemented.
    370     return E_NOTIMPL;
    371 }
    372 
    373 
    374 //-------------------------------------------------------------------
    375 // DeleteInputStream
    376 //-------------------------------------------------------------------
    377 
    378 HRESULT OcvImageManipulations::DeleteInputStream(DWORD dwStreamID)
    379 {
    380     // This MFT has a fixed number of input streams, so the method is not supported.
    381     return E_NOTIMPL;
    382 }
    383 
    384 
    385 //-------------------------------------------------------------------
    386 // AddInputStreams
    387 //-------------------------------------------------------------------
    388 
    389 HRESULT OcvImageManipulations::AddInputStreams(
    390     DWORD   cStreams,
    391     DWORD   *adwStreamIDs
    392 )
    393 {
    394     // This MFT has a fixed number of output streams, so the method is not supported.
    395     return E_NOTIMPL;
    396 }
    397 
    398 
    399 //-------------------------------------------------------------------
    400 // GetInputAvailableType
    401 // Returns a preferred input type.
    402 //-------------------------------------------------------------------
    403 
    404 HRESULT OcvImageManipulations::GetInputAvailableType(
    405     DWORD           dwInputStreamID,
    406     DWORD           dwTypeIndex, // 0-based
    407     IMFMediaType    **ppType
    408 )
    409 {
    410     if (ppType == NULL)
    411     {
    412         return E_INVALIDARG;
    413     }
    414 
    415     EnterCriticalSection(&m_critSec);
    416 
    417     if (!IsValidInputStream(dwInputStreamID))
    418     {
    419         LeaveCriticalSection(&m_critSec);
    420         return MF_E_INVALIDSTREAMNUMBER;
    421     }
    422 
    423     HRESULT hr = S_OK;
    424 
    425     // If the output type is set, return that type as our preferred input type.
    426     if (m_pOutputType == NULL)
    427     {
    428         // The output type is not set. Create a partial media type.
    429         hr = OnGetPartialType(dwTypeIndex, ppType);
    430     }
    431     else if (dwTypeIndex > 0)
    432     {
    433         hr = MF_E_NO_MORE_TYPES;
    434     }
    435     else
    436     {
    437         *ppType = m_pOutputType;
    438         (*ppType)->AddRef();
    439     }
    440 
    441     LeaveCriticalSection(&m_critSec);
    442     return hr;
    443 }
    444 
    445 
    446 
    447 //-------------------------------------------------------------------
    448 // GetOutputAvailableType
    449 // Returns a preferred output type.
    450 //-------------------------------------------------------------------
    451 
    452 HRESULT OcvImageManipulations::GetOutputAvailableType(
    453     DWORD           dwOutputStreamID,
    454     DWORD           dwTypeIndex, // 0-based
    455     IMFMediaType    **ppType
    456 )
    457 {
    458     if (ppType == NULL)
    459     {
    460         return E_INVALIDARG;
    461     }
    462 
    463     EnterCriticalSection(&m_critSec);
    464 
    465     if (!IsValidOutputStream(dwOutputStreamID))
    466     {
    467         LeaveCriticalSection(&m_critSec);
    468         return MF_E_INVALIDSTREAMNUMBER;
    469     }
    470 
    471     HRESULT hr = S_OK;
    472 
    473     if (m_pInputType == NULL)
    474     {
    475         // The input type is not set. Create a partial media type.
    476         hr = OnGetPartialType(dwTypeIndex, ppType);
    477     }
    478     else if (dwTypeIndex > 0)
    479     {
    480         hr = MF_E_NO_MORE_TYPES;
    481     }
    482     else
    483     {
    484         *ppType = m_pInputType;
    485         (*ppType)->AddRef();
    486     }
    487 
    488     LeaveCriticalSection(&m_critSec);
    489     return hr;
    490 }
    491 
    492 
    493 //-------------------------------------------------------------------
    494 // SetInputType
    495 //-------------------------------------------------------------------
    496 
    497 HRESULT OcvImageManipulations::SetInputType(
    498     DWORD           dwInputStreamID,
    499     IMFMediaType    *pType, // Can be NULL to clear the input type.
    500     DWORD           dwFlags
    501 )
    502 {
    503     // Validate flags.
    504     if (dwFlags & ~MFT_SET_TYPE_TEST_ONLY)
    505     {
    506         return E_INVALIDARG;
    507     }
    508 
    509     EnterCriticalSection(&m_critSec);
    510 
    511     if (!IsValidInputStream(dwInputStreamID))
    512     {
    513         LeaveCriticalSection(&m_critSec);
    514         return MF_E_INVALIDSTREAMNUMBER;
    515     }
    516 
    517     HRESULT hr = S_OK;
    518 
    519     // Does the caller want us to set the type, or just test it?
    520     BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0);
    521 
    522     // If we have an input sample, the client cannot change the type now.
    523     if (HasPendingOutput())
    524     {
    525         hr = MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING;
    526         goto done;
    527     }
    528 
    529     // Validate the type, if non-NULL.
    530     if (pType)
    531     {
    532         hr = OnCheckInputType(pType);
    533         if (FAILED(hr))
    534         {
    535             goto done;
    536         }
    537     }
    538 
    539     // The type is OK. Set the type, unless the caller was just testing.
    540     if (bReallySet)
    541     {
    542         OnSetInputType(pType);
    543 
    544         // When the type changes, end streaming.
    545         hr = EndStreaming();
    546     }
    547 
    548 done:
    549     LeaveCriticalSection(&m_critSec);
    550     return hr;
    551 }
    552 
    553 
    554 
    555 //-------------------------------------------------------------------
    556 // SetOutputType
    557 //-------------------------------------------------------------------
    558 
    559 HRESULT OcvImageManipulations::SetOutputType(
    560     DWORD           dwOutputStreamID,
    561     IMFMediaType    *pType, // Can be NULL to clear the output type.
    562     DWORD           dwFlags
    563 )
    564 {
    565     // Validate flags.
    566     if (dwFlags & ~MFT_SET_TYPE_TEST_ONLY)
    567     {
    568         return E_INVALIDARG;
    569     }
    570 
    571     EnterCriticalSection(&m_critSec);
    572 
    573     if (!IsValidOutputStream(dwOutputStreamID))
    574     {
    575         LeaveCriticalSection(&m_critSec);
    576         return MF_E_INVALIDSTREAMNUMBER;
    577     }
    578 
    579     HRESULT hr = S_OK;
    580 
    581     // Does the caller want us to set the type, or just test it?
    582     BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0);
    583 
    584     // If we have an input sample, the client cannot change the type now.
    585     if (HasPendingOutput())
    586     {
    587         hr = MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING;
    588         goto done;
    589     }
    590 
    591     // Validate the type, if non-NULL.
    592     if (pType)
    593     {
    594         hr = OnCheckOutputType(pType);
    595         if (FAILED(hr))
    596         {
    597             goto done;
    598         }
    599     }
    600 
    601     // The type is OK. Set the type, unless the caller was just testing.
    602     if (bReallySet)
    603     {
    604         OnSetOutputType(pType);
    605 
    606         // When the type changes, end streaming.
    607         hr = EndStreaming();
    608     }
    609 
    610 done:
    611     LeaveCriticalSection(&m_critSec);
    612     return hr;
    613 }
    614 
    615 
    616 //-------------------------------------------------------------------
    617 // GetInputCurrentType
    618 // Returns the current input type.
    619 //-------------------------------------------------------------------
    620 
    621 HRESULT OcvImageManipulations::GetInputCurrentType(
    622     DWORD           dwInputStreamID,
    623     IMFMediaType    **ppType
    624 )
    625 {
    626     if (ppType == NULL)
    627     {
    628         return E_POINTER;
    629     }
    630 
    631     HRESULT hr = S_OK;
    632 
    633     EnterCriticalSection(&m_critSec);
    634 
    635     if (!IsValidInputStream(dwInputStreamID))
    636     {
    637         hr = MF_E_INVALIDSTREAMNUMBER;
    638     }
    639     else if (!m_pInputType)
    640     {
    641         hr = MF_E_TRANSFORM_TYPE_NOT_SET;
    642     }
    643     else
    644     {
    645         *ppType = m_pInputType;
    646         (*ppType)->AddRef();
    647     }
    648     LeaveCriticalSection(&m_critSec);
    649     return hr;
    650 }
    651 
    652 
    653 //-------------------------------------------------------------------
    654 // GetOutputCurrentType
    655 // Returns the current output type.
    656 //-------------------------------------------------------------------
    657 
    658 HRESULT OcvImageManipulations::GetOutputCurrentType(
    659     DWORD           dwOutputStreamID,
    660     IMFMediaType    **ppType
    661 )
    662 {
    663     if (ppType == NULL)
    664     {
    665         return E_POINTER;
    666     }
    667 
    668     HRESULT hr = S_OK;
    669 
    670     EnterCriticalSection(&m_critSec);
    671 
    672     if (!IsValidOutputStream(dwOutputStreamID))
    673     {
    674         hr = MF_E_INVALIDSTREAMNUMBER;
    675     }
    676     else if (!m_pOutputType)
    677     {
    678         hr = MF_E_TRANSFORM_TYPE_NOT_SET;
    679     }
    680     else
    681     {
    682         *ppType = m_pOutputType;
    683         (*ppType)->AddRef();
    684     }
    685 
    686     LeaveCriticalSection(&m_critSec);
    687     return hr;
    688 }
    689 
    690 
    691 //-------------------------------------------------------------------
    692 // GetInputStatus
    693 // Query if the MFT is accepting more input.
    694 //-------------------------------------------------------------------
    695 
    696 HRESULT OcvImageManipulations::GetInputStatus(
    697     DWORD           dwInputStreamID,
    698     DWORD           *pdwFlags
    699 )
    700 {
    701     if (pdwFlags == NULL)
    702     {
    703         return E_POINTER;
    704     }
    705 
    706     EnterCriticalSection(&m_critSec);
    707 
    708     if (!IsValidInputStream(dwInputStreamID))
    709     {
    710         LeaveCriticalSection(&m_critSec);
    711         return MF_E_INVALIDSTREAMNUMBER;
    712     }
    713 
    714     // If an input sample is already queued, do not accept another sample until the
    715     // client calls ProcessOutput or Flush.
    716 
    717     // NOTE: It is possible for an MFT to accept more than one input sample. For
    718     // example, this might be required in a video decoder if the frames do not
    719     // arrive in temporal order. In the case, the decoder must hold a queue of
    720     // samples. For the video effect, each sample is transformed independently, so
    721     // there is no reason to queue multiple input samples.
    722 
    723     if (m_pSample == NULL)
    724     {
    725         *pdwFlags = MFT_INPUT_STATUS_ACCEPT_DATA;
    726     }
    727     else
    728     {
    729         *pdwFlags = 0;
    730     }
    731 
    732     LeaveCriticalSection(&m_critSec);
    733     return S_OK;
    734 }
    735 
    736 
    737 
    738 //-------------------------------------------------------------------
    739 // GetOutputStatus
    740 // Query if the MFT can produce output.
    741 //-------------------------------------------------------------------
    742 
    743 HRESULT OcvImageManipulations::GetOutputStatus(DWORD *pdwFlags)
    744 {
    745     if (pdwFlags == NULL)
    746     {
    747         return E_POINTER;
    748     }
    749 
    750     EnterCriticalSection(&m_critSec);
    751 
    752     // The MFT can produce an output sample if (and only if) there an input sample.
    753     if (m_pSample != NULL)
    754     {
    755         *pdwFlags = MFT_OUTPUT_STATUS_SAMPLE_READY;
    756     }
    757     else
    758     {
    759         *pdwFlags = 0;
    760     }
    761 
    762     LeaveCriticalSection(&m_critSec);
    763     return S_OK;
    764 }
    765 
    766 
    767 //-------------------------------------------------------------------
    768 // SetOutputBounds
    769 // Sets the range of time stamps that the MFT will output.
    770 //-------------------------------------------------------------------
    771 
    772 HRESULT OcvImageManipulations::SetOutputBounds(
    773     LONGLONG        hnsLowerBound,
    774     LONGLONG        hnsUpperBound
    775 )
    776 {
    777     // Implementation of this method is optional.
    778     return E_NOTIMPL;
    779 }
    780 
    781 
    782 //-------------------------------------------------------------------
    783 // ProcessEvent
    784 // Sends an event to an input stream.
    785 //-------------------------------------------------------------------
    786 
    787 HRESULT OcvImageManipulations::ProcessEvent(
    788     DWORD              dwInputStreamID,
    789     IMFMediaEvent      *pEvent
    790 )
    791 {
    792     // This MFT does not handle any stream events, so the method can
    793     // return E_NOTIMPL. This tells the pipeline that it can stop
    794     // sending any more events to this MFT.
    795     return E_NOTIMPL;
    796 }
    797 
    798 
    799 //-------------------------------------------------------------------
    800 // ProcessMessage
    801 //-------------------------------------------------------------------
    802 
    803 HRESULT OcvImageManipulations::ProcessMessage(
    804     MFT_MESSAGE_TYPE    eMessage,
    805     ULONG_PTR           ulParam
    806 )
    807 {
    808     EnterCriticalSection(&m_critSec);
    809 
    810     HRESULT hr = S_OK;
    811 
    812     switch (eMessage)
    813     {
    814     case MFT_MESSAGE_COMMAND_FLUSH:
    815         // Flush the MFT.
    816         hr = OnFlush();
    817         break;
    818 
    819     case MFT_MESSAGE_COMMAND_DRAIN:
    820         // Drain: Tells the MFT to reject further input until all pending samples are
    821         // processed. That is our default behavior already, so there is nothing to do.
    822         //
    823         // For a decoder that accepts a queue of samples, the MFT might need to drain
    824         // the queue in response to this command.
    825     break;
    826 
    827     case MFT_MESSAGE_SET_D3D_MANAGER:
    828         // Sets a pointer to the IDirect3DDeviceManager9 interface.
    829 
    830         // The pipeline should never send this message unless the MFT sets the MF_SA_D3D_AWARE
    831         // attribute set to TRUE. Because this MFT does not set MF_SA_D3D_AWARE, it is an error
    832         // to send the MFT_MESSAGE_SET_D3D_MANAGER message to the MFT. Return an error code in
    833         // this case.
    834 
    835         // NOTE: If this MFT were D3D-enabled, it would cache the IDirect3DDeviceManager9
    836         // pointer for use during streaming.
    837 
    838         hr = E_NOTIMPL;
    839         break;
    840 
    841     case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
    842         hr = BeginStreaming();
    843         break;
    844 
    845     case MFT_MESSAGE_NOTIFY_END_STREAMING:
    846         hr = EndStreaming();
    847         break;
    848 
    849     // The next two messages do not require any action from this MFT.
    850 
    851     case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
    852         break;
    853 
    854     case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
    855         break;
    856     }
    857 
    858     LeaveCriticalSection(&m_critSec);
    859     return hr;
    860 }
    861 
    862 
    863 //-------------------------------------------------------------------
    864 // ProcessInput
    865 // Process an input sample.
    866 //-------------------------------------------------------------------
    867 
    868 HRESULT OcvImageManipulations::ProcessInput(
    869     DWORD               dwInputStreamID,
    870     IMFSample           *pSample,
    871     DWORD               dwFlags
    872 )
    873 {
    874     // Check input parameters.
    875     if (pSample == NULL)
    876     {
    877         return E_POINTER;
    878     }
    879 
    880     if (dwFlags != 0)
    881     {
    882         return E_INVALIDARG; // dwFlags is reserved and must be zero.
    883     }
    884 
    885     HRESULT hr = S_OK;
    886 
    887     EnterCriticalSection(&m_critSec);
    888 
    889     // Validate the input stream number.
    890     if (!IsValidInputStream(dwInputStreamID))
    891     {
    892         hr = MF_E_INVALIDSTREAMNUMBER;
    893         goto done;
    894     }
    895 
    896     // Check for valid media types.
    897     // The client must set input and output types before calling ProcessInput.
    898     if (!m_pInputType || !m_pOutputType)
    899     {
    900         hr = MF_E_NOTACCEPTING;
    901         goto done;
    902     }
    903 
    904     // Check if an input sample is already queued.
    905     if (m_pSample != NULL)
    906     {
    907         hr = MF_E_NOTACCEPTING;   // We already have an input sample.
    908         goto done;
    909     }
    910 
    911     // Initialize streaming.
    912     hr = BeginStreaming();
    913     if (FAILED(hr))
    914     {
    915         goto done;
    916     }
    917 
    918     // Cache the sample. We do the actual work in ProcessOutput.
    919     m_pSample = pSample;
    920     pSample->AddRef();  // Hold a reference count on the sample.
    921 
    922 done:
    923     LeaveCriticalSection(&m_critSec);
    924     return hr;
    925 }
    926 
    927 
    928 //-------------------------------------------------------------------
    929 // ProcessOutput
    930 // Process an output sample.
    931 //-------------------------------------------------------------------
    932 
    933 HRESULT OcvImageManipulations::ProcessOutput(
    934     DWORD                   dwFlags,
    935     DWORD                   cOutputBufferCount,
    936     MFT_OUTPUT_DATA_BUFFER  *pOutputSamples, // one per stream
    937     DWORD                   *pdwStatus
    938 )
    939 {
    940     // Check input parameters...
    941 
    942     // This MFT does not accept any flags for the dwFlags parameter.
    943 
    944     // The only defined flag is MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER. This flag
    945     // applies only when the MFT marks an output stream as lazy or optional. But this
    946     // MFT has no lazy or optional streams, so the flag is not valid.
    947 
    948     if (dwFlags != 0)
    949     {
    950         return E_INVALIDARG;
    951     }
    952 
    953     if (pOutputSamples == NULL || pdwStatus == NULL)
    954     {
    955         return E_POINTER;
    956     }
    957 
    958     // There must be exactly one output buffer.
    959     if (cOutputBufferCount != 1)
    960     {
    961         return E_INVALIDARG;
    962     }
    963 
    964     // It must contain a sample.
    965     if (pOutputSamples[0].pSample == NULL)
    966     {
    967         return E_INVALIDARG;
    968     }
    969 
    970     HRESULT hr = S_OK;
    971 
    972     IMFMediaBuffer *pInput = NULL;
    973     IMFMediaBuffer *pOutput = NULL;
    974 
    975     EnterCriticalSection(&m_critSec);
    976 
    977     // There must be an input sample available for processing.
    978     if (m_pSample == NULL)
    979     {
    980         hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
    981         goto done;
    982     }
    983 
    984     // Initialize streaming.
    985 
    986     hr = BeginStreaming();
    987     if (FAILED(hr))
    988     {
    989         goto done;
    990     }
    991 
    992     // Get the input buffer.
    993     hr = m_pSample->ConvertToContiguousBuffer(&pInput);
    994     if (FAILED(hr))
    995     {
    996         goto done;
    997     }
    998 
    999     // Get the output buffer.
   1000     hr = pOutputSamples[0].pSample->ConvertToContiguousBuffer(&pOutput);
   1001     if (FAILED(hr))
   1002     {
   1003         goto done;
   1004     }
   1005 
   1006     hr = OnProcessOutput(pInput, pOutput);
   1007     if (FAILED(hr))
   1008     {
   1009         goto done;
   1010     }
   1011 
   1012     // Set status flags.
   1013     pOutputSamples[0].dwStatus = 0;
   1014     *pdwStatus = 0;
   1015 
   1016 
   1017     // Copy the duration and time stamp from the input sample, if present.
   1018 
   1019     LONGLONG hnsDuration = 0;
   1020     LONGLONG hnsTime = 0;
   1021 
   1022     if (SUCCEEDED(m_pSample->GetSampleDuration(&hnsDuration)))
   1023     {
   1024         hr = pOutputSamples[0].pSample->SetSampleDuration(hnsDuration);
   1025         if (FAILED(hr))
   1026         {
   1027             goto done;
   1028         }
   1029     }
   1030 
   1031     if (SUCCEEDED(m_pSample->GetSampleTime(&hnsTime)))
   1032     {
   1033         hr = pOutputSamples[0].pSample->SetSampleTime(hnsTime);
   1034     }
   1035 
   1036 done:
   1037     SafeRelease(&m_pSample);   // Release our input sample.
   1038     SafeRelease(&pInput);
   1039     SafeRelease(&pOutput);
   1040     LeaveCriticalSection(&m_critSec);
   1041     return hr;
   1042 }
   1043 
   1044 // PRIVATE METHODS
   1045 
   1046 // All methods that follow are private to this MFT and are not part of the IMFTransform interface.
   1047 
   1048 // Create a partial media type from our list.
   1049 //
   1050 // dwTypeIndex: Index into the list of peferred media types.
   1051 // ppmt:        Receives a pointer to the media type.
   1052 
   1053 HRESULT OcvImageManipulations::OnGetPartialType(DWORD dwTypeIndex, IMFMediaType **ppmt)
   1054 {
   1055     if (dwTypeIndex >= ARRAYSIZE(g_MediaSubtypes))
   1056     {
   1057         return MF_E_NO_MORE_TYPES;
   1058     }
   1059 
   1060     IMFMediaType *pmt = NULL;
   1061 
   1062     HRESULT hr = MFCreateMediaType(&pmt);
   1063     if (FAILED(hr))
   1064     {
   1065         goto done;
   1066     }
   1067 
   1068     hr = pmt->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
   1069     if (FAILED(hr))
   1070     {
   1071         goto done;
   1072     }
   1073 
   1074     hr = pmt->SetGUID(MF_MT_SUBTYPE, g_MediaSubtypes[dwTypeIndex]);
   1075     if (FAILED(hr))
   1076     {
   1077         goto done;
   1078     }
   1079 
   1080     *ppmt = pmt;
   1081     (*ppmt)->AddRef();
   1082 
   1083 done:
   1084     SafeRelease(&pmt);
   1085     return hr;
   1086 }
   1087 
   1088 
   1089 // Validate an input media type.
   1090 
   1091 HRESULT OcvImageManipulations::OnCheckInputType(IMFMediaType *pmt)
   1092 {
   1093     assert(pmt != NULL);
   1094 
   1095     HRESULT hr = S_OK;
   1096 
   1097     // If the output type is set, see if they match.
   1098     if (m_pOutputType != NULL)
   1099     {
   1100         DWORD flags = 0;
   1101         hr = pmt->IsEqual(m_pOutputType, &flags);
   1102 
   1103         // IsEqual can return S_FALSE. Treat this as failure.
   1104         if (hr != S_OK)
   1105         {
   1106             hr = MF_E_INVALIDMEDIATYPE;
   1107         }
   1108     }
   1109     else
   1110     {
   1111         // Output type is not set. Just check this type.
   1112         hr = OnCheckMediaType(pmt);
   1113     }
   1114     return hr;
   1115 }
   1116 
   1117 
   1118 // Validate an output media type.
   1119 
   1120 HRESULT OcvImageManipulations::OnCheckOutputType(IMFMediaType *pmt)
   1121 {
   1122     assert(pmt != NULL);
   1123 
   1124     HRESULT hr = S_OK;
   1125 
   1126     // If the input type is set, see if they match.
   1127     if (m_pInputType != NULL)
   1128     {
   1129         DWORD flags = 0;
   1130         hr = pmt->IsEqual(m_pInputType, &flags);
   1131 
   1132         // IsEqual can return S_FALSE. Treat this as failure.
   1133         if (hr != S_OK)
   1134         {
   1135             hr = MF_E_INVALIDMEDIATYPE;
   1136         }
   1137 
   1138     }
   1139     else
   1140     {
   1141         // Input type is not set. Just check this type.
   1142         hr = OnCheckMediaType(pmt);
   1143     }
   1144     return hr;
   1145 }
   1146 
   1147 
   1148 // Validate a media type (input or output)
   1149 
   1150 HRESULT OcvImageManipulations::OnCheckMediaType(IMFMediaType *pmt)
   1151 {
   1152     BOOL bFoundMatchingSubtype = FALSE;
   1153 
   1154     // Major type must be video.
   1155     GUID major_type;
   1156     HRESULT hr = pmt->GetGUID(MF_MT_MAJOR_TYPE, &major_type);
   1157     if (FAILED(hr))
   1158     {
   1159         goto done;
   1160     }
   1161 
   1162     if (major_type != MFMediaType_Video)
   1163     {
   1164         hr = MF_E_INVALIDMEDIATYPE;
   1165         goto done;
   1166     }
   1167 
   1168     // Subtype must be one of the subtypes in our global list.
   1169 
   1170     // Get the subtype GUID.
   1171     GUID subtype;
   1172     hr = pmt->GetGUID(MF_MT_SUBTYPE, &subtype);
   1173     if (FAILED(hr))
   1174     {
   1175         goto done;
   1176     }
   1177 
   1178     // Look for the subtype in our list of accepted types.
   1179     for (DWORD i = 0; i < ARRAYSIZE(g_MediaSubtypes); i++)
   1180     {
   1181         if (subtype == g_MediaSubtypes[i])
   1182         {
   1183             bFoundMatchingSubtype = TRUE;
   1184             break;
   1185         }
   1186     }
   1187 
   1188     if (!bFoundMatchingSubtype)
   1189     {
   1190         hr = MF_E_INVALIDMEDIATYPE; // The MFT does not support this subtype.
   1191         goto done;
   1192     }
   1193 
   1194     // Reject single-field media types.
   1195     UINT32 interlace = MFGetAttributeUINT32(pmt, MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
   1196     if (interlace == MFVideoInterlace_FieldSingleUpper  || interlace == MFVideoInterlace_FieldSingleLower)
   1197     {
   1198         hr = MF_E_INVALIDMEDIATYPE;
   1199     }
   1200 
   1201 done:
   1202     return hr;
   1203 }
   1204 
   1205 
   1206 // Set or clear the input media type.
   1207 //
   1208 // Prerequisite: The input type was already validated.
   1209 
   1210 void OcvImageManipulations::OnSetInputType(IMFMediaType *pmt)
   1211 {
   1212     // if pmt is NULL, clear the type.
   1213     // if pmt is non-NULL, set the type.
   1214 
   1215     SafeRelease(&m_pInputType);
   1216     m_pInputType = pmt;
   1217     if (m_pInputType)
   1218     {
   1219         m_pInputType->AddRef();
   1220     }
   1221 
   1222     // Update the format information.
   1223     UpdateFormatInfo();
   1224 }
   1225 
   1226 
   1227 // Set or clears the output media type.
   1228 //
   1229 // Prerequisite: The output type was already validated.
   1230 
   1231 void OcvImageManipulations::OnSetOutputType(IMFMediaType *pmt)
   1232 {
   1233     // If pmt is NULL, clear the type. Otherwise, set the type.
   1234 
   1235     SafeRelease(&m_pOutputType);
   1236     m_pOutputType = pmt;
   1237     if (m_pOutputType)
   1238     {
   1239         m_pOutputType->AddRef();
   1240     }
   1241 }
   1242 
   1243 
   1244 // Initialize streaming parameters.
   1245 //
   1246 // This method is called if the client sends the MFT_MESSAGE_NOTIFY_BEGIN_STREAMING
   1247 // message, or when the client processes a sample, whichever happens first.
   1248 
   1249 HRESULT OcvImageManipulations::BeginStreaming()
   1250 {
   1251     HRESULT hr = S_OK;
   1252 
   1253     if (!m_bStreamingInitialized)
   1254     {
   1255         m_bStreamingInitialized = true;
   1256         hr = S_OK;
   1257     }
   1258 
   1259     return hr;
   1260 }
   1261 
   1262 
   1263 // End streaming.
   1264 
   1265 // This method is called if the client sends an MFT_MESSAGE_NOTIFY_END_STREAMING
   1266 // message, or when the media type changes. In general, it should be called whenever
   1267 // the streaming parameters need to be reset.
   1268 
   1269 HRESULT OcvImageManipulations::EndStreaming()
   1270 {
   1271     m_bStreamingInitialized = false;
   1272     return S_OK;
   1273 }
   1274 
   1275 
   1276 
   1277 // Generate output data.
   1278 
   1279 HRESULT OcvImageManipulations::OnProcessOutput(IMFMediaBuffer *pIn, IMFMediaBuffer *pOut)
   1280 {
   1281     BYTE *pDest = NULL;         // Destination buffer.
   1282     LONG lDestStride = 0;       // Destination stride.
   1283 
   1284     BYTE *pSrc = NULL;          // Source buffer.
   1285     LONG lSrcStride = 0;        // Source stride.
   1286 
   1287     // Helper objects to lock the buffers.
   1288     VideoBufferLock inputLock(pIn);
   1289     VideoBufferLock outputLock(pOut);
   1290 
   1291     // Stride if the buffer does not support IMF2DBuffer
   1292     LONG lDefaultStride = 0;
   1293 
   1294     HRESULT hr = GetDefaultStride(m_pInputType, &lDefaultStride);
   1295     if (FAILED(hr))
   1296     {
   1297         return hr;
   1298     }
   1299 
   1300     // Lock the input buffer.
   1301     hr = inputLock.LockBuffer(lDefaultStride, m_imageHeightInPixels, &pSrc, &lSrcStride);
   1302     if (FAILED(hr))
   1303     {
   1304         return hr;
   1305     }
   1306 
   1307     // Lock the output buffer.
   1308     hr = outputLock.LockBuffer(lDefaultStride, m_imageHeightInPixels, &pDest, &lDestStride);
   1309     if (FAILED(hr))
   1310     {
   1311         return hr;
   1312     }
   1313 
   1314     cv::Mat InputFrame(m_imageHeightInPixels + m_imageHeightInPixels/2, m_imageWidthInPixels, CV_8UC1, pSrc, lSrcStride);
   1315     cv::Mat InputGreyScale(InputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels));
   1316     cv::Mat OutputFrame(m_imageHeightInPixels + m_imageHeightInPixels/2, m_imageWidthInPixels, CV_8UC1, pDest, lDestStride);
   1317 
   1318     switch (m_TransformType)
   1319     {
   1320     case Preview:
   1321         {
   1322             InputFrame.copyTo(OutputFrame);
   1323         } break;
   1324     case GrayScale:
   1325         {
   1326             OutputFrame.setTo(cv::Scalar(128));
   1327             cv::Mat OutputGreyScale(OutputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels));
   1328             InputGreyScale.copyTo(OutputGreyScale);
   1329         } break;
   1330     case Canny:
   1331         {
   1332             OutputFrame.setTo(cv::Scalar(128));
   1333             cv::Mat OutputGreyScale(OutputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels));
   1334             cv::Canny(InputGreyScale, OutputGreyScale, 80, 90);
   1335 
   1336         } break;
   1337     case Sobel:
   1338         {
   1339             OutputFrame.setTo(cv::Scalar(128));
   1340             cv::Mat OutputGreyScale(OutputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels));
   1341             cv::Sobel(InputGreyScale, OutputGreyScale, CV_8U, 1, 1);
   1342         } break;
   1343     case Histogram:
   1344         {
   1345             const int mHistSizeNum = 25;
   1346             const int channels[3][1] = {{0}, {1}, {2}};
   1347             const int mHistSize[] = {25};
   1348             const float baseRabge[] = {0.f,256.f};
   1349             const float* ranges[] = {baseRabge};
   1350 
   1351             const cv::Scalar mColorsY[] = { cv::Scalar(76), cv::Scalar(149), cv::Scalar(29) };
   1352             const cv::Scalar mColorsUV[] = { cv::Scalar(84, 255), cv::Scalar(43, 21), cv::Scalar(255, 107) };
   1353 
   1354             cv::Mat OutputY(m_imageHeightInPixels, m_imageWidthInPixels, CV_8UC1, pDest, lDestStride);
   1355             cv::Mat OutputUV(m_imageHeightInPixels/2, m_imageWidthInPixels/2,
   1356                              CV_8UC2, pDest+m_imageHeightInPixels*lDestStride, lDestStride);
   1357             cv::Mat BgrFrame;
   1358 
   1359             InputFrame.copyTo(OutputFrame);
   1360 
   1361             cv::cvtColor(InputFrame, BgrFrame, cv::COLOR_YUV420sp2BGR);
   1362             int thikness = (int) (BgrFrame.cols / (mHistSizeNum + 10) / 5);
   1363             if(thikness > 5) thikness = 5;
   1364             int offset = (int) ((BgrFrame.cols - (5*mHistSizeNum + 4*10)*thikness)/2);
   1365 
   1366             // RGB
   1367             for (int c=0; c<3; c++)
   1368             {
   1369                 cv::Mat hist;
   1370                 cv::calcHist(&BgrFrame, 1, channels[c], cv::Mat(), hist, 1, mHistSize, ranges);
   1371                 cv::normalize(hist, hist, BgrFrame.rows/2, 0, cv::NORM_INF);
   1372                 for(int h=0; h<mHistSizeNum; h++) {
   1373                     cv::Point mP1, mP2;
   1374                     // Draw on Y plane
   1375                     mP1.x = mP2.x = offset + (c * (mHistSizeNum + 10) + h) * thikness;
   1376                     mP1.y = BgrFrame.rows-1;
   1377                     mP2.y = mP1.y - 2 - (int)hist.at<float>(h);
   1378                     cv::line(OutputY, mP1, mP2, mColorsY[c], thikness);
   1379 
   1380                     // Draw on UV planes
   1381                     mP1.x /= 2;
   1382                     mP1.y /= 2;
   1383                     mP2.x /= 2;
   1384                     mP2.y /= 2;
   1385                     cv::line(OutputUV, mP1, mP2, mColorsUV[c], thikness/2);
   1386                 }
   1387             }
   1388         } break;
   1389     default:
   1390         break;
   1391     }
   1392 
   1393     // Set the data size on the output buffer.
   1394     hr = pOut->SetCurrentLength(m_cbImageSize);
   1395 
   1396     return hr;
   1397 }
   1398 
   1399 
   1400 // Flush the MFT.
   1401 
   1402 HRESULT OcvImageManipulations::OnFlush()
   1403 {
   1404     // For this MFT, flushing just means releasing the input sample.
   1405     SafeRelease(&m_pSample);
   1406     return S_OK;
   1407 }
   1408 
   1409 
   1410 // Update the format information. This method is called whenever the
   1411 // input type is set.
   1412 
   1413 HRESULT OcvImageManipulations::UpdateFormatInfo()
   1414 {
   1415     HRESULT hr = S_OK;
   1416 
   1417     GUID subtype = GUID_NULL;
   1418 
   1419     m_imageWidthInPixels = 0;
   1420     m_imageHeightInPixels = 0;
   1421     m_cbImageSize = 0;
   1422 
   1423     if (m_pInputType != NULL)
   1424     {
   1425         hr = m_pInputType->GetGUID(MF_MT_SUBTYPE, &subtype);
   1426         if (FAILED(hr))
   1427         {
   1428             goto done;
   1429         }
   1430         if (subtype != MFVideoFormat_NV12)
   1431         {
   1432             hr = E_UNEXPECTED;
   1433             goto done;
   1434         }
   1435 
   1436         hr = MFGetAttributeSize(m_pInputType, MF_MT_FRAME_SIZE, &m_imageWidthInPixels, &m_imageHeightInPixels);
   1437         if (FAILED(hr))
   1438         {
   1439             goto done;
   1440         }
   1441 
   1442         // Calculate the image size for YUV NV12 image(not including padding)
   1443         m_cbImageSize = (m_imageHeightInPixels + m_imageHeightInPixels/2)*m_imageWidthInPixels;
   1444     }
   1445 
   1446 done:
   1447     return hr;
   1448 }
   1449 
   1450 
   1451 // Get the default stride for a video format.
   1452 HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride)
   1453 {
   1454     LONG lStride = 0;
   1455 
   1456     // Try to get the default stride from the media type.
   1457     HRESULT hr = pType->GetUINT32(MF_MT_DEFAULT_STRIDE, (UINT32*)&lStride);
   1458     if (FAILED(hr))
   1459     {
   1460         // Attribute not set. Try to calculate the default stride.
   1461         GUID subtype = GUID_NULL;
   1462 
   1463         UINT32 width = 0;
   1464         UINT32 height = 0;
   1465 
   1466         // Get the subtype and the image size.
   1467         hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype);
   1468         if (SUCCEEDED(hr))
   1469         {
   1470             hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
   1471         }
   1472         if (SUCCEEDED(hr))
   1473         {
   1474             if (subtype == MFVideoFormat_NV12)
   1475             {
   1476                 lStride = width;
   1477             }
   1478             else if (subtype == MFVideoFormat_YUY2 || subtype == MFVideoFormat_UYVY)
   1479             {
   1480                 lStride = ((width * 2) + 3) & ~3;
   1481             }
   1482             else
   1483             {
   1484                 hr = E_INVALIDARG;
   1485             }
   1486         }
   1487 
   1488         // Set the attribute for later reference.
   1489         if (SUCCEEDED(hr))
   1490         {
   1491             (void)pType->SetUINT32(MF_MT_DEFAULT_STRIDE, UINT32(lStride));
   1492         }
   1493     }
   1494     if (SUCCEEDED(hr))
   1495     {
   1496         *plStride = lStride;
   1497     }
   1498     return hr;
   1499 }
   1500