1. 程式人生 > 其它 >音視訊之視訊錄製(十)

音視訊之視訊錄製(十)

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 (default
false) -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 << "正常結束----------";