我目前在使音频和视频流保持同步时遇到问题。
这些是我使用的AVCodecContexts:
视频:
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
然后我使用avcodec_encode_video2()对帧进行编码。在此之后,我调用以下内容来设置时间戳:
ffmpeg.av_packet_rescale_ts(&packet, videoCodecContext->time_base, videoStream->time_base);
这完美播放。
然而,当我为音频做同样的事情时,视频以慢动作播放,首先播放音频,然后随后播放视频而没有声音。
我无法找到如何在MP4文件中设置视频/音频的pts / dts位置的示例。任何帮助的例子都会很棒!
另外,我先写视频帧,之后(一旦写完)我就写了音频。我已使用评论中建议的调整值更新了此问题。
我上传了一个测试视频,以便在此显示我的搜索结果:http://www.filedropper.com/test_124
答案 0 :(得分:1)
PS:查看 A/V Sync with FFmpeg 上的这篇文章/教程。如果以下情况没有,它可能对您有帮助。
1)关于视频&音频时间戳......
不是使用当前frameIndex
作为时间戳,而是稍后重新缩放它们。如果可能,请跳过重新缩放。
另一种方法是通过使用视频的每秒帧数(FPS)来确保首先正确创建PTS值(在outputFrame->pts
中)。要做到这一点......
对于每个视频帧:outputFrame->pts = (1000 / FPS) * frameIndex;
(对于30 FPS视频,第1帧有0时间,第30帧时间"时钟"已达到1秒。
因此,1000/30现在为每个视频帧提供33.333毫秒的显示间隔。当frameIndex
为30时,我们可以说33.333 x 30 = 1000 m.secs(或1秒,确认每秒30帧)。
对于每个音频框架:outputFrame->pts = ((1024 / 48000) * 1000) * frameIndex;
(由于48khz AAC帧的持续时间为21.333 m.secs,时间戳增加了该时间量。公式为:(1024 PCM / SampleRate)x 1000 ms / perSec)然后乘以帧索引)。
2)关于音频设置......
比特率:
如果你的audioCodecContext->bit_rate = 64000;
是48000Hz(我假设你的位深度是每个样本16位?),sample_rate
似乎很奇怪。
尝试将96000
或128000
作为最低起始值。
相框尺寸:
int AVCodecContext::frame_size
表示" 每个频道的样本数量 音频帧" 。
考虑到Docs的上述引用,并且MPEG AAC不会每个频道"" (因为两个L / R通道的数据都包含在每个帧内)。每个AAC帧可容纳1024个PCM样本。
audioCodecContext->frame_size = 88200;
的大小,您可以尝试= 1024;
个人资料:
我注意到您已将MAIN
用于AAC配置文件。我过去常常在视频中看到Low Complexity
。我在我的硬盘上尝试了一些随机的MP4文件来自各种来源,我找不到使用" Main"轮廓。作为最后的手段,测试"低复杂性"不会受伤。
尝试使用audioCodecContext->profile = ffmpeg.FF_PROFILE_AAC_LOW;
PS:选中 possible AAC issue (具体取决于您的FFmpeg版本)。
答案 1 :(得分:1)
解决了这个问题。在设置帧PTS位置后,我添加了一个新功能来设置视频/音频位置。
视频只是通常的增量(每帧+1),而音频按如下方式完成:
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;
}