繁体   English   中英

Media Foundation视频重新编码产生音频流同步偏移

[英]Media Foundation video re-encoding producing audio stream sync offset

我试图编写一个简单的Windows Media Foundation命令行工具,以使用IMFSourceReaderIMFSyncWriter加载视频,将视频和音频读取为未压缩的流,并使用一些特定的硬编码将其重新编码为H.246 / AAC设置。

简单的程序Gist在这里

范例影片1

样本视频2

范例影片3

(注意:我一直在测试的视频均为立体声,采样率为48000k)

该程序可以运行,但是在某些情况下,在编辑程序中将新输出的视频与原始视频进行比较时,我看到复制的视频流匹配,但是复制的音频流预先固定了一些静默,并且音频抵消了,这在我的情况下是不可接受的。

audio samples:
original - |[audio1] [audio2] [audio3] [audio4] [audio5] ... etc
copy     - |[silence] [silence] [silence] [audio1] [audio2] [audio3] ... etc

在这种情况下,进入的第一个视频帧的时间戳为非零,但第一个音频帧的时间戳为0。

我希望能够从视频和音频流中产生第一帧的复制视频,所以我首先尝试从所有后续视频帧中减去该初始时间戳( videoOffset ),从而产生了我想要的视频,但导致这种情况与音频:

original - |[audio1] [audio2] [audio3] [audio4] [audio5] ... etc
copy     - |[audio4] [audio5] [audio6] [audio7] [audio8] ... etc

现在,音轨向另一个方向移动了少量,但仍未对齐。 有时,当视频流的开始时间戳确实为0时, WMF仍会在开始时切断一些音频样本(请参见样本视频3),有时也会发生这种情况!

我已经能够解决此同步对齐问题,并在将音频样本数据传递给IMFSinkWriter插入了以下代码,从而将视频流偏移为从0开始:

//inside read sample while loop
...

// LONGLONG llDuration has the currently read sample duration
// DWORD audioOffset has the global audio offset, starts as 0
// LONGLONG audioFrameTimestamp has the currently read sample timestamp

//add some random amount of silence in intervals of 1024 samples
static bool runOnce{ false };
if (!runOnce)
{
    size_t numberOfSilenceBlocks = 1; //how to derive how many I need!?  It's aribrary
    size_t samples = 1024 * numberOfSilenceBlocks; 
    audioOffset = samples * 10000000 / audioSamplesPerSecond;
    std::vector<uint8_t> silence(samples * audioChannels * bytesPerSample, 0);
    WriteAudioBuffer(silence.data(), silence.size(), audioFrameTimeStamp, audioOffset);

    runOnce= true;
}

LONGLONG audioTime = audioFrameTimeStamp + audioOffset;
WriteAudioBuffer(dataPtr, dataSize, audioTime, llDuration);

奇怪的是,这将创建一个与原始视频文件匹配的输出视频文件。

original - |[audio1] [audio2] [audio3] [audio4] [audio5] ... etc
copy     - |[audio1] [audio2] [audio3] [audio4] [audio5] ... etc

解决方案是在音频流的开头以1024的块大小插入额外的静音 IMFSourceReader提供的音频块大小IMFSourceReader ,填充为1024的倍数。

样本视频2的不同尝试的音轨偏移的屏幕截图

我的问题是,静音偏移似乎没有可检测的原因。 我为什么需要它? 我怎么知道我需要多少? 经过数天的努力,我偶然发现了1024个样本沉默块解决方案。

有些视频似乎只需要1个填充块,有些则需要2个或更多填充,而有些则根本不需要额外的填充!

我的问题是:

  • 有人知道为什么会这样吗?

  • 在这种情况下我是否错误地使用了Media Foundation?

  • 如果我是正确的,我如何使用视频元数据来确定是否需要填充音频流以及填充中需要有1024个静音块?

编辑:

