Windows 媒体基础:IMFSinkWriter WriteSample API 未设置返回错误 sampleduration

Windows Media foundation: IMFSinkWriter WriteSample API returning error sampleduration is not set

我需要接收 RTP 流 (H264) 并将它们导出到 MP4 文件。我们正在使用媒体基础将 RTP 流中接收到的帧导出到 mp4 文件。因此,我们提取 H264 帧(从 RTP 数据包中)并通过 WriteSample API(采样时间、采样持续时间等已设置)将其提供给 sinkwriter。这似乎有效,我得到了可播放的 mp4。 但是当我不设置样本持续时间(使用 SetSampleDuration API)时,writeSample 会抛出错误 (MF_E_NO_SAMPLE_DURATION)。前几帧不会抛出错误,但只会在一定时间后(1.48 秒后的帧)a 问题: 1. 为什么需要 SetSampleDuration?我假设如果我们为每个样本提供样本时间,则不需要样本持续时间。 Sink writer 可以计算当前帧和上一帧之间的差异作为样本持续时间 2. 为什么writeSample API 前几帧不报错。WriteSample 只在一定时间后(1.48 秒后的帧)才会报错。它是否特定于某些框架。 3. 如何做 当帧间持续时间不均匀时,我们理想地设置采样持续时间。在我的例子中,平均 fps 是 15,但 2 帧之间的时间不均匀。 (以毫秒为单位的帧时间戳:0、83,133、200、283,333,400,...) 3.1 要设置帧的采样持续时间,等待下一帧并从下一帧时间戳中减去当前帧时间戳。应用程序是否应该推迟到下一帧可用 3.2 根据平均fps设置采样持续时间是可以的(即使帧之间的时间差不均匀)。 (注意:我尝试了 3.2 并且它有效。我在视觉上看不到任何问题。这可能是因为帧之间的时间差不统一但变化不大。但我不确定这是否可以。我应该去寻求方法吗3.1)

你有很多不同的问题。

对于设置时间戳和持续时间,我建议检查 documentation。它解释了时间戳与呈现时间等的关系

要设置持续时间,您应该使用源流的采样率。如果以 H264 的正常 90KHz 速率采样,则在 15fps 下每个采样的持续时间为 66ms。 Media Foundation 示例使用 100's of nano seconds 的时间戳分辨率,因此 IMFSample 持续时间应为 660000。您的 RTP header 时间戳也应在 15ps 时具有 6000 的间距(6000 x 15 = 90000) .

对于时间戳,因为您要将它保存到文件中,所以您应该从 0 开始,并且每次您获得样本持续时间 660000 的样本增量。

  1. Why SetSampleDuration is needed?I assumed that we don't need sample duration if we are providing sample time for every sample. Sink writer can calculate difference between the current frame and last frame as sample duration

  2. Why the error is not thrown for first few frames by writeSample API .WriteSample throws error only after certain time(frame after 1.48 seconds). Is it specific to certain frames.

示例可以不附加持续时间,对吧。但是您正在使用的媒体接收器期望存在持续时间,因此您必须将它们放在那里。或者您不能使用水槽,因为它不兼容。

您的输入被异步排队和处理。这解释了为什么您没有立即收到错误。

  1. ... But in the stream the RTP timestamps are 0, 7470, 11970, 18000,.... The spacing is not uniform but overall we get 15 frames in a second. How to set duration in this scenario: 1. Set is as 660000 for all sample or 2.For first sample set duration as (83-0)* 10000 and for second sample set duration as (133-83)*10000

这道题既简单又困难。当 sink 创建输出文件时,MP4 格式有自己的假设和期望,其中有一个轨道,具有自己的时间刻度值。尽管它在技术上可以遵循您的有效时序并在那里保持 90 kHz 值,但它是在假设视频流具有固定帧速率的情况下进行的。接收器获取您的 MF_MT_FRAME_RATE 属性值并从中导出计时。此外,Windows 更新甚至可能使行为变得更严格或更宽松,因为没有记录具体行为,也没有承诺。

解决这个问题需要权衡取舍。一种选择是将帧时间重新调整为统一的固定速率时间戳序列。另一种解决方案可能是指示更高的速率并期望您的真实帧与 "dropped" 帧混合。您需要尝试找到适合您的方法。 MP4 文件最终将具有一个时间刻度值,并且各个帧时间将表示为相对于该频率递增的整数值。

如果编码器、网络流或捕获为您提供 time/duration,请使用它们,尊重它们。

这将是保存 audio/video 演示文稿的最佳方式。

我不能在这里详细说明,但你不能告诉这个:

Sink writer can calculate difference between the current frame and last frame

比这更复杂