视频转码 via Media Foundation

转码(transcoding)其实就是把音频从一种编码转换成另一种编码的过程,如 mpg2 → h.264。基本流程如下图:
transcoding

Media Foundation 简介

Media Foundation (简称 MF)是微软在 Windows Vista上 推出的新一代多媒体应用库,目的是提供 Windows 平台一个统一的多媒体影音解决方案,开发者可以通过 MF 播放视频或声音文件、进行多媒体文件格式转码,或者将一连串图片编码为视频等等。

MF 是 DirectShow 为主的旧式多媒体应用程序接口的替代者与继承者,在微软的计划下将逐步汰换 DirectShow 技术。MF 要求 Windows Vista 或更高版本,不支持较早期的 Windows 版本,特别是 Windows XP。
MF 长于高质量的音频和视频播放,高清内容(如 HDTV,高清电视)和数字版权管理(DRM)访问控制。MF 在不同的 Windows 版本上能力不同,如 Windows 7 上就添加了 h.264 编码支持。Windows 8 上则提供数种更高质量的设置。

MF 提供了两种编程模型,第一种是以 Media Session 为主的 Media pipeline 模型,但是该模型太过复杂,且曝露过多底层细节,故微软于 Windows 7 上推出第二种编程模型,内含 SourceReaderTranscode APISinkWriterMFPlay 等高度封装模块,大大简化了 MF 的使用难度。

# 本文使用了第二种(简单的)编程模型。

Media Foundation 转码视频

Transcoding 流程图

mf transcode

Transcoding 代码

以下是整个转码过程的概要代码,略去各个函数的具体实现和资源释放:

HRESULT CTranscodeApi::transcodeFile(PCWSTR pszInput, PCWSTR pszOutput)
{
    HRESULT hr = S_OK;
    CComPtr<IMFTopology> pTopology; 
    hr = MFCreateMediaSession(NULL, &m_pSession);
    RETURN_IF_FAILED(hr);
    
    hr = m_pSession->BeginGetEvent((IMFAsyncCallback*)this, NULL);
    RETURN_IF_FAILED(hr);
    
    hr = _setTranscodeProfile(pszOutput);
    RETURN_IF_FAILED(hr);
    
    hr = m_topoBuilder.createTranscodeTopology(pszInput, pszOutput);
    RETURN_IF_FAILED(hr);
    
    pTopology = m_topoBuilder.getTopology();
    hr = m_pSession->SetTopology(0, pTopology);
    if (SUCCEEDED(hr)) {
        PROPVARIANT varStart;
        PropVariantClear(&varStart);
        hr = m_pSession->Start(&GUID_NULL, &varStart);
    }
    
    return hr;
}

setTranscodeProfile 函数

Windows7 以上系统默认支持 MP4 和 WMV。

HRESULT CTranscodeApi::_setTranscodeProfile(LPCTSTR pszOutputFile)
{
    HRESULT hr = E_NOTIMPL;

    LPCTSTR ext = pszOutputFile + _tcslen(pszOutputFile) - 3;
    if (_tcsicmp(ext, _T("mp4")) == 0) {
        hr = m_topoBuilder.SetTranscodeProfile(
            MFAudioFormat_AAC,           
            MFVideoFormat_H264,               
            MFTranscodeContainerType_MPEG4);     
    }
    else if (_tcsicmp(ext, _T("wmv")) == 0) {
        hr = m_topoBuilder.SetTranscodeProfile(
            MFAudioFormat_WMAudioV9,           
            MFVideoFormat_WMV3,                
            MFTranscodeContainerType_ASF);     
    }

    return hr;
}

HRESULT CTranscodeTopoBuilder::setTranscodeProfile(
    const GUID& audioFormat,    // target audio format
    const GUID& videoFormat,    // target video format
    const GUID& containerType)  // target file container 
{
    HRESULT hr = S_OK;
    hr = MFCreateTranscodeProfile(&m_pTranscodeProfile);
    RETURN_IF_FAILED(hr);
        
    hr = _setAudioAttributes(audioFormat);
    RETURN_IF_FAILED(hr);

    hr = _setVideoAttributes(videoFormat);
    RETURN_IF_FAILED(hr);

    hr = _setContainerAttributes(containerType);
    RETURN_IF_FAILED(hr);

    return hr;
}
CTranscodeTopoBuilder_setAudioAttributes 函数

请看 这里,一模一样。

CTranscodeTopoBuilder::_setVideoAttributes 函数

设置视频基本属性,如宽高、帧率、比特率等等。

HRESULT CTranscodeTopoBuilder::_setVideoAttributes(const GUID& videoFormat)
{
    HRESULT hr = S_OK;
    CComPtr<IMFCollection> pVideoTypeCollection;
    CComPtr<IMFAttributes> pVideoAttrs;
    DWORD dwFlags = 0;
    dwFlags = (MFT_ENUM_FLAG_ALL & (~MFT_ENUM_FLAG_FIELDOFUSE)) | MFT_ENUM_FLAG_SORTANDFILTER; 
    hr = getVideoOutputAvailableTypes( videoFormat, dwFlags, pVideoTypeCollection );
    RETURN_IF_FAILED(hr);
    
    hr = getTypeAttributesFromTypeCollection( pVideoTypeCollection, 0, pVideoAttrs );
    RETURN_IF_FAILED(hr);        
    
    hr = MFSetAttributeSize( pVideoAttrs, MF_MT_FRAME_SIZE, 720, 576 ); 
    RETURN_IF_FAILED(hr);  
    
    hr = MFSetAttributeRatio( pVideoAttrs, MF_MT_FRAME_RATE, 30000, 1001 );
    RETURN_IF_FAILED(hr);  
    
    hr = pVideoAttrs->SetUINT32( MF_MT_AVG_BITRATE, 1000000 );
    RETURN_IF_FAILED(hr);  
    
    hr = m_pTranscodeProfile->SetVideoAttributes(pVideoAttrs);
    RETURN_IF_FAILED(hr);
    
    return hr;
}
CTranscodeTopoBuilder::_setContainerAttributes 函数

请看 这里,一模一样。

CTranscodeTopoBuilder::createTranscodeTopology 函数

请看 这里,一模一样。

IMFAsyncCallback::Invoke 函数

请看 这里,一模一样。

其他框架的转码

关于 FFmpeg 的视频转码请参考 这里

Blueware
EOF

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值