[英]FFmpeg C audio video streams (mic, webcam) sync to mp4
我正在尝试使用麦克风和网络摄像头将音频和视频捕获到 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;
对于视频 pts,一旦帧被编码,我将索引增加 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++;
对于音频 pts,一旦对帧进行编码,我将按帧->nb_samples 递增,然后使用重新缩放,然后通过 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 的新手,在互联网上尝试了各种资源/帖子,但仍然无法以稳健的方式同步音频和视频。 这里有几个我想了解的问题,它们将帮助我解决这个问题。 任何想法都非常感谢。
FFmpeg C API 可以在内部处理同步还是需要从调用方处理?
我是否首先为音频和视频正确设置了 PTS? 我注意到当我使用低于 20 的 fps 时,我得到 Invalid pts (66667) <= last (66667) Operation not allowed from the encoder。 这一定是我目前设置视频 PTS 的方式有问题。 如何设置视频 PTS 以处理较低的 fps?
我也在尝试采用dranger 教程中时钟同步的想法,不确定这是否适合我的用例,比如在何处设置音频和视频时钟,因为他只使用解码器,对于音频我使用 fifo并且不确定如何根据时钟同步调整样本,以及调用和设置刷新计时器的方式?
是否有更好的机制为我的用例创建强大的同步,如果音频和视频不同步,它可以处理音频和视频,了解基于此的样本和帧调整会很棒吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.