C# 使用AutoGen FFmpeg库在MP4中同步音频/视频

C# 使用AutoGen FFmpeg库在MP4中同步音频/视频,c#,c++,ffmpeg,synchronization,mp4,C#,C++,Ffmpeg,Synchronization,Mp4,我目前在使音频和视频流保持同步方面遇到问题 以下是我正在使用的AVCODEC上下文: 视频: AVCodec* videoCodec = ffmpeg.avcodec_find_encoder(AVCodecID.AV_CODEC_ID_H264) AVCodecContext* videoCodecContext = ffmpeg.avcodec_alloc_context3(videoCodec); videoCodecContext->bit_rate = 400000; video

我目前在使音频和视频流保持同步方面遇到问题

以下是我正在使用的AVCODEC上下文:

视频:

AVCodec* videoCodec = ffmpeg.avcodec_find_encoder(AVCodecID.AV_CODEC_ID_H264)
AVCodecContext* videoCodecContext = ffmpeg.avcodec_alloc_context3(videoCodec);
videoCodecContext->bit_rate = 400000;
videoCodecContext->width = 1280;
videoCodecContext->height = 720;
videoCodecContext->gop_size = 12;
videoCodecContext->max_b_frames = 1;
videoCodecContext->pix_fmt = videoCodec->pix_fmts[0];
videoCodecContext->codec_id = videoCodec->id;
videoCodecContext->codec_type = videoCodec->type;
videoCodecContext->time_base = new AVRational
{
    num = 1,
    den = 30
};
对于音频:

AVCodec* audioCodec = ffmpeg.avcodec_find_encoder(AVCodecID.AV_CODEC_ID_AAC)
AVCodecContext* audioCodecContext = ffmpeg.avcodec_alloc_context3(audioCodec);
audioCodecContext->bit_rate = 1280000;
audioCodecContext->sample_rate = 48000;
audioCodecContext->channels = 2;
audioCodecContext->channel_layout = ffmpeg.AV_CH_LAYOUT_STEREO;
audioCodecContext->frame_size = 1024;
audioCodecContext->sample_fmt = audioCodec->sample_fmts[0];
audioCodecContext->profile = ffmpeg.FF_PROFILE_AAC_LOW;
audioCodecContext->codec_id = audioCodec->id;
audioCodecContext->codec_type = audioCodec->type;
在写入视频帧时,我设置PTS位置如下:

outputFrame->pts = frameIndex;  // The current index of the image frame being written
outputFrame->pts = ffmpeg.av_rescale_q(m_audioFrameSampleIncrement, new AVRational { num = 1, den = 48000 }, m_audioCodecContext->time_base);

m_audioFrameSampleIncrement += outputFrame->nb_samples;
然后我使用avcodec_encode_video2()对帧进行编码。在此之后,我调用以下命令来设置时间戳:

ffmpeg.av_packet_rescale_ts(&packet, videoCodecContext->time_base, videoStream->time_base);
这部戏演得很好

但是,当我对音频做同样的操作时,视频以慢动作播放,先播放音频,然后再继续播放视频,没有声音

我在任何地方都找不到如何在MP4文件中为视频/音频设置pts/dts位置的示例。任何帮助的例子都会很棒

另外,我先写视频帧,然后(一旦全部写好)我再写音频。我已经用评论中建议的调整值更新了这个问题


我上传了一段测试视频,在这里显示我的测试结果:

PS:查看这篇文章/教程。如果下面的选项不起作用,它可能会对您有所帮助

1)关于视频和音频时间戳

而不是使用当前的
frameIndex
作为时间戳,然后重新缩放它们。如果可能的话,跳过重新缩放

另一种方法是首先使用视频的每秒帧数(FPS),确保正确创建PTS值(在
outputFrame->PTS
)。要做到这一点

对于每个视频帧
outputFrame->pts=(1000/FPS)*帧索引
(对于每秒30帧的视频,第1帧的时间为0,到第30帧时,“时钟”已达到1秒。
因此,1000/30现在为每个视频帧提供33.333毫秒的显示间隔。当
frameIndex
为30时,我们可以说33.333 x 30=1000米秒(或1秒,确认每秒30帧)

对于每个音频帧
outputFrame->pts=((1024/48000)*1000)*frameIndex;

(由于48khz AAC帧的持续时间为21.333 m.secs,时间戳将增加该时间量。公式为:(1024 PCM/SampleRate)x 1000 ms/perSec),然后乘以帧索引)

2)关于音频设置

比特率:
audioCodecContext->比特率=64000采样率
为48000Hz(我假设,您的位深度为每个样本16位),那么code>似乎很奇怪

尝试将
96000
128000
作为最低起始值

帧大小:

int-AVCodecContext::frame_size
表示“每个通道中的采样数” “音频帧”

考虑到上述文档的引用,MPEG AAC并不是“每个通道”(因为两个L/R通道的数据都包含在每个帧中)。AAC帧每个可容纳1024个PCM样本

audioCodecContext->frame\u size=88200=1024

档案:
我注意到您已将
MAIN
用于AAC配置文件。我习惯于在视频中看到
低复杂度
。我在我的硬盘上尝试了一些来自不同来源的随机MP4文件,但我找不到一个使用“Main”配置文件的。作为最后的手段,测试“低复杂性”不会有什么坏处

尝试使用
audioCodecContext->profile=ffmpeg.FF\u profile\u AAC\u LOW


PS:检查此项是否有(取决于您的FFmpeg版本)。

解决了问题。在设置帧位置后,我添加了一个新功能来设置视频/音频位置

视频只是通常的增量(每帧+1),而音频则按如下方式进行:

outputFrame->pts = frameIndex;  // The current index of the image frame being written
outputFrame->pts = ffmpeg.av_rescale_q(m_audioFrameSampleIncrement, new AVRational { num = 1, den = 48000 }, m_audioCodecContext->time_base);

m_audioFrameSampleIncrement += outputFrame->nb_samples;
帧编码后,我调用新函数:

private static void SetPacketProperties(ref AVPacket packet, AVCodecContext* codecContext, AVStream* stream)
{
    packet.pts = ffmpeg.av_rescale_q_rnd(packet.pts, codecContext->time_base, stream->time_base, AVRounding.AV_ROUND_NEAR_INF | AVRounding.AV_ROUND_PASS_MINMAX);
    packet.dts = ffmpeg.av_rescale_q_rnd(packet.dts, codecContext->time_base, stream->time_base, AVRounding.AV_ROUND_NEAR_INF | AVRounding.AV_ROUND_PASS_MINMAX);
    packet.duration = (int)ffmpeg.av_rescale_q(packet.duration, codecContext->time_base, stream->time_base);
    packet.stream_index = stream->index;
}

错误的标记,一定是c++我正在使用AutoGen库,它使用c#中的Invoke来访问库!我不使用FFmpeg API,只使用编译后的.exe作为进程(std in/out)。很遗憾,我无法测试您的代码,但是。。。希望我的答案中的建议能对你有所帮助。哎呀,我忘了说明我关于a/v时间戳的观点。希望有帮助。这是一个非常有用的答案。需要尝试并从那里开始。outputFrame->pts=(1000/FPS)*frameIndex(用于视频帧)会导致19秒的视频在1秒内快速播放。您能否提供指向示例视频文件的临时链接?我将尝试检查字节(以找到固定值)。尝试使用44khz和128比特率。当我使用您的设置时,FFmpeg不会生成文件,但它会自动默认为使用44100 samplerate+16位深度+128kbps比特率的工作良好视频。很抱歉回复太晚。我在这里上传了视频: