FFmpeg采集本机摄像头一帧YUV数据
使用FFmpeg库从摄像头采集视频数据并保存为YUV格式的实现方法。代码首先通过avformat_open_input()初始化摄像头设备,设置分辨率(1280x720)和像素格式(YUYV422)。然后使用avformat_find_stream_info()获取视频流信息,包括帧率和编码参数。通过av_read_frame()读取单帧视频数据后,将YUV数据写入文件。最后释放资源并关闭设备。该
读取代码在下面,下面是代码讲解

ret = avformat_find_stream_info(g_capture_ctx, NULL);
-
用于解析输入流(这里是摄像头)的详细信息
-
函数会填充
g_capture_ctx->streams数组,每个元素代表一个媒体流(视频、音频等) -
对于摄像头这类实时设备,它会协商获取实际支持的参数(分辨率、帧率等)
videoStreamId = av_find_best_stream(g_capture_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, NULL);
-
用于从多个流中找到最合适的指定类型的流
-
对于摄像头,通常只有一个视频流,但该函数可以兼容有多个流的情况(如带麦克风的摄像头)
-
用这个函数可以跨设备兼容
// 计算帧率(将AVRational格式转换为double)
double fps = av_q2d(video_stream->avg_frame_rate);
AVPacket的初始化和使用:
// 分配AVPacket用于存储采集到的视频数据,api函数
AVPacket* captured_packet = av_packet_alloc();// 等同于new AVPacket并初始化
// 读取一帧视频数据,api函数
auto ret = av_read_frame(g_capture_ctx, captured_packet);
// 将采集到的YUV帧写入文件,自定义函数
write_yuv_frame_to_file(captured_packet);
// 释放AVPacket的资源(但不释放指针本身)
av_packet_unref(captured_packet);
#include "include_ffmpeg.h"
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
// 全局变量:视频采集上下文,用于管理整个视频采集过程
AVFormatContext* g_capture_ctx = nullptr;
// 全局变量:视频流对象,存储视频流的相关信息
AVStream* video_stream = nullptr;
/**
* 创建DirectShow视频采集上下文,初始化摄像头采集
* @param video_device_name 视频设备名称(如摄像头名称)
*/
void create_capture_dshow_context(const string& video_device_name)
{
// 分配AVFormatContext上下文,用于管理媒体文件或流
g_capture_ctx = avformat_alloc_context();
// 查找DirectShow输入格式(Windows平台的视频采集接口)
const AVInputFormat* inputFormat = av_find_input_format("dshow");
cout << "capture : " << inputFormat->long_name << endl;
// 创建并设置采集参数选项
AVDictionary* options = nullptr;
// 设置视频分辨率为1280x720
av_dict_set(&options, "video_size", "1280x720", 0);
// 设置像素格式为YUYV422(一种常见的YUV格式)
av_dict_set(&options, "pixel_format", "yuyv422", 0);
// 打开输入设备(摄像头)
// 注意:dshow设备名需要以"video="为前缀
int ret = avformat_open_input(&g_capture_ctx
, string("video=" + video_device_name).c_str()
, inputFormat, &options);
check_error("avformat_open_input", ret); // 检查函数调用是否成功
// 查找流信息,获取视频流的详细参数
ret = avformat_find_stream_info(g_capture_ctx, NULL);
check_error("avformat_find_stream_info", ret); // 检查函数调用是否成功
// 查找最佳视频流(从所有流中找出视频类型的流)
int videoStreamId = -1;
videoStreamId = av_find_best_stream(g_capture_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, NULL);
// 获取找到的视频流
video_stream = g_capture_ctx->streams[videoStreamId];
// 获取视频流的编解码器参数
AVCodecParameters* codec_par = video_stream->codecpar;
// 获取像素格式
AVPixelFormat pixel_format = (AVPixelFormat)codec_par->format;
// 计算帧率(将AVRational格式转换为double)
double fps = av_q2d(video_stream->avg_frame_rate);
// 输出采集到的视频信息
cout << "capture format:" << endl
<< " capture fps = " << fps << endl // 帧率
<<" capture codec_id = " << avcodec_get_name( codec_par->codec_id) << endl // 编解码器ID
<< " w=" << video_stream->codecpar->width // 宽度
<< ", h=" << video_stream->codecpar->height << endl // 高度
<< " capture format="<< av_get_pix_fmt_name(pixel_format) // 像素格式
<< endl;
}
/**
* 将YUV帧数据写入文件
* @param captured_packet 包含YUV数据的数据包
*/
void write_yuv_frame_to_file(AVPacket* captured_packet)
{
cout << "write_yuv_frame_to_file" << endl;
// 输出数据包大小
cout << "packet size=" << captured_packet->size << endl;
// 打开文件流,准备写入YUV数据
ofstream fout("captured_yuyv422.yuv");
// 将数据包中的数据写入文件
// reinterpret_cast用于将void*转换为const char*,适配ofstream的write方法
fout.write(reinterpret_cast<const char*>(captured_packet->data), captured_packet->size);
// 对于1280x720分辨率的YUYV422格式,每帧大小计算:
// YUV422格式每个像素占用2字节(YUV420是1.5字节)
// 1280*720*2 = 1,843,200字节
}
int main(void)
{
// 注册所有的FFmpeg设备(必须在使用设备前调用)
avdevice_register_all();
// 显示系统中所有可用的视频和音频设备
// 运行此代码后,应从输出列表中选择一个视频设备名称用于后续采集
show_dshow_device();
// 视频设备名称(需从show_dshow_device()的输出中复制)
string video_device_name = "Integrated Camera";// 例如:"集成摄像头"或"Integrated Camera"
// 创建视频采集上下文,初始化摄像头
create_capture_dshow_context(video_device_name);
// 分配AVPacket用于存储采集到的视频数据
AVPacket* captured_packet = av_packet_alloc();// 等同于new AVPacket并初始化
// 读取一帧视频数据
auto ret = av_read_frame(g_capture_ctx, captured_packet);
// 将采集到的YUV帧写入文件
write_yuv_frame_to_file(captured_packet);
// 释放AVPacket的资源(但不释放指针本身)
av_packet_unref(captured_packet);
// 关闭输入设备,释放采集上下文
avformat_close_input(&g_capture_ctx);
return 0;
}
开源链接
https://gitee.com/cxx888/ffmpeg-capture-camera-1-yuv-frame-answer
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)