音频转码 via Media Foundation

  • Media Foundation 简介
  • Media Foundation 转码音频
    • Transcoding 流程图
    • Transcoding 代码
      • setTranscodeProfile 函数
        • CTranscodeTopoBuilder::_setAudioAttributes 函数
        • CTranscodeTopoBuilder::_setContainerAttributes 函数
      • CTranscodeTopoBuilder::createTranscodeTopology 函数
      • IMFAsyncCallback::Invoke 函数
  • 其他框架的转码

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

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 上推出第二种编程模型,内含 SourceReader、Transcode API 、SinkWriter 及 MFPlay 等高度封装模块,大大简化了 MF 的使用难度。

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

Media Foundation 转码音频

Transcoding 流程图

Transcoding 代码

以下是整个 MF 转码过程的概要代码,略去 TopoBuilder 类的实现:

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以上系统默认支持 AAC 和 WMA encoder。

HRESULT CTranscodeApi::_setTranscodeProfile(LPCTSTR pszOutputFile)
{HRESULT hr = E_NOTIMPL;LPCTSTR ext = pszOutputFile + _tcslen(pszOutputFile) - 3;if (_tcsicmp(ext, _T("aac")) == 0) {hr = m_topoBuilder.SetTranscodeProfile(MFAudioFormat_AAC,           GUID_NULL,               MFTranscodeContainerType_MPEG4);     }else if (_tcsicmp(ext, _T("wma")) == 0) {hr = m_topoBuilder.SetTranscodeProfile(MFAudioFormat_WMAudioV9,           GUID_NULL,                MFTranscodeContainerType_ASF);     }return hr;
}HRESULT CTranscodeTopoBuilder::setTranscodeProfile(const GUID& audioFormat,    // target audio formatconst GUID& videoFormat,    // target video formatconst 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 函数

枚举所有支持的输出媒体类型并选择第一个。

HRESULT CTranscodeTopoBuilder::_setAudioAttributes(const GUID& audioFormat)
{HRESULT hr = S_OK;CComPtr<IMFCollection> pAudioTypeCollection;CComPtr<IMFAttributes> pAudioAttrs;// enumerate all of the audio encoders that match the specified// parameters and find all audio types that can be generated. DWORD dwFlags = (MFT_ENUM_FLAG_ALL & (~MFT_ENUM_FLAG_FIELDOFUSE))   | MFT_ENUM_FLAG_SORTANDFILTER;  hr = MFTranscodeGetAudioOutputAvailableTypes(audioFormat,                      // specify the requested audio formatdwFlags,                          // get all MFTs except for the FOU, and sortNULL,                             // no custom attributes&pAudioTypeCollection);           // store result in specified collectionRETURN_IF_FAILED(hr);// get the first element from the collection of media types, // copy all the information of the first type into a new attribute// collection, and return the attribute collectionhr = getTypeAttributesFromTypeCollection(pAudioTypeCollection, 0, pAudioAttrs);RETURN_IF_FAILED(hr);hr = m_pTranscodeProfile->SetAudioAttributes(pAudioAttrs);RETURN_IF_FAILED(hr);return hr;
}

CTranscodeTopoBuilder::_setContainerAttributes 函数

设置媒体容器的类型,如 MP3,AVI 等。

HRESULT CTranscodeTopoBuilder::_setContainerAttributes(const GUID& containerType)
{HRESULT hr = S_OK;CComPtr<IMFAttributes> pContainerAttributes;RETURN_IF_NULL(m_pTranscodeProfile);hr = MFCreateAttributes(&pContainerAttributes, 1);RETURN_IF_FAILED(hr);// store an attribute that indicates that we want to write to an ASF filehr = pContainerAttributes->SetGUID(MF_TRANSCODE_CONTAINERTYPE,         // attribute ID GUID - container typecontainerType);                     // generate the specified containerRETURN_IF_FAILED(hr);// store the container attributes in the transcode profilehr = m_pTranscodeProfile->SetContainerAttributes(pContainerAttributes);RETURN_IF_FAILED(hr);return hr;
}

CTranscodeTopoBuilder::createTranscodeTopology 函数

MF 提供了 transcoding 专用的 topology。

HRESULT CTranscodeTopoBuilder::createTranscodeTopology(PCWSTR pszInput, PCWSTR pszOutput)
{HRESULT hr = S_OK;// standard media source creationhr = createMediaSource(pszInput, m_pSource);RETURN_IF_FAILED(hr);// create the actual transcode topology based on the transcode profilehr = MFCreateTranscodeTopology(m_pSource,                      // the source of the content to transcodepszOutput,                      // output filenamem_pTranscodeProfile,            // transcode profile to use&m_pTopology);                  // resulting topologyRETURN_IF_FAILED(hr);return hr;
}

IMFAsyncCallback::Invoke 函数

Media Session 的 所有事件 都会回调这里。当收到 MESessionEnded 事件时就说明转码结束了。
注意:转码未完时要重新 BeginGetEvent,不然就傻傻等不到下一个事件了。

HRESULT CTranscodeApi::Invoke(IMFAsyncResult* pAsyncResult)
{CComPtr<IMFMediaEvent> pEvent;HRESULT hr = S_OK;MediaEventType eventType;// Get the event from the event queue.hr = m_pSession->EndGetEvent(pAsyncResult, &pEvent);RETURN_IF_FAILED(hr);// Get the event type.hr = pEvent->GetType(&eventType);RETURN_IF_FAILED(hr);if (eventType == MESessionEnded) {hr = m_pSession->Close();}else if (eventType == MESessionClosed) {SetEvent(m_closeCompleteEvent);}else {hr = m_pSession->BeginGetEvent(this, NULL);}RETURN_IF_FAILED(hr);return S_OK;
}

其他框架的转码

  • 关于 FFmpeg 的音频转码请参考 这里。
  • 关于 DirectShow 的音频转码请参考 这里。


EOF

音频转码 via Media Foundation相关推荐

  1. 音频特效滤镜 via Media Foundation Transform (MFT)

    音频特效滤镜 via Media Foundation Transform 音频特效定义 Media Foundation Transform IMFTransform::GetInputStream ...

  2. Media Foundation

    1简介 Media Foundation是微软在Windows Vista上推出的新一代多媒体应用库,目的是提供Windows平台一个统一的多媒体影音解决方案,开发者可以通过Media Foundat ...

  3. 音视频播放 via Media Foundation II

    音视频播放 via Media Foundation II Media Foundation 简介 Media Foundation 播放音视频 播放流程图 播放代码 MFPlayer 类 MFPla ...

  4. 音频转码 via FFmpeg

    音频转码 via FFmpeg FFmpeg 简介 FFmpeg 命令行转码 FFmpeg API 转码 Transcoding 流程图 Transcoding 代码 open_input_file ...

  5. 音频转码 via DirectShow

    音频转码 via DirectShow DirectShow 简介 DirectShow 转码 Transcoding 流程图 Transcoding 代码 _initGraph 函数 _addEnc ...

  6. Android 音频源码分析——AndroidRecord录音(一)

    Android 音频源码分析--AndroidRecord录音(一) Android 音频源码分析--AndroidRecord录音(二) Android 音频源码分析--AndroidRecord音 ...

  7. Media Foundation——媒体类型(1)

    Media Foundaton对象的属性和特性 每一个对象上的数据,都可通过"属性(Attributes)"和"特性(Properties)"来设置.描述.属性 ...

  8. Microsoft Media Foundation官方文档翻译(20)《Stream Subtype GUIDs》《...

    官方英文文档链接:https://docs.microsoft.com/en-us/windows/desktop/medfound/stream-subtype-guids 基于05/31/2018 ...

  9. Media Foundation与DirectShow的具体差别有哪些

    DirectShow是微软公司在ActiveMovie和Video for Windows的基础上推出的新一代基于COM(Component Object Model)的流媒体处理的开发包,与Dire ...

最新文章

  1. C# 实现Oracle中的数据与Excel之间的转换
  2. 这68个Python内置函数,建议你吃透!
  3. SPCAMLEditor–灵活实用的CAML编辑工具(上)
  4. 结构体指针struct stu *p;和结构体变量struct stu p;结构体为什么要用指针引用而不用变量引用
  5. vsftp虚拟用户权限问题
  6. mariadb用户群体mysql_mysql(mariadb)新建用户及用户授权管理
  7. cuda和cudnn各版本下载地址
  8. 中国象棋,源码,开发,毕业设计,go,qt,c++,gin,游戏,残局,悔棋,人机,网络对战,双人
  9. python幂次_python n次幂
  10. 工厂生产管理流程有哪些环节?
  11. bmp,jpg,png,tif,wmf,emf与eps图片格式转换
  12. 求100到1000内水仙花数及个数
  13. 计算机操作员考试模拟在线考试,计算机操作员高级问答集考试卷模拟考_试题...
  14. 【独立按键鼠标式的单击与双击】
  15. 拼多多蓝海词数据分析:如何优化拼多多关键词?拼多多标题关键词优化方法。
  16. android socket 推送服务版本
  17. SqlServer Tigger
  18. Array,String 方法
  19. 联想台式机 ubuntu 16.04 安装 Nvidia GTX 1060 3g 驱动
  20. 求职与面试(一):Android必备

热门文章

  1. PHP与正则表达式 | 黄乔国PHP
  2. html video标签播放直播视频,HTML5 Video 标签播放及控制视频
  3. Qt 实现系统托盘,托盘菜单,托盘消息
  4. mysql 主备和双主模式_MySQL双主模式
  5. java out of memory_java中OutOfMemory种类和解决方法
  6. 对称与魔术初步(一)——美丽的对称
  7. vm虚拟机中的虚拟网络编辑器出现 不能更改网络为桥接:已经没有桥接的主机网络适配器的 解决方案
  8. python保存灰度图像_如何使用matplotlib/numpy将数组保存为灰度图像?
  9. 关于keil常见问题解决方法记录error: #268: declaration may not appear after executable statement in block
  10. 张勇:阿里巴巴所有产品未来将接入大模型全面改造