音視訊之視訊錄製(十)
阿新 • • 發佈:2021-11-11
MAC端錄製視訊
命令列錄製
avfoundation支援的裝置
ffmpeg -f avfoundation -list_devices true -i ' '
輸出結果大致如下所示:
[AVFoundation indev @ 0x7fd2d1804400] AVFoundation video devices: [AVFoundation indev @ 0x7fd2d1804400] [0] FaceTime HD Camera [AVFoundation indev @ 0x7fd2d1804400] [1] Capture screen 0 [AVFoundation indev @ 0x7fd2d1804400] AVFoundation audio devices: [AVFoundation indev @ 0x7fd2d1804400] [0] Built-in Microphone [AVFoundation indev @ 0x7fd2d1804400] [1] 江波的AirPods
0號裝置就是Mac自帶的攝像頭
avfoundation支援的引數
ffmpeg -h demuxer=avfoundation
輸出結果大致如下所示:
AVFoundation indev AVOptions: -list_devices <boolean> .D......... list available devices (defaultfalse) -video_device_index <int> .D......... select video device by index for devices with same name (starts at 0) (from -1 to INT_MAX) (default -1) -audio_device_index <int> .D......... select audio device by index for devices with same name (starts at 0) (from -1 to INT_MAX) (default-1) -pixel_format <pix_fmt> .D......... set pixel format (default yuv420p) -framerate <video_rate> .D......... set frame rate (default "ntsc") -video_size <image_size> .D......... set video size -capture_cursor <boolean> .D......... capture the screen cursor (default false) -capture_mouse_clicks <boolean> .D......... capture the screen mouse clicks (default false) -capture_raw_data <boolean> .D......... capture the raw data from device connection (default false) -drop_late_frames <boolean> .D......... drop frames that are available later than expected (default true)
- -video_size: 解析度
- -pixel_format: 畫素格式
- 預設是yuv420p
- -framerate: 幀率(每秒菜雞多少幀畫面)
- 預設是ntsc,也就是30000/1001,約等於29.970030
- -list_device: true表示列出avfoundation支援的所有裝置
錄製
使用0號視訊裝置錄製
ffmpeg -f avfoundation -i 0 out.yuv
然後你可能會遇到一個錯誤: 這個裝置(攝像頭)不支援29.970030的幀率
Selected framerate (29.970030) is not supported by the device
重新設定30的幀率試試
ffmpeg -f avfoundation -framerate 30 -i 0 out.yuv
- 這個裝置(攝像頭)不支援yuv420p
- 只支援uyvy422、yuyv422、nv12、0rgb、bgr0
- 並且自動選擇使用uyvy422替代yuv420p
Selected pixel format (yuv420p) is not supported by the input device. Supported pixel formats: uyvy422 yuyv422 nv12 0rgb bgr0 Overriding selected pixel format to use uyvy422 instead.
與此同時,也成功開始採集攝像頭的視訊資料了。
- 畫素格式: uyvy422
- 解析度: 1280x720
- 幀率: 30
Input #0, avfoundation, from '0': Stream #0:0: Video: rawvideo, uyvy422, 1280x720 Output #0, rawvideo, to 'out.yuv': Stream #0:0: Video: rawvideo, uyvy422, 1280x720, 30 fps
播放錄製好的YUV
ffplay -video_size 1280x720 -pixel_format uyvy422 -framerate 30 out.yuv
程式設計錄製視訊
依賴庫
需要依賴5個庫
extern "C" { // 裝置相關API #include <libavdevice/avdevice.h> // 格式相關API #include <libavformat/avformat.h> // 工具(比如錯誤處理) #include <libavutil/avutil.h> // 編碼相關的API #include <libavcodec/avcodec.h> #include <libavutil/imgutils.h> }
巨集定義
#ifdef Q_OS_WIN // 格式名稱 #define FMT_NAME "dshow" // 裝置名稱 #define DEVICE_NAME "" // PCM檔名 #define FILEPATH "F:/" #else #define FMT_NAME "avfoundation" #define DEVICE_NAME ":0" #define FILEPATH "/Users/muzi/Desktop/out.yuv" #endif
許可權申請
在Mac平臺,有2個注意點:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>NSCameraUsageDescription</key> <string>申請使用您的攝像頭許可權</string> <key>NSMicrophoneUsageDescription</key> <string>申請使用您的麥克風許可權</string> </dict> </plist>
- 需要在Info.plist中新增攝像頭、麥克風的使用說明,申請攝像頭、麥克風的使用許可權
- 使用Debug模式執行程式
- 不然會出現閃退的情況
註冊裝置
在整個程式的執行過程中,只需要執行1次註冊裝置的程式碼。
// 註冊裝置 avdevice_register_all();
獲取輸入格式物件
// 獲取輸入格式物件 AVInputFormat *fmt = av_find_input_format(FMT_NAME); if (!fmt) { qDebug() << "獲取輸入格式物件失敗" << FMT_NAME; return; }
開啟輸入裝置
// 格式上下文(將來可以利用上下文操作裝置) AVFormatContext *ctx = nullptr; // 裝置引數 AVDictionary *options = nullptr; av_dict_set(&options, "video_size", "640x480", 0); av_dict_set(&options, "pixel_format", "yuyv422", 0); av_dict_set(&options, "framerate", "30", 0); // 開啟裝置 int ret = avformat_open_input(&ctx, DEVICE_NAME, fmt, &options); if (ret < 0) { char errbuf[1024]; av_strerror(ret, errbuf, sizeof (errbuf)); qDebug() << "開啟裝置失敗" << errbuf; return; }
開啟輸出檔案
// 檔名 QFile file(FILEPATH); // 開啟檔案 // WriteOnly:只寫模式。如果檔案不存在,就建立檔案;如果檔案存在,就會清空檔案內容 if (!file.open(QFile::WriteOnly)) { qDebug() << "檔案開啟失敗" ; // 關閉裝置 avformat_close_input(&ctx); return; }
採集視訊資料
// 計算一幀的大小 AVCodecParameters *params = ctx->streams[0]->codecpar; AVPixelFormat pixFmt = (AVPixelFormat) params->format; int imageSize = av_image_get_buffer_size(pixFmt, params->width, params->height, 1); // 資料包 AVPacket *pkt = av_packet_alloc(); while (!isInterruptionRequested()) { // 不斷採集資料 ret = av_read_frame(ctx, pkt); if (ret == 0) { // 讀取成功 // 將資料寫入檔案 file.write((const char *) pkt->data, imageSize); // 釋放資源 av_packet_unref(pkt); } else if (ret == AVERROR(EAGAIN)) { // 資源臨時不可用 continue; } else { // 其他錯誤 char errbuf[1024]; av_strerror(ret, errbuf, sizeof (errbuf)); qDebug() << "av_read_frame error" << errbuf << ret; break; } // 必須要加,釋放pkt內部的資源 av_packet_unref(pkt); }
釋放資源
// 釋放資源 // 關閉檔案 file.close(); // 釋放資源 av_packet_free(&pkt); // 關閉裝置 avformat_close_input(&ctx); qDebug() << this << "正常結束----------";