FFMPEG API - 录制视频和音频 - 同步问题

时间:2015-07-24 18:42:00

标签: c++ qt audio video ffmpeg

我开发的应用程序能够录制来自网络摄像头的视频和来自麦克风的音频。我一直在使用QT,但遗憾的是相机模块无法在Windows上工作,导致我使用ffmpeg来录制视频/音频。

我的相机模块现在运行良好,除了同步的轻微问题。音频和视频有时会因为一小段差异而不同步(不到1秒我会说,虽然录制时间越长可能会更糟)。

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

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

我以25 fps保存文件并要求相机给我25 fps(可以)。我也将视频帧转换为YUV420P格式。对于音频帧转换,我需要使用AVAudioFifo因为微生物发送的样本比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);
}

1 个答案:

答案 0 :(得分:0)

听起来你需要为帧(音频和视频)提供真正的时间戳。创建一个函数,以毫秒为单位返回自开始捕获以来经过的时间(整数)。然后将每个流的time_base设置为{1,1000},并将每个帧的pts设置为函数的返回值。但要小心:您不能拥有< =之前时间戳的时间戳。因此,如果您同时获得多个帧,则需要删除帧(或者编写另一种机制来处理这种情况)。

取自我较长的答案here

使用QElapsedTimer here

的示例