我目前有问题,使我的音频和视频流保持同步。
这些是我正在使用的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文件中为视频/音频设置pt/dts位置的例子。任何帮助的例子都是很棒的!
另外,我首先要写视频帧,然后(一旦它们都写好了)我就会写音频。我用评论中建议的调整值更新了这个问题。
我上传了一个测试视频,在这里显示我的结果:124
发布于 2016-07-12 10:31:35
解决了问题。我增加了一个新的功能来设置视频/音频位置后,设置帧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;
}
发布于 2016-07-06 18:01:20
PS:查看这篇关于带FFmpeg的A/V同步的文章/教程。如果下面没有的话可能会对你有帮助。
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;
(由于48 the AAC帧的持续时间为21.333 m.secs,时间戳增加了该时间量。公式为:(1024 PCM / SampleRate) x 1000 ms/perSec,然后乘以帧索引)。
2)关于音频设置的.
位速率:
如果你的audioCodecContext->bit_rate = 64000;
是48000赫兹(我想,你的位深是16位?)
尝试将96000
或128000
作为最低起始值。
帧大小:
int AVCodecContext::frame_size
的意思是“音频帧中每个频道的样本数”。
考虑到以上引用的Docs,并且MPEG AAC不做“每个通道”(因为两个L/R通道的数据包含在每个帧中)。每个AAC帧包含1024个PCM样本。
audioCodecContext->frame_size = 88200;
的大小,您可以尝试= 1024;
配置文件:
我注意到你用MAIN
作为AAC的配置文件。我习惯在视频里看到Low Complexity
。我尝试了一些随机的MP4文件从不同的来源在我的硬盘,我找不到一个使用“主要”配置文件。作为最后的手段,测试“低复杂度”不会有什么影响。
尝试使用audioCodecContext->profile = ffmpeg.FF_PROFILE_AAC_LOW;
PS:检查这个可能的审咨委问题 (取决于您的FFmpeg版本)。
https://stackoverflow.com/questions/38198052
复制相似问题