1.调用ffmpeg命令采集摄像头图像
$ ffmpeg -f v4l2 -framerate 30 -video_size 1280*720 -i /dev/video0 -c:v libx264 -preset veryfast -f h264 output.h264
-f v4l2: 指定输入设备采用Video4Linux2框架。
-framerate 30: 设置帧率为30。
-video_size 1280720: 设置视频分辨率为1280720
-i /dev/video0: 指定输入设备文件路径。
-c:v libx264: 指定使用H.264编码。
-preset veryfast: 选择快速编码预设。
-f h264: 输出格式为H.264帧。
Output.h264: 输出文件。
2 调用ffmpeg库实现摄像头采集并编码为h264
- ffmpeg 采集摄像头图像,编码为H264格式步骤:
1.注册设备avdevice_register_all();
2.查找摄像头框架格式av_find_input_format(“video4Linux2”);
3.设置摄像头参数options:图像尺寸(video_size)、帧率(framerate)、图像格式(input_format),av_dict_set();
4.打开输入文件,获取输入上下文指针avformat_open_input();
5.获取摄像头图像流信息avformat_find_stream_info;
6.查找摄像头中的视频流av_find_best_stream;
7.根据编码格式,获取解码器avcodec_find_decoder_by_name(“libx264”);
8.分配编码器上下文指针avcodec_alloc_context3();
9.设置图像编码参数:图像尺寸、帧率framebate、time_base、gop_size、pix_fmt,将编码器关联到AVDocodecCotext指针;
10.创建输出文件fopen
11.创建视频帧av_frame_alloc();
12.设置frame参数:宽度、高度、图像格式;
13.为frame中data和buf分配空间:av_frame_get_buffer();
14.分配packet包,用于存放h264编码后的数据;
15.从摄像头中读取采集的数据av_read_frame();
17.判断是否为视频流,将packet中的yuv422数据转换为yuv420p格式,并保存到frame中;
18.将frame中的流数据进行h264格式编码encodec_video();
- 编码流程图如下:
示例代码:
#include <stdio.h>
#include <libavutil/avutil.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavutil/imgutils.h>
#include <unistd.h>
#include <signal.h>
#define VIDEO_DEV "/dev/video0"
static int video_width;
static int video_height;
int camera_flag=0;
void YUYV422_toYuv420p(AVFrame *frame,AVPacket *pkt){
/*
yuv422 存储格式为 y u y v y u y v
y u y v y u y v
yuv422 每两个y公用一组UV分量,yuyv(yuv422)一个像素大小:y+1/2(u)+1/2(v)=2byte
yuv420p 存储最简单,先存所以的y,再存u,最后v,yuv420p 每4个Y共用一组UV分量
所以先把422所有的y存在一起,再提奇数行的u ,偶数行舍弃。提完u后,再提v,v也是偶数行不提取。
*/
int i = 0;
int yuv422_length=video_width*video_height*2;//yuv422图像大小
int y_index = 0;
// 取出Y分量数据
for (i = 0; i < yuv422_length; i += 2) {
frame->data[0][y_index] = pkt->data[i];
y_index++;
}
// copy u and v
int line_start = 0;
int is_u = 1;
int u_index = 0;
int v_index = 0;
// copy u, v per line. skip a line once
for (i = 0; i < video_height; i += 2)
{
line_start = i * (video_width<<1);//每一行的起始位置,相当于:video_width*2
for (int j = line_start + 1