首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Linux 下使用 V4L2 實現視頻採集、編碼與定時寫入 SD 卡

     編輯:程式設計綜合問答

項目背景與需求

在嵌入式 Linux 開發中,常見需求是通過 Video for Linux 2 (V4L2) 接口採集攝像頭視頻流,經過 H.264 編碼後,按固定時間間隔(如每 10 秒)切割成獨立文件寫入 SD 卡。本文梳理完整實現流程,重點解決「定時切片」與「數據流緩衝」兩大核心難點。

整體架構設計

採用「生產者-消費者」模型:

  • 採集線程:調用 V4L2 API 循環讀取幀數據,送入編碼器(如 FFmpeg 或硬件編碼庫),將編碼後的 H.264 NAL 單元推入線程安全隊列。
  • 寫入線程:由定時器觸發,每 10 秒從隊列取出數據,創建新文件寫入 SD 卡掛載點(如 /mnt/sdcard/video_YYYYMMDD_HHMMSS.h264)。

關鍵步驟詳解

1. V4L2 採集初始化

int fd = open("/dev/video0", O_RDWR);
struct v4l2_format fmt = {0};
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 1920;
fmt.fmt.pix.height = 1080;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
ioctl(fd, VIDIOC_S_FMT, &fmt);
// 申請緩衲區、映射內存、入隊、啟動串流...

2. 編碼器集成(以 FFmpeg 為例)

AVCodecContext *ctx = avcodec_alloc_context3(codec);
ctx->width = 1920; ctx->height = 1080;
ctx->pix_fmt = AV_PIX_FMT_YUV420P;
ctx->time_base = (AVRational){1, 30};
ctx->bit_rate = 4000000;
avcodec_open2(ctx, codec, NULL);
// 循環:avcodec_send_frame -> avcodec_receive_packet -> 推入隊列

3. 定時切片邏輯

使用 timerfd_create(CLOCK_MONOTONIC, 0) 創建高精度定時器,設置 10 秒週期。定時器回調中:

  1. 加鎖保護隊列
  2. 關閉當前文件句柄 fclose(fp)
  3. 生成新文件名(含時間戳)
  4. 打開新文件 fp = fopen(new_path, "wb")
  5. 後續寫入線程直接 fwrite 到新 fp

4. SD 卡寫入優化

SD 卡屬於塊設備,頻繁 fwrite 會觸發大量擦寫。建議:

  • 應用層緩衝:累積 512 KB 再調用 fwrite
  • 掛載參數加 noatime,nodiratime 減少元數據寫入
  • 定期 fsync 確保數據落盤,平衡性能與可靠性

常見坑點與對策

  • 啟用 writeback 模式 + 獨立寫入線程
  • 問題原因解決方案
    文件時長不足 10 秒關鍵幀間隔過大編碼器設置 g=300 (30fps×10s) 強制關鍵幀
    首幀花屏SPS/PPS 未寫入文件頭切片時先寫入 extradata 再寫數據
    SD 卡寫入卡頓文件系統同步阻塞

    完整代碼參考

    可參考 CSDN 開源項目:V4L2_H264_SD_Recorder,包含 Makefile、信號處理、優雅退出等工程化細節。

    總結

    核心在於「隊列解耦採集與寫入」+「定時器驅動切片」。只要處理好關鍵幀對齊、緩衝區回收、SD 卡壽命管理,即可構建穩定可靠的嵌入式視頻錄製系統。

    1. 上一篇文章:
    2. 下一篇文章:
    Copyright © 程式碼之家 All Rights Reserved