对于上面的示例视频:

  • 示例视频1 :视频流从0开始, 不需要额外的块 ,原始数据的传递正常。

  • 示例视频2 :视频流从834166(hns)开始, 需要1 1024个静音块才能同步

  • 示例视频3 :视频流从0开始, 需要2 1024个静默块才能同步。

更新:

我尝试过的其他方法:

  • 增加第一个视频帧的持续时间以解决偏移:不产生任何效果。

我编写了另一个程序版本,以正确处理NV12格式(您无法正常使用):

EncodeWithSourceReaderSinkWriter

我将Blender用作视频编辑工具。 这是我与Tuning_against_a_window.mov的结果:

在此处输入图片说明

从底部到顶部:

  • 原始文件
  • 编码文件
  • 我通过将数字条目的“ elst”原子设置为0来更改了原始文件(我使用了Visual Studio hexa编辑器)

就像Roman R.所说的那样,MediaFoundation mp4源不使用“ edts / elst”原子。 但是Blender和您的视频编辑工具可以。 mp4源也会忽略“ tmcd”音轨。

“ edts / elst”:

编辑Atom('edts')

编辑列表可用于提示轨道...

MPEG-4文件源

MPEG-4文件源静默忽略提示轨道。

所以实际上,编码是好的。 与真实的音频/视频数据相比,我认为没有音频流同步偏移。 例如,您可以将“ edts / elst”添加到编码文件中,以获得相同的结果。

PS:在编码文件上,我为音频/视频轨道添加了“ edts / elst”。 我还增加了trak原子和moov原子的大小。 我确认,Blender对于原始文件和编码文件都显示相同的波形。

编辑

在3个视频样本中,我试图了解mvhd / tkhd / mdhd / elst原子之间的关系。 (是的,我知道,我应该阅读规格。但是我很懒...)

您可以使用mp4资源管理器工具获取atom的值,也可以使用H264Dxva2Decoder项目中的mp4解析器:

H264Dxva2Decoder

Tuning_against_a_window.mov

  • tkhd视频上的最老(媒体时间):20689
  • 来自tkhd音频的最早(媒体时间):1483

GREEN_SCREEN_ANIMALS__ALPACA.mp4

  • tkhd视频上的最早(媒体时间):2002
  • 来自tkhd音频的最高级(媒体时间):1024

GOPR6239_1.mov

  • tkhd视频中的最高级(媒体时间):0
  • 来自tkhd音频的第一时间(媒体时间):0

如您所见,对于GOPR6239_1.mov,最远的媒体时间为0。这就是为什么此文件没有视频/音频同步问题的原因。

对于Tuning_against_a_window.mov和GREEN_SCREEN_ANIMALS__ALPACA.mp4,我尝试计算视频/音频偏移。 我修改了项目以考虑到这一点:

EncodeWithSourceReaderSinkWriter

目前,我还没有找到所有文件的通用计算。

我只是找到正确编码两个文件所需的视频/音频偏移量。

对于Tuning_against_a_window.mov,我在(电影时间-视频/音频mdhd时间)之后开始编码。 对于GREEN_SCREEN_ANIMALS__ALPACA.mp4,我在视频/音频主要媒体时间之后开始编码。

可以,但是我需要为所有文件找到正确的唯一计算。

因此,您有2个选择:

  • 编码文件并添加第一个原子
  • 使用右偏移量计算对文件进行编码

这取决于您的需求:

  • 第一个选项允许您保留原始文件。但是您必须添加第一个原子
  • 使用第二个选项,您必须在编码之前从文件中读取原子,并且编码后的文件将丢失一些原始帧

如果选择第一个选项,我将说明如何添加第一个原子。

PS:我对此问题很感兴趣,因为在我的H264Dxva2Decoder项目中,edts / elst原子在我的待办事项列表中。 我解析它,但我不使用它...

PS2:该链接听起来很有趣: 音频启动-AAC中的编码器延迟处理

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM