本主题介绍何时以及如何使用 H.264/AVC Remux MFT 和 MP4 接收器。
何时使用 H.264/AVC Remux MFT
MPEG-4 文件格式要求每个压缩样本包含一张主图片,其 NAL 单位顺序正确。 (请参阅 H.264 AVC 规范的第 7.4.1.2.3 节“ NAL 单位顺序和编码图片与访问单位的关联”中的主图片和强制 NAL 单位顺序的定义。) 它还要求每个压缩样本与演示时间戳、解码时间戳和样本持续时间相关联。
在许多情况下,当应用程序需要在 MPEG-4 文件容器中录制 H.264/AVC 视频时,压缩示例可能无法满足上述要求。 例如,一个压缩的示例可能不包含完整的主图片,或者可能没有与之关联的正确演示时间戳。 一些应用程序示例包括:
- 将 H.264/AVC 流式处理基本视频写入 MPEG-4 文件容器。
- 在 MPEG-4 文件容器中录制相机捕获的 H.264/AVC 基本视频。
- 在 MPEG-4 文件容器中录制 H.264/AVC 视频会议。
- 在 MPEG-2 TS 或 MP4 中连接两个 H.264/AVC 视频,并使用正确的时间戳写入 MPEG-4 文件容器。
- 将 H.264/AVC 视频从 AVCHD、MPEG-2 TS/PS 文件格式转换为 MPEG-4 文件格式。
- 在不转码的情况下剪裁 H.264/AVC 视频文件。
在这种情况下,应用程序需要使用 H.264/AVC remux MFT 来转换不包含完整主图片的压缩样本,然后再将其写入 MPEG-4 文件容器。
如何使用 H.264/AVC Remux MFT 和 MP4 接收器
将源输出媒体类型设置为 MFVideoFormat_H264_ES,这表示每个示例可能不包含完整的主图片。 将 MP4 接收器的输入媒体类型设置为 MFVideoFormat_H264。 因此,H.264/AVC remux MFT 的输入媒体类型 MFVideoFormat_H264_ES 并且 H.264/AVC remux MFT 的输出媒体类型 MFVideoFormat_H264,这将自动插入拓扑解析程序。
H.264/AVC remux 会忽略样本持续时间,因为不包含完整主图片的样本的样本持续时间没有明确的含义。 相反,采样持续时间是从帧速率计算的。 帧速率是从序列参数计算得出的。 如果序列参数中不存在信息,则从输入媒体类型中的参数计算帧速率。 如果帧速率信息不可用,则使用默认帧速率 29.97 fps。
H.264/AVC remux MFT 根据帧速率对每个压缩图片 (DTS) 线性内插解码时间戳。 H.264/AVC remux MFT 遵循输入样本中 PTS) (输入表示时间戳,并将它们传递到输出(如果存在)。 它根据帧速率、以前的 PTS 和图片输出顺序,通过解码的图片缓冲 (DBP 执行 PTS 内插,) H.264 AVC 规范的附件 C.4.5.3 凸起过程 。 H.264/AVC remux MFT 的每个输出样本应具有 PTS、DTS 和采样持续时间。 H.264/AVC remux MFT 还标识位流中的IDR图片,并使用 MFSampleExtension_CleanPoint的 MF 属性将它们设置为清洁点。
目前,H.264/AVC remux MFT 最多可处理 64 个重新排序的帧。 如果重新排序的帧数超过 64,并且存在长期参考帧,则 H.264/AVC remux MFT 将为该帧内插错误的 PTS,并在错误的时间输出该帧。
若要实例化 H.264/AVC remux MFT,请在 H.264/AVC remux MFT 上设置正确的输入和输出媒体类型,设置 MP4 接收器的输入媒体类型,并解析拓扑。
以下示例代码演示如何初始化 H.264/AVC remux MFT 和 MP4 接收器。
对于 H.264/AVC remux MFT,
hr = CoCreateInstance(
CLSID_CMSH264RemuxMFT,
NULL,
CLSCTX_INPROC_SERVER,
IID_IMFTransform,
(void**) &pIMFTransform
);
无需进行任何其他配置。
对于 MP4 接收器,
IMFByteStream* pMFBSOutputFile = NULL;
hr = MFCreateFile(
MF_ACCESSMODE_READWRITE,
MF_OPENMODE_DELETE_IF_EXIST,
MF_FILEFLAGS_NONE,
m_pszOutputFile,
&pMFBSOutputFile);
if(FAILED(hr))
{
Log(L"ERROR>> Failed to create output file for MP4 Sink (hr=0x%x)", hr);
break;
}
hr = MFCreateMPEG4MediaSink(
pMFBSOutputFile,
(guidMajorType == MFMediaType_Video) ? pMediaType : NULL, // pMediaType comes from the output type of the remux MFT
(guidMajorType == MFMediaType_Audio) ? pMediaType : NULL,
&m_pMediaSink);
if(FAILED(hr))
{
Log(L"ERROR>> Failed to create MP4 Sink (hr=0x%x)", hr);
break;
}
hr = m_pMediaSink->GetStreamSinkByIndex(0, &pStream);
相关主题