【问题标题】:FFMPEG API - Recording video and audio - Syncing problemsFFMPEG API - 录制视频和音频 - 同步问题
【发布时间】:2015-07-24 18:41:59
【问题描述】:

我正在开发一个应用程序,它能够录制来自网络摄像头的视频和来自麦克风的音频。我一直在使用 QT,但不幸的是相机模块在 Windows 上不起作用,这导致我使用 ffmpeg 来录制视频/音频。

我的相机模块现在运行良好,除了同步出现小问题。音频和视频有时会因微小的差异而不同步(我会说不到 1 秒,尽管较长的录音可能会更糟)。

当我对帧进行编码时,我按以下方式添加 PTS(我取自 muxing.c 示例):

  • 对于视频帧,我将 PTS 逐一递增(从 0 开始)。
  • 对于音频帧,我将 PTS 增加音频帧的 nb_samples(从 0 开始)。

我正在以 25 fps 的速度保存文件,并要求相机给我 25 fps(它可以)。我还将视频帧转换为YUV420P 格式。对于音频帧转换,我需要使用AVAudioFifo,因为 microfone 发送的样本比 mp4 流支持的更大,所以我必须将它们分成块。我为此使用了transcode.c 示例。

我不知道应该如何同步音频和视频。我需要使用时钟或其他东西来正确同步两个流吗?

完整代码太大,无法在此处发布,但如果有必要,我可以将其添加到 github,例如。

下面是写框架的代码:

int FFCapture::writeFrame(const AVRational *time_base, AVStream *stream, AVPacket *pkt) {
    /* rescale output packet timestamp values from codec to stream timebase */
    av_packet_rescale_ts(pkt, *time_base, stream->time_base);
    pkt->stream_index = stream->index;
    /* Write the compressed frame to the media file. */
    return av_interleaved_write_frame(oFormatContext, pkt);
}

获取经过时间的代码:

qint64 FFCapture::getElapsedTime(qint64 *previousTime) {
    qint64 newTime = timer.elapsed();
    if(newTime > *previousTime) {
        *previousTime = newTime;
        return newTime;
    }
    return -1;
}

添加PTS的代码(分别是视频和音频流):

qint64 time = getElapsedTime(&previousVideoTime);
if(time >= 0) outFrame->pts = time;
//if(time >= 0) outFrame->pts = av_rescale_q(time, outStream.videoStream->codec->time_base, outStream.videoStream->time_base);

qint64 time = getElapsedTime(&previousAudioTime);
if(time >= 0) {
    AVRational aux;
    aux.num = 1;
    aux.den = 1000;
    outFrame->pts = time;
    //outFrame->pts = av_rescale_q(time, aux, outStream.audioStream->time_base);
}

【问题讨论】:

    标签: c++ qt audio video ffmpeg


    【解决方案1】:

    听起来您需要为帧(音频和视频)提供真正的时间戳。创建一个函数,该函数返回自开始捕获以来经过的时间(以毫秒为单位)(整数)。然后将每个流的time_base 设置为{1,1000},并将每帧的pts 设置为函数的返回值。但要小心:你不能有一个

    取自我更长的答案here

    使用QElapsedTimerhere 的示例。

    【讨论】:

    • 我应该为两个流设置一个 QElapsedTimer 吗?还是每人一个?而且我需要每个流的“先前时间戳”,对吗?另外,将每个流设为 {1,1000} 这意味着多少 fps?我怎样才能转换呢? (如果相机允许,用户应该可以选择)。
    • 这似乎适用于视频,但不适用于音频。由于音频流始终保持 {1 sample_rate} 的 time_base,即使我将其更改为 {1, 1000}。第一个 pts 最终为负数,音频无法播放或完全关闭。
    • 是的,ffmpeg 有时会将 time_base 更改为其他一些合理的值。在这种情况下,您必须在设置之前将时间戳转换(“重新缩放”)为流的 time_base。使用av_rescale_q(your_pts, your_time_base, stream_time_base)。您应该只使用一个 QElapsedTimer,因为它是您的流的主计时器。它会根据您的程序收到音频和视频帧的时间来保持您的流同步。
    • 我在保存 pkt 之前使用了av_packet_rescale_ts。我已经在我的问题上添加了代码。这种方法和使用av_rescale_q(参见注释代码)都会产生质量差的音频(音频跳过并且不断被剪切)。此外,似乎出于某种原因av_rescale_q 会降低性能。我不确定这一点,但帧速度变慢了很多(我也在屏幕上显示视频)。
    • 我一直在想。我的麦克风为每帧提供 22050 个样本,输出流使用 1024,因此我使用 audiofifo 存储样本并将它们切割成 1024 个块。我不应该只获取每个 22050 的经过时间,然后在切割样本时计算我应该在经过时间上增加多少毫秒?
    猜你喜欢
    • 1970-01-01
    • 2017-04-13
    • 2019-05-19
    • 2016-05-26
    • 2012-03-16
    • 2017-01-28
    • 2012-10-02
    • 2020-10-04
    • 2023-03-05
    相关资源
    最近更新 更多