音视频之视频录制(十)
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 << "正常结束----------";