videoenc.cpp
上传用户:liguizhu
上传日期:2015-11-01
资源大小:2422k
文件大小:16k
源码类别:

P2P编程

开发平台:

Visual C++

  1. /*
  2.  *  Openmysee
  3.  *
  4.  *  This program is free software; you can redistribute it and/or modify
  5.  *  it under the terms of the GNU General Public License as published by
  6.  *  the Free Software Foundation; either version 2 of the License, or
  7.  *  (at your option) any later version.
  8.  *
  9.  *  This program is distributed in the hope that it will be useful,
  10.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *  GNU General Public License for more details.
  13.  *
  14.  *  You should have received a copy of the GNU General Public License
  15.  *  along with this program; if not, write to the Free Software
  16.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17.  *
  18.  */
  19. //-----------------------------------------------------------------------------
  20. // Copyright (c) Microsoft Corporation.  All rights reserved.
  21. //-----------------------------------------------------------------------------
  22. #include "stdafx.h"
  23. #include <streams.h>
  24. #include <dvdmedia.h>
  25. #include <qedit.h>
  26. #include "wmcodecconst.h"
  27. #include "wmcodeciface.h"
  28. #include "encappErr.h"
  29. #include "macros.h"
  30. #include "VideoEncParams.h"
  31. #include "videoenc.h"
  32. #include "Capture.h"
  33. //////////////////////////////////////////////////////////////////////////////
  34. //
  35. // MakeVideoOutputType
  36. //
  37. //////////////////////////////////////////////////////////////////////////////
  38. HRESULT MakeVideoOutputType(IMediaObject   *pDMO,    
  39.                             AM_MEDIA_TYPE  *pmtIn,   
  40.                             CVideoEncParams *pParams, 
  41.                             AM_MEDIA_TYPE  *pmt      ) {
  42.     
  43.     HRESULT             hr                   = S_OK;
  44.     VIDEOINFOHEADER2    *pvih2               = NULL;
  45.     VIDEOINFOHEADER     vih;
  46.     IWMCodecPrivateData *pWMCodecPrivateData = NULL;
  47.     DWORD               cbPrivateData        = 0;
  48.     BYTE                *pbPrivateData       = NULL;
  49.     BYTE                *pNewFormat          = NULL;
  50.     
  51.     if( pDMO == NULL || pmtIn == NULL || pParams == NULL || pmt == NULL )
  52.         return E_INVALIDARG;
  53.     
  54.     if( pmtIn->pbFormat == NULL || pmtIn->cbFormat <= 0 )
  55.         return E_INVALIDARG;
  56.     
  57.     // make up a partial media type
  58.     pmt->majortype            = MEDIATYPE_Video;
  59.     pmt->formattype           = FORMAT_VideoInfo;
  60.     pmt->bFixedSizeSamples    = FALSE;
  61.     pmt->bTemporalCompression = TRUE;
  62.     
  63.     if( pmtIn->formattype == FORMAT_VideoInfo ){
  64.         vih = *(VIDEOINFOHEADER*)pmtIn->pbFormat; 
  65.     } else if( pmtIn->formattype == FORMAT_VideoInfo2 ){
  66.         pvih2 = (VIDEOINFOHEADER2*)pmtIn->pbFormat;
  67.         vih.rcSource        = pvih2->rcSource;
  68.         vih.rcTarget        = pvih2->rcTarget;
  69.         vih.AvgTimePerFrame = pvih2->AvgTimePerFrame;
  70.         vih.bmiHeader       = pvih2->bmiHeader;
  71.     } else
  72.         return E_VIDEO_INVALID_INPUT_TYPE;
  73.     
  74.     vih.dwBitRate            = (DWORD)pParams->nBitrate;
  75.     vih.dwBitErrorRate       = 0;
  76.     vih.bmiHeader.biPlanes   = 1;
  77.     vih.bmiHeader.biBitCount = 24;
  78.     
  79.     switch( pParams->dwTag ){
  80.     case WMCFOURCC_WMV3:
  81.         pmt->subtype = WMCMEDIASUBTYPE_WMV3;
  82.         vih.bmiHeader.biCompression = WMCFOURCC_WMV3;
  83.         break;
  84.     default:
  85.         return E_VIDEO_COMPRESSION_NOT_SUPPORTED;
  86.     }
  87.     
  88.     //use the fake format above to get the private data
  89.     pmt->pbFormat = (BYTE*)&vih;
  90.     pmt->cbFormat = sizeof( vih );
  91.     pmt->pUnk = NULL;
  92.     
  93.     hr = pDMO->QueryInterface(IID_IWMCodecPrivateData, (void**)&pWMCodecPrivateData);    
  94.     if( FAILED( hr ) )
  95.         return E_NO_PRIVATE_DATA;
  96.     
  97.     hr = pWMCodecPrivateData->SetPartialOutputType( pmt );
  98.     if( FAILED( hr ) ){
  99.         SAFERELEASE( pWMCodecPrivateData );
  100.         return E_PARTIAL_TYPE_REJECTED;;
  101.     }
  102.     
  103.     hr = pWMCodecPrivateData->GetPrivateData( NULL, &cbPrivateData );
  104.     if( FAILED( hr ) ){
  105.         SAFERELEASE( pWMCodecPrivateData );        
  106.         return E_NO_PRIVATE_DATA_COUNT;
  107.     }
  108.     
  109.     if( cbPrivateData != 0 ){
  110.         pbPrivateData = new BYTE[ cbPrivateData ];
  111.         if( pbPrivateData == NULL ){
  112.             SAFERELEASE( pWMCodecPrivateData );
  113.             return E_OUTOFMEMORY;
  114.         }
  115.         
  116.         // get the private data
  117.         hr = pWMCodecPrivateData->GetPrivateData( pbPrivateData, &cbPrivateData );
  118.         SAFERELEASE( pWMCodecPrivateData );
  119.         if( FAILED( hr ) ) 
  120.             return E_PRIVATE_DATA_FAILED;
  121.     }
  122.     
  123.     //modify the media type accordingly
  124.     pNewFormat = (BYTE*)CoTaskMemAlloc( sizeof( VIDEOINFOHEADER) + cbPrivateData );
  125.     if( pNewFormat == NULL ){
  126.         SAFEDELETE( pbPrivateData );
  127.         return E_OUTOFMEMORY;
  128.     }
  129.     
  130.     memcpy( pNewFormat, pmt->pbFormat, sizeof( VIDEOINFOHEADER));
  131.     if( pbPrivateData != NULL )
  132.         memcpy( pNewFormat + sizeof( VIDEOINFOHEADER), pbPrivateData, cbPrivateData);
  133.     SAFEDELETE( pbPrivateData );
  134.     
  135.     pmt->pbFormat = pNewFormat;
  136.     pmt->cbFormat = sizeof( VIDEOINFOHEADER) + cbPrivateData;
  137.     ((VIDEOINFOHEADER*)pmt->pbFormat)->bmiHeader.biSize += cbPrivateData;
  138.     
  139.     return S_OK;
  140. }
  141. //////////////////////////////////////////////////////////////////////////////
  142. //
  143. // SetVideoTypes
  144. //
  145. //////////////////////////////////////////////////////////////////////////////
  146. HRESULT SetVideoTypes( IMediaObject   *pDMO,    
  147.                       AM_MEDIA_TYPE  *pmtIn,   
  148.                       CVideoEncParams *pParams, 
  149.                       AM_MEDIA_TYPE  *pmtOut,  
  150.                       DWORD *pcbIn,            
  151.                       DWORD *pcbOut ){
  152.     HRESULT hr;
  153.     DWORD   dwDummy;
  154.     
  155.     //Now we can make the output type...
  156.     hr = MakeVideoOutputType( pDMO, pmtIn, pParams, pmtOut );
  157.     if( FAILED( hr ) )
  158.     {
  159. //        ON_FAIL("Failed MakeVideoOutputTypern", hr)
  160.             return hr;
  161.     }
  162.     
  163.     //... and set it on the DMO just to check whether it is accepted or not
  164.     hr = pDMO->SetOutputType(0, pmtOut, 0);
  165.     if( FAILED( hr ) )
  166.     {
  167.   //      ON_FAIL("Failed SetOutputTypern", hr)
  168.             return hr;
  169.     }
  170.     
  171.     //     
  172.     hr = pDMO->GetInputSizeInfo( 0, pcbIn, &dwDummy, &dwDummy);
  173.     if( FAILED(hr) )
  174.     {
  175.    //     ON_FAIL("Failed GetInputSizeInforn", hr)
  176.             return hr;
  177.     }
  178.     
  179.     hr = pDMO->GetOutputSizeInfo( 0, pcbOut, &dwDummy);
  180.     if( FAILED( hr ) )
  181.     {
  182.  //       ON_FAIL("Failed GetOutputSizeInforn", hr)
  183.             return hr;
  184.     }
  185.     
  186.     return hr;
  187. //////////////////////////////////////////////////////////////////////////////
  188. //
  189. // SetVideoParams
  190. //
  191. //////////////////////////////////////////////////////////////////////////////
  192. HRESULT SetVideoParams( IMediaObject *pDMO, CVideoEncParams *pParams ){
  193.     HRESULT      hr = S_OK;
  194.     VARIANT      varg;
  195.     BSTR         bstrIn;
  196.     IPropertyBag *pPropertyBag = NULL;
  197.     
  198.     if( pDMO == NULL || pParams == NULL )
  199.         return E_INVALIDARG;
  200.     
  201.     do {
  202.         // Get the IPropertyBag IF and set the appropriate params
  203.         hr = pDMO->QueryInterface(IID_IPropertyBag, (void**)&pPropertyBag);
  204.         if( FAILED( hr ) ){
  205.             break;
  206.         }
  207.         
  208.         //set the encoder in VBR mode if required
  209.         if( pParams->fIsVBR == TRUE ){
  210.             ::VariantInit(&varg);
  211.             varg.vt      = VT_BOOL;
  212.             varg.boolVal = TRUE;
  213.             
  214.             hr = pPropertyBag->Write( g_wszWMVCVBREnabled, &varg );
  215.             if( FAILED( hr ) ){
  216.                 hr = E_VIDEO_VBR_NOT_SUPPORTED;
  217.                 break;
  218.             }
  219.             
  220.             ::VariantInit(&varg);
  221.             varg.vt = VT_I4;
  222.             varg.lVal = pParams->nVBRQuality;
  223.             hr = pPropertyBag->Write( g_wszWMVCVBRQuality, &varg );
  224.             if( FAILED( hr ) ){
  225.                 hr = E_VBR_QUALITY_REJECTED;
  226.                 break;
  227.             }
  228.         }
  229.         
  230.         // set the bitrate if not VBR
  231.         if( pParams->fIsVBR == FALSE ){
  232.             ::VariantInit(&varg);
  233.             varg.vt = VT_I4;
  234.             varg.lVal = pParams->nBitrate;
  235.             hr = pPropertyBag->Write( g_wszWMVCAvgBitrate, &varg );
  236.             if( FAILED( hr ) ){
  237.                 hr = E_VIDEO_BITRATE_REJECTED;
  238.                 break;
  239.             }
  240.         }
  241.         
  242.         // set the buffer window
  243.         ::VariantInit(&varg);
  244.         varg.vt = VT_I4;
  245.         varg.lVal = pParams->nBufferDelay;
  246.         hr = pPropertyBag->Write( g_wszWMVCVideoWindow, &varg );
  247.         if( FAILED( hr ) ){
  248.             hr = E_VIDEO_BUFFER_REJECTED;
  249.             break;
  250.         }
  251.         
  252.         // set the profile for WMV# only
  253.         if( pParams->dwTag == WMCFOURCC_WMV3 ){
  254.             switch( pParams->nProfile ){
  255.             case P_MAIN:
  256.                 bstrIn = ::SysAllocString(L"MP");
  257.                 break;
  258.             case P_SIMPLE:
  259.                 bstrIn = ::SysAllocString(L"SP");
  260.                 break;
  261.             case P_COMPLEX:
  262.                 bstrIn = ::SysAllocString(L"CP");
  263.                 break;
  264.             default:
  265.                 hr = E_VIDEO_INVALID_PROFILE;
  266.                 break;
  267.             }
  268.             ::VariantInit(&varg);
  269.             varg.vt      = VT_BSTR;
  270.             varg.bstrVal = bstrIn;
  271.             hr = pPropertyBag->Write( g_wszWMVCDecoderComplexityRequested, &varg );
  272.             ::SysFreeString( bstrIn );
  273.             if( FAILED( hr ) ){
  274.                 hr = E_VIDEO_PROFILE_REJECTED;
  275.                 break;
  276.             }
  277.         }
  278.         
  279.         // set the ecoder complexity
  280.         ::VariantInit(&varg);
  281.         varg.vt = VT_I4;
  282.         varg.lVal = pParams->nComplexity;
  283.         hr = pPropertyBag->Write(g_wszWMVCComplexityEx, &varg);
  284.         if( FAILED( hr ) ){
  285.             hr = E_VIDEO_COMPLEXITY_REJECTED;
  286.             break;
  287.         }
  288.         
  289.         // set the max distance between the key frames
  290.         ::VariantInit(&varg);
  291.         varg.vt = VT_I4;
  292.         varg.lVal = pParams->nKeyDist * 1000;
  293.         hr = pPropertyBag->Write( g_wszWMVCKeyframeDistance, &varg );
  294.         if( FAILED( hr ) ){
  295.             hr = E_VIDEO_KEYDIST_REJECTED;
  296.             break;
  297.         }
  298.         
  299.         // set the crispness params for WMV# only
  300.         if( pParams->dwTag == WMCFOURCC_WMV3 ){
  301.             ::VariantInit(&varg);
  302.             varg.vt = VT_I4;
  303.             varg.lVal = pParams->nQuality;
  304.             hr = pPropertyBag->Write( g_wszWMVCCrisp, &varg );
  305.             if( FAILED( hr ) ){
  306.                 hr = E_VIDEO_CRISPNESS_REJECTED;
  307.                 break;
  308.             }
  309.         }
  310.         
  311.     } while( FALSE );
  312.     SAFERELEASE( pPropertyBag );
  313.     return hr;
  314. }
  315. //////////////////////////////////////////////////////////////////////////////
  316. //
  317. // DefaultVideoBitrate
  318. //
  319. //////////////////////////////////////////////////////////////////////////////
  320. // a decent guess would be 0.4 bits per pixel
  321. HRESULT DefaultVideoBitrate( AM_MEDIA_TYPE *pmt, double dFramesPerSec, int *pBitrate ){
  322.     if( pmt == NULL || pBitrate == NULL )
  323.         return E_INVALIDARG;
  324.     
  325.     if( pmt->pbFormat == NULL || pmt->cbFormat <= 0 )
  326.         return E_INVALIDARG;
  327.     
  328.     if( pmt->formattype == FORMAT_VideoInfo ){
  329.         VIDEOINFOHEADER *pvih = (VIDEOINFOHEADER*)pmt->pbFormat;
  330.         
  331.         // 0.4 bits per pixel will generate good quality content at a reasonable bitrate
  332.         *pBitrate = ( pvih->bmiHeader.biWidth * pvih->bmiHeader.biHeight * 2 ) / 5;
  333.         if( dFramesPerSec == 0 ) { // use the input rate
  334.             if( pvih->AvgTimePerFrame > 0 )
  335.                 dFramesPerSec = 10000000.0 / pvih->AvgTimePerFrame;
  336.             else
  337.                 dFramesPerSec = 29.97;   // 30 frames per sec
  338.         }
  339.     } else if( pmt->formattype == FORMAT_VideoInfo2 ){
  340.         VIDEOINFOHEADER2 *pvih = (VIDEOINFOHEADER2*)pmt->pbFormat;
  341.         
  342.         // 0.4 bits per pixel will generate good quality content at a reasonable bitrate
  343.         *pBitrate = ( pvih->bmiHeader.biWidth * pvih->bmiHeader.biHeight * 2 ) / 5;
  344.         
  345.         if( dFramesPerSec == 0 ) { // use the input rate
  346.             if( pvih->AvgTimePerFrame > 0 )
  347.                 dFramesPerSec = 10000000.0 / pvih->AvgTimePerFrame;
  348.             else
  349.                 dFramesPerSec = 29.97;   // 30 frames per sec
  350.         }
  351.     } else
  352.         return E_VIDEO_INVALID_INPUT_TYPE;
  353.     *pBitrate = (int)( *pBitrate * dFramesPerSec );
  354.     
  355.     return S_OK;
  356. }
  357. //////////////////////////////////////////////////////////////////////////////
  358. //
  359. // InitializeVideoEncoder
  360. //
  361. //////////////////////////////////////////////////////////////////////////////
  362. HRESULT InitializeVideoEncoder(  AM_MEDIA_TYPE *pmtInput, 
  363.                                CVideoEncParams *pParams, 
  364.                                IMediaObject   *pDMO,  
  365.                                AM_MEDIA_TYPE  *pmtOutput){
  366.     HRESULT       hr;
  367.     DWORD         cbInputBuffer  = 0;
  368.     DWORD         cbOutputBuffer = 0;
  369.     
  370.     if( pmtInput == NULL || pParams == NULL || pDMO == NULL )
  371.         return E_INVALIDARG;
  372.     
  373.     
  374.     
  375.     //check to see if the video bitrate has been set; if not calculate the default
  376.     if( pParams->nBitrate <= 0 )
  377.     {
  378.         hr = DefaultVideoBitrate( pmtInput, pParams->fFrameRate, &pParams->nBitrate );
  379.         if( FAILED( hr ) )
  380.             return hr;
  381.     }
  382.     
  383.     
  384.     
  385.     hr = SetVideoParams( pDMO, pParams );
  386.  //   ON_FAIL("Failed SetVideoParams", hr)
  387.         
  388.         
  389.         // cbInputBuffer and cbOutputBuffer are actually not used here.
  390.         hr = SetVideoTypes( pDMO, pmtInput, pParams, pmtOutput, &cbInputBuffer, &cbOutputBuffer );
  391.     if( FAILED( hr ) )
  392.     {
  393.   //      ON_FAIL("Failed SetVideoTypes", hr)
  394.             return hr;
  395.     }
  396.     return hr;     
  397. }
  398. HRESULT CCaptureGraph::GetInputMediaType(IBaseFilter* pCap, AM_MEDIA_TYPE& mt)
  399. {
  400. HRESULT hr;
  401. IAMStreamConfig *pSC = NULL;
  402. AM_MEDIA_TYPE* lpmt = NULL;
  403. //获得lpgraphBuilder2_
  404. CComPtr<ICaptureGraphBuilder2> lpgraphBuilder2_;
  405. hr = lpgraphBuilder2_.CoCreateInstance(CLSID_CaptureGraphBuilder2);
  406. if (FAILED(hr))
  407. {
  408. return hr;
  409. }
  410. hr = lpgraphBuilder2_->SetFiltergraph(m_pGB);
  411. //查询接口
  412. hr = lpgraphBuilder2_->FindInterface(&PIN_CATEGORY_CAPTURE,
  413. &MEDIATYPE_Interleaved, m_pVideoCapture,
  414. IID_IAMStreamConfig, (void **)&pSC);
  415. if(hr != NOERROR)
  416. hr = lpgraphBuilder2_->FindInterface(&PIN_CATEGORY_CAPTURE,
  417. &MEDIATYPE_Video, m_pVideoCapture,
  418. IID_IAMStreamConfig, (void **)&pSC);
  419. if (!FAILED(hr))
  420. {
  421. hr = pSC->GetFormat(&lpmt);
  422. mt = *lpmt;
  423. pSC->Release();
  424. }
  425. /*
  426.     CComPtr<IBaseFilter> pDummyFilter;
  427. CComPtr<IPin> pCapOutPin;
  428.     hr = AddFilter(CLSID_NullRenderer, &pDummyFilter, "Dummy Filter");
  429. if(FAILED(hr))
  430. {
  431. TRACE("Failed to create dummy filter!");
  432. return hr;
  433. }
  434.     hr = ConnectPins(pCap, NULL, pDummyFilter, NULL, &mt);
  435. if(FAILED(hr))
  436. {
  437. TRACE("Failed to connect dummy filter!");
  438. return hr;
  439. }
  440.     
  441.     pCapOutPin = FindPinOnFilter(pCap, NULL, PINDIR_OUTPUT);
  442. if(pCapOutPin == NULL)
  443. {
  444. TRACE("Failed to get capture out pin!");
  445. return E_FAIL;
  446. }
  447.     hr = pCapOutPin->ConnectionMediaType(&mt);
  448. if(FAILED(hr))
  449. {
  450. TRACE("Failed to get connection media type!");
  451. return hr;
  452. }
  453.     hr = pCapOutPin->Disconnect();
  454. if(FAILED(hr))
  455. {
  456. TRACE("Failed to disconnect capture out pin!");
  457. return hr;
  458. }
  459.     //now disconnect and remove dummy filter
  460.     hr = m_pGB->RemoveFilter(pDummyFilter);
  461. if(FAILED(hr))
  462. {
  463. TRACE("Failed to remove dummy filter!");
  464. return hr;
  465. }
  466. */
  467.     return hr;
  468. }
  469. extern CVideoEncParams g_VideoEncodingParams;
  470. HRESULT ConfigureDMO(IMediaObject* pDMO, AM_MEDIA_TYPE* pmtIn, AM_MEDIA_TYPE* pmtOut)
  471. {
  472.     HRESULT hr;
  473.     if ( FORMAT_VideoInfo  == pmtIn->formattype  || FORMAT_VideoInfo2 == pmtIn->formattype )
  474.     {
  475.         hr = InitializeVideoEncoder( pmtIn, &g_VideoEncodingParams, pDMO, pmtOut );
  476.     }
  477.     else 
  478.     {
  479.         FreeMediaType( *pmtIn );
  480.         memset( pmtIn, 0, sizeof( AM_MEDIA_TYPE ) );
  481.         hr = E_FAIL;
  482.     }
  483.     
  484.     return hr;
  485. }