You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用v4l2框架+FFmpeg录制MP4视频:时长不足与播放卡顿问题

问题排查与解决方案

1. 时间戳(PTS/DTS)错误

这是时长不准、播放卡顿的核心诱因。如果采集帧时未正确传递硬件时间戳给FFmpeg,编码器或容器会使用默认的单调递增时间,或因时间戳不匹配导致帧被丢弃、时长计算偏差。

  • 修复方式:从v4l2的struct v4l2_buffer中提取硬件时间戳,转换为FFmpeg流的时间基准:
struct v4l2_buffer buf;
// 执行VIDIOC_DQBUF获取帧数据后...
AVPacket pkt;
av_init_packet(&pkt);
// 将v4l2的微秒时间戳转换为流的时间基准
pkt.pts = av_rescale_q(buf.timestamp.tv_sec * AV_TIME_BASE + buf.timestamp.tv_usec,
                       AV_TIME_BASE_Q, stream->time_base);
pkt.dts = pkt.pts; // 无B帧时DTS与PTS一致
pkt.stream_index = stream->index;

2. 帧率不匹配与USB带宽限制

  • 先确认设备实际支持的帧率:用v4l2-ctl --list-formats-ext查看目标分辨率下的稳定帧率范围。1080p分辨率对USB带宽要求极高,USB2.0通常无法支撑30fps的未压缩视频(如YUYV),强行设置会导致大量丢帧,直接缩短实际录制时长。
  • 对齐采集与编码帧率:确保v4l2设置的struct v4l2_streamparm中的帧率,与FFmpeg编码器上下文的framerate参数完全一致,避免编码器自动丢帧或重复帧。

3. v4l2缓冲区配置不足

缓冲区数量过少会导致采集时丢帧,尤其高分辨率下数据量更大:

  • 调整缓冲区数量:调用VIDIOC_REQBUFS时,将count设置为4-8个(根据设备支持情况调整),确保有足够的缓冲区缓存帧数据,避免因缓冲区填满导致设备停止输出:
struct v4l2_requestbuffers req = {0};
req.count = 6; // 增加缓冲区数量
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ioctl(fd, VIDIOC_REQBUFS, &req);

4. FFmpeg封装收尾不完整

录制结束时未正确触发编码器输出缓存帧、未写入文件尾,会导致MP4文件末尾截断,时长不足:

  • 正确的收尾流程:
// 向编码器发送结束信号
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
avcodec_send_packet(codec_ctx, &pkt);

// 读取编码器缓存的所有剩余帧
while (avcodec_receive_packet(codec_ctx, &pkt) == 0) {
    av_interleaved_write_frame(fmt_ctx, &pkt);
    av_packet_unref(&pkt);
}

// 写入MP4文件尾
av_write_trailer(fmt_ctx);

5. 帧处理阻塞导致丢帧

如果采集、格式转换、编码在同一线程执行,高分辨率下处理耗时超过帧间隔,会导致v4l2缓冲区无法及时释放,新帧无法写入:

  • 优化方案:
    • 采用多线程架构:采集线程负责从v4l2取帧,编码线程负责处理和写入文件,用队列传递帧数据。
    • 减少格式转换开销:让v4l2直接输出编码器支持的格式(如YUV420P),避免额外的sws_scale转换。

内容的提问来源于stack exchange,提问作者Reena

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 16:37:00