FFMPEG学习日记–采集视频
本文描述了在centos8上进行视频采集的方式,采用FFMEPGE,在采集前需要正确安装和配置FFMPEG,可参考:
https://blog.csdn.net/qq_27031005/article/details/111815318
- 使用命令方式采集linux界面:(需要采用x11方式开启centos)
ffmpeg -video_size 1024x768 -framerate 25 -f x11grab -i :0.0+100,200 v-out.mp4
上面的参数,指的是从屏幕的左上角(x=100, y=200)的位置,录制分辨率为1024×768的视频,在使用时可能会报错分辨率超限,此时修改x和y即可
- 可以使用ALSA同时录制声音
ffmpeg -video_size 1024x768 -framerate 25 -f x11grab -i :0.0+100,200 -f alsa -ac 2 -i hw:0 av-out.mkv
- 采用命令录制摄像头:
ffmpeg -f video4linux -s 320*240 -r 10 -i /dev/video0 test.asf
这个时候录制的是yuv数据,我是采用虚拟机的,驱动/dev/video0需要进行如下操作:
- VMvare虚拟机-》设置,usb里将3.0开起来,有些可能是2.0,就不用更改了,我的电脑是3.0,如果这个不对的话会采集不到数据
- VMware设置里设备添加可移动设备里连接上摄像头
- cheese测试是否可以正常看到摄像头内容,如果cheese能够出现视频的话ffmpeg一般也能出现,否则可以去/dev/video0看一下是否有这个设备节点,代表摄像头。
API采集源码:
与音频采集类似,需要经历以下几个步骤:
- 先获取采集器video4linux2和设备/dev/video0,av_find_input_format();
- 打开设备采集avformat_open_input()
- 获取输入视频流信息,宽和高
- av_read_frame读取一帧数据,数据大小一帧里和宽高以及yuv格式相关
代码如下:
//ffplay -pix_fmt yuyv422 -s 320x240 rec_vedio.yuv
//gcc sample_vedio.c -o test `pkg-config --libs --cflags libavutil libavdevice libavformat libavcodec`
#include <stdio.h>
#include <libavutil/avutil.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
void rec_vedio()
{
int ret=0;
char error[1024]={0};
int count=0;
AVPacket pkt;
//register device
avdevice_register_all();
av_log_set_level(AV_LOG_DEBUG);
char deviceName[]="/dev/video0";
AVFormatContext *fmt_ctx=NULL;
AVInputFormat* p_InputFormat=av_find_input_format("video4linux2");
AVDictionary* avDic=NULL;
char filename[]="rec_vedio.yuv";
FILE *fd=NULL;
int videoindex=-1,i=0;
AVCodecContext *pCodecCtx=NULL;
#if 0
AVCodec *pCodec;
#endif
if(p_InputFormat==NULL)
{
printf("p_InputFormat is null\n");
goto end;
}
ret= avformat_open_input(&fmt_ctx, deviceName, p_InputFormat, &avDic);
if(ret<0)
{
av_strerror(ret,error,1024);
printf("avformat_open_input err deviceName[%s] ,ret[%d] ,str[%s]",deviceName,ret,error);
goto end;
}
if(avformat_find_stream_info(fmt_ctx,NULL)<0)
{
printf("找不到流信息.\n");
goto end;
}
for(i=0; i<fmt_ctx->nb_streams; i++)
if(fmt_ctx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoindex=i;
printf("videoindex=%d\n",videoindex);
break;
}
if(videoindex==-1)
{
printf("找不到视频流。\n");
goto end;
}
pCodecCtx=fmt_ctx->streams[videoindex]->codec;
printf("codec->id[%d]\n",pCodecCtx->codec_id);
#if 0
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
printf("找不到编解码器。\n");
goto end;
}
if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)
{
printf("无法打开编解码器。\n");
goto end;
}
#endif
printf("pCodecCtx->width[%d]pCodecCtx->height[%d]\n",pCodecCtx->width,pCodecCtx->height);
av_init_packet(&pkt);
fd=fopen(filename,"wb+");
while((0==av_read_frame (fmt_ctx, &pkt))&&count<1000)
{
count++;
printf("av_packct size[%d] count[%d]\n",pkt.size);
fwrite(pkt.data,1,pkt.size,fd);
av_packet_unref(&pkt);
}
/* flush the encoder */
av_log(NULL,AV_LOG_DEBUG,"rec_vedio success!\n");
end:
if(fd!=NULL)
{
fclose(fd);
}
if(fmt_ctx!=NULL)
{
avformat_close_input(&fmt_ctx);
}
return ;
}
int main(int argc,char* argv[])
{
rec_vedio();
return 0;
}
编译命令:
gcc sample_vedio.c -o test `pkg-config --libs --cflags libavutil libavdevice libavformat libavcodec`
采集完之后可以用ffplay播放,这个时候需要给播放器明确yuv格式和对应采集的分辨率(这些在调用采集时会打印出来,我这里时yuyv422,320x240的分辨率),命令如下:
ffplay -pix_fmt yuyv422 -s 320x240 rec_vedio.yuv
这样视频的基本数据采集就完成了,后面就可以对数据进行编码了。