FFmpeg C音频视频流(麦克风,网络摄像头)同步到mp4

时间:2020-02-21 20:36:30

标签: c audio video ffmpeg synchronization

我正在尝试使用麦克风和网络摄像头将音频和视频捕获到mp4文件中。录制的文件是可播放的,但是随着时间的流逝,音频开始逐渐偏离视频,并且在更长的时间内,差距会增大。音频和视频都在单独的线程中处理,对于音频,我正在使用从transcode_acc.c示例https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/transcode_aac.c
改编而成的audiofifo 这是我设置流的方法
视频:

video_output_codec_ctx = video_stream->codec;
video_output_codec_ctx->bit_rate = 2000000;
video_output_codec_ctx->codec_id = AV_CODEC_ID_MPEG4;
video_output_codec_ctx->width = 640;
video_output_codec_ctx->height = 480;
video_stream->time_base = (AVRational){1, fps};
video_output_codec_ctx->time_base = video_stream->time_base;
video_output_codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
video_output_codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;

音频:

audio_output_codec_ctx->channels       = OUTPUT_CHANNELS; // 2
audio_output_codec_ctx->channel_layout = av_get_default_channel_layout(OUTPUT_CHANNELS);
audio_output_codec_ctx->sample_rate    = audio_input_codec_ctx->sample_rate;
audio_output_codec_ctx->sample_fmt     = audio_output_codec->sample_fmts[0];
audio_output_codec_ctx->bit_rate       = OUTPUT_BIT_RATE; // 96000
audio_output_codec_ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;

/* Set the sample rate for the container. */
audio_stream->time_base.den = audio_input_codec_ctx->sample_rate;
audio_stream->time_base.num = 1;

对于视频点,一旦帧被编码,我将索引增加1,在将帧发送到编码器之前,我使用rescale,并且在接收到帧之后,再通过av_interleaved_write_frame()写入数据包。

output_frame->pts = av_rescale_q(video_frame_index, video_output_codec_ctx->time_base, video_input_format_ctx->streams[0]->time_base);

error = avcodec_send_frame(video_output_codec_ctx, output_frame);

error = avcodec_receive_packet(video_output_codec_ctx, &output_packet);

output_packet.stream_index = video_index;

output_packet.pts = av_rescale_q_rnd(output_packet.pts, video_input_format_ctx->streams[0]->time_base, output_format_context->streams[video_index]->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));

output_packet.dts = av_rescale_q_rnd(output_packet.dts, video_input_format_ctx->streams[0]->time_base, output_format_context->streams[video_index]->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));

output_packet.duration = ((output_format_context->streams[0]->time_base.den / output_format_context->streams[0]->time_base.num) / video_output_codec_ctx->time_base.den);

output_packet.pos = -1;  

video_frame_index++;

对于音频pt,一旦对帧进行编码,我将使用frame-> nb_samples进行增量,然后使用rescale,然后通过av_interleaved_write_frame()写入数据包。

frame->pts = aud_pts;
aud_pts += frame->nb_samples;

error = avcodec_send_frame(audio_output_codec_ctx, frame);

error = avcodec_receive_packet(audio_output_codec_ctx, &output_packet);

output_packet.stream_index = audio_index;

output_packet.pts = av_rescale_q_rnd(output_packet.pts, audio_output_codec_ctx->time_base, output_format_context->streams[audio_index]->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));

output_packet.dts = av_rescale_q_rnd(output_packet.dts, audio_output_codec_ctx->time_base, output_format_context->streams[audio_index]->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));

output_packet.duration = av_rescale_q(output_packet.duration, audio_output_codec_ctx->time_base, output_format_context->streams[audio_index]->time_base);

我是FFmpeg C API的新手,曾经尝试过Internet上的各种资源/帖子,但仍然无法以可靠的方式同步音频和视频。这里是我想了解的几个问题,可以帮助我解决这个问题。任何想法对此表示赞赏。

  1. FFmpeg C API是否可以在内部处理同步,或者这需要在调用方进行处理?

  2. 我是否首先为音频和视频正确设置了PTS?我注意到,当我使用低于20的fps时,会收到无效的pts(66667)<= last(66667)编码器不允许的操作。我当前设置视频PTS的方式一定有问题。如何设置视频PTS以处理较低的fps?

  3. 我还尝试采用dranger's tutorial进行时钟同步的想法,不确定是否适合我的用例,比如在哪里设置音频和视频时钟,因为他只是使用解码器,对于音频,我使用的是fifo,不确定如何根据时钟同步来调整样本,以及调用和设置刷新计时器的方式?

  4. 是否存在一种更好的机制来为我的用例创建健壮的同步,如果音频和视频不同步,它可以处理音频和视频,因此对基于该采样和帧的调整有所了解会很棒?

0 个答案:

没有答案