FFmpeg4入门14:Linux下摄像头捕获并编码为h264
Posted 幽迷狂
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FFmpeg4入门14:Linux下摄像头捕获并编码为h264相关的知识,希望对你有一定的参考价值。
上一篇是将H264流封装到MP4容器中,本篇介绍一个最常用的捕获原始数据的方法:从摄像头获取数据。
因为本人已经放弃windows操作系统,所以使用linux来获取摄像头并编码为H264文件保存。
linux下使用video4linux2作为设备来定义统一的接口,先看一下摄像头数据信息:
$ ffprobe /dev/video0
...
Input #0, video4linux2,v4l2, from '/dev/video0':
Duration: N/A, start: 4232.341681, bitrate: 110592 kb/s
Stream #0:0: Video: rawvideo (YUY2 / 0x32595559), yuyv422, 640x360, 110592 kb/s, 30 fps, 30 tbr, 1000k tbn, 1000k tbc
摄像头原始数据为YVYU422格式,而我们一般使用的是YUV420P。所以我们编码之前需要将其解码为YUV420P(当然也可以不解码,因为视频播放的时候也会解码,这里只是为了入门教学)。
那么步骤就是读取摄像头YUYV422数据->解码为YUV420P->编码为H264流->保存文件。
先看一下流程:
先将打开和保存的步骤写好,然后读取每一帧,读到一帧后解码,然后送入编码器,保存文件。
先看一下
打开摄像头部分
首先打开摄像头
avdevice_register_all();
AVInputFormat *inFmt = av_find_input_format("v4l2");
if(avformat_open_input(&inFmtCtx,"/dev/video0",inFmt,NULL)<0)
printf("Cannot open camera.\\n");
return -1;
先注册所有的设备,然后打开v4l2(video4linux2)用于读取摄像头数据,接下来的步骤和之前的一样
解码部分代码如下:
avdevice_register_all();
/解码器部分//
AVFormatContext *inFmtCtx = avformat_alloc_context();
AVCodecContext *inCodecCtx = NULL;
AVCodec *inCodec =NULL;
AVPacket *inPkt =av_packet_alloc();
AVFrame *srcFrame =av_frame_alloc();
AVFrame *yuvFrame =av_frame_alloc();
struct SwsContext *img_ctx = NULL;
int inVideoStreamIndex = -1;
//打开摄像头
AVInputFormat *inFmt = av_find_input_format("v4l2");
if(avformat_open_input(&inFmtCtx,"/dev/video0",inFmt,NULL)<0)
printf("Cannot open camera.\\n");
return -1;
if(avformat_find_stream_info(inFmtCtx,NULL)<0)
printf("Cannot find any stream in file.\\n");
return -1;
for(size_t i=0;i<inFmtCtx->nb_streams;i++)
if(inFmtCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO)
inVideoStreamIndex=i;
break;
if(inVideoStreamIndex==-1)
printf("Cannot find video stream in file.\\n");
return -1;
AVCodecParameters *inVideoCodecPara = inFmtCtx->streams[inVideoStreamIndex]->codecpar;
if(!(inCodec=avcodec_find_decoder(inVideoCodecPara->codec_id)))
printf("Cannot find valid video decoder.\\n");
return -1;
if(!(inCodecCtx = avcodec_alloc_context3(inCodec)))
printf("Cannot alloc valid decode codec context.\\n");
return -1;
if(avcodec_parameters_to_context(inCodecCtx,inVideoCodecPara)<0)
printf("Cannot initialize parameters.\\n");
return -1;
if(avcodec_open2(inCodecCtx,inCodec,NULL)<0)
printf("Cannot open codec.\\n");
return -1;
img_ctx = sws_getContext(inCodecCtx->width,
inCodecCtx->height,
inCodecCtx->pix_fmt,
inCodecCtx->width,
inCodecCtx->height,
AV_PIX_FMT_YUV420P,
SWS_BICUBIC,
NULL,NULL,NULL);
int numBytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P,
inCodecCtx->width,
inCodecCtx->height,1);
uint8_t* out_buffer = (unsigned char*)av_malloc(numBytes*sizeof(unsigned char));
ret = av_image_fill_arrays(yuvFrame->data,
yuvFrame->linesize,
out_buffer,
AV_PIX_FMT_YUV420P,
inCodecCtx->width,
inCodecCtx->height,
1);
if(ret<0)
printf("Fill arrays failed.\\n");
return -1;
//解码器部分结束/
就是普通的打开编码器流程,此部分代码和FFmpeg4入门5:解码视频流过程部分一样。
打开保存文件部分
//编码器部分开始/
const char* outFile = "result.h264";
AVOutputFormat *outFmt = NULL;
AVCodecContext *outCodecCtx=NULL;
AVCodec *outCodec = NULL;
AVStream *outVStream = NULL;
AVPacket *outPkt = av_packet_alloc();
//打开输出文件,并填充fmtCtx数据
AVFormatContext *outFmtCtx = avformat_alloc_context();
if(avformat_alloc_output_context2(&outFmtCtx,NULL,NULL,outFile)<0)
printf("Cannot alloc output file context.\\n");
return -1;
outFmt = outFmtCtx->oformat;
//打开输出文件
if(avio_open(&outFmtCtx->pb,outFile,AVIO_FLAG_READ_WRITE)<0)
printf("output file open failed.\\n");
return -1;
//创建h264视频流,并设置参数
outVStream = avformat_new_stream(outFmtCtx,outCodec);
if(outVStream==nullptr)
printf("create new video stream fialed.\\n");
return -1;
outVStream->time_base.den=30;
outVStream->time_base.num=1;
//编码参数相关
AVCodecParameters *outCodecPara = outFmtCtx->streams[outVStream->index]->codecpar;
outCodecPara->codec_type=AVMEDIA_TYPE_VIDEO;
outCodecPara->codec_id = outFmt->video_codec;
outCodecPara->width = 480;
outCodecPara->height = 360;
outCodecPara->bit_rate = 110000;
//查找编码器
outCodec = avcodec_find_encoder(outFmt->video_codec);
if(outCodec==NULL)
printf("Cannot find any encoder.\\n");
return -1;
//设置编码器内容
outCodecCtx = avcodec_alloc_context3(outCodec);
avcodec_parameters_to_context(outCodecCtx,outCodecPara);
if(outCodecCtx==NULL)
printf("Cannot alloc output codec content.\\n");
return -1;
outCodecCtx->codec_id = outFmt->video_codec;
outCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
outCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
outCodecCtx->width = inCodecCtx->width;
outCodecCtx->height = inCodecCtx->height;
outCodecCtx->time_base.num=1;
outCodecCtx->time_base.den=30;
outCodecCtx->bit_rate=110000;
outCodecCtx->gop_size=10;
if(outCodecCtx->codec_id==AV_CODEC_ID_H264)
outCodecCtx->qmin=10;
outCodecCtx->qmax=51;
outCodecCtx->qcompress=(float)0.6;
else if(outCodecCtx->codec_id==AV_CODEC_ID_MPEG2VIDEO)
outCodecCtx->max_b_frames=2;
else if(outCodecCtx->codec_id==AV_CODEC_ID_MPEG1VIDEO)
outCodecCtx->mb_decision=2;
//打开编码器
if(avcodec_open2(outCodecCtx,outCodec,NULL)<0)
printf("Open encoder failed.\\n");
return -1;
///编码器部分结束
此部分代码和FFmpeg4入门12:本地yuv文件编码为h264一样。
编解码部分
先将数据从原始的YUYV422转换为YUV420P,然后再将YUV420P编码为H264。
///编解码部分//
yuvFrame->format = outCodecCtx->pix_fmt;
yuvFrame->width = outCodecCtx->width;
yuvFrame->height = outCodecCtx->height;
ret = avformat_write_header(outFmtCtx,NULL);
int count = 0;
while(av_read_frame(inFmtCtx,inPkt)>=0 && count<50)
if(inPkt->stream_index == inVideoStreamIndex)
if(avcodec_send_packet(inCodecCtx,inPkt)>=0)
while((ret=avcodec_receive_frame(inCodecCtx,srcFrame))>=0)
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return -1;
else if (ret < 0)
fprintf(stderr, "Error during decoding\\n");
exit(1);
sws_scale(img_ctx,
srcFrame->data,srcFrame->linesize,
0,inCodecCtx->height,
yuvFrame->data,yuvFrame->linesize);
yuvFrame->pts=srcFrame->pts;
//encode
if(avcodec_send_frame(outCodecCtx,yuvFrame)>=0)
if(avcodec_receive_packet(outCodecCtx,outPkt)>=0)
printf("encode one frame.\\n");
++count;
outPkt->stream_index = outVStream->index;
av_packet_rescale_ts(outPkt,outCodecCtx->time_base,
outVStream->time_base);
outPkt->pos=-1;
av_interleaved_write_frame(outFmtCtx,outPkt);
av_packet_unref(outPkt);
usleep(1000*24);
av_packet_unref(inPkt);
就是先解码然后再编码,将两者结合起来。
结果
编译运行程序,输出为:
$ ./camera2h264
[libx264 @ 0x5565f9304cc0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[libx264 @ 0x5565f9304cc0] profile High, level 3.0, 4:2:0, 8-bit
encode one frame.
...
encode one frame.
Flushing stream #0 encoder
success encoder 1 frame.
...
success encoder 1 frame.
[libx264 @ 0x5565f9304cc0] frame I:8 Avg QP:15.79 size: 46078
[libx264 @ 0x5565f9304cc0] frame P:22 Avg QP:13.08 size: 49616
[libx264 @ 0x5565f9304cc0] frame B:45 Avg QP:14.14 size: 41955
[libx264 @ 0x5565f9304cc0] consecutive B-frames: 20.0% 0.0% 0.0% 80.0%
[libx264 @ 0x5565f9304cc0] mb I I16..4: 7.9% 60.7% 31.4%
[libx264 @ 0x5565f9304cc0] mb P I16..4: 2.7% 31.7% 12.3% P16..4: 15.5% 18.6% 14.4% 0.0% 0.0% skip: 4.9%
[libx264 @ 0x5565f9304cc0] mb B I16..4: 0.7% 16.6% 7.2% B16..8: 24.3% 16.9% 8.6% direct:16.1% skip: 9.5% L0:34.1% L1:26.8% BI:39.1%
[libx264 @ 0x5565f9304cc0] final ratefactor: -39.38
[libx264 @ 0x5565f9304cc0] 8x8 transform intra:65.9% inter:39.8%
[libx264 @ 0x5565f9304cc0] coded y,uvDC,uvAC intra: 95.0% 97.3% 93.9% inter: 77.6% 84.7% 72.6%
[libx264 @ 0x5565f9304cc0] i16 v,h,dc,p: 8% 12% 13% 68%
[libx264 @ 0x5565f9304cc0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 15% 22% 23% 5% 6% 5% 9% 5% 11%
[libx264 @ 0x5565f9304cc0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 18% 22% 13% 6% 7% 6% 9% 6% 11%
[libx264 @ 0x5565f9304cc0] i8c dc,h,v,p: 72% 11% 10% 8%
[libx264 @ 0x5565f9304cc0] Weighted P-Frames: Y:22.7% UV:22.7%
[libx264 @ 0x5565f9304cc0] ref P L0: 58.8% 10.1% 18.3% 12.8% 0.1%
[libx264 @ 0x5565f9304cc0] ref B L0: 77.4% 18.8% 3.8%
[libx264 @ 0x5565f9304cc0] ref B L1: 87.4% 12.6%
[libx264 @ 0x5565f9304cc0] kb/s:0.15
然后使用ffplay检测一下结果是否正确:
当然可以参照FFmpeg4入门8:软解并使用QtWidget播放视频(YUV420P->RGB32)直接在QT界面显示摄像头数据。
完整代码在ffmpeg_Beginner中的14.video_encode_camera2h264
中。
本文首发于:FFmpeg4入门14:Linux下摄像头捕获并编码为h264
Linux下使用FFmpeg实现采集摄像头数据
FFmpeg采集摄像头数据
文章目录
前言
博主对音视频蛮感兴趣的,学习了一段时间的FFmpeg。前几天,在逛博客的时候发现在Linux下使用FFmpeg采集摄像头的数据,由于这采集摄像头的数据没写过代码,于是复现了下人家的代码,是一个比较简单的demo程序,仅供参考。
一、查看Linux系统下的摄像头设备
前排提示:在看此博客的之前,需要在自己的Ubuntu环境中安装FFmpeg,若没安装FFmpeg,可以在网上搜教程(网上的教程还是蛮详细的)。
在Linux系统中,使用的是v4l2框架来驱动摄像头设备的。
使用FFmpeg的ffprobe命令来查看连接到Ubuntu系统中的摄像头设备,如下图。
从图中可以看到,所使用摄像头的参数,从图中可以看出摄像头输出的原始参数是yuyv422的形式,一般我们使用的是yuv420p的数据,因此在保存摄像头数据的时候,先对yuyu422的格式进行变化,将其变换为yuv420p的格式,然后再进行编码保存为h264的文件。
二、代码
1.在main函数中,所需要用到的参数的声明
int ret = 0;
// 注册所有的设备
avdevice_register_all();
// 输入设备的相关参数
AVFormatContext *inFmtCtx = avformat_alloc_context();
AVCodec *inCodec = NULL;
AVCodecContext *inCodecCtx = NULL;
int inVideoSteamIndex = -1;
struct SwsContext *img_ctx = NULL;
AVFrame *yuvFrame = NULL;
AVFrame *srcFrame = NULL;
AVPacket *inPkt = av_packet_alloc();
// 输出文件的相关参数
AVFormatContext *outFmtCtx = avformat_alloc_context();
AVOutputFormat *outFmt = NULL;
AVStream *outStream = NULL;
AVCodecContext *outCodecCtx=NULL;
AVCodec *outCodec = NULL;
AVPacket *outPkt = av_packet_alloc();
2.解码摄像头原始参数设置
// 解码部分
// 打开v4l2的相机输入
AVInputFormat *inFmt = av_find_input_format("v4l2");
if(avformat_open_input(&inFmtCtx,"/dev/video0",inFmt,NULL) < 0)
fprintf(stderr,"Cannot open camera.\\n");
return -1;
// 查找流
if(avformat_find_stream_info(inFmtCtx,NULL) < 0)
fprintf(stderr,"Cannot find any stream in file.\\n");
return -1;
// 寻找视频流
for(size_t i = 0;i < inFmtCtx->nb_streams;i++)
if(inFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
inVideoSteamIndex = i;
break;
// 没找到视频流
if(inVideoSteamIndex == -1)
fprintf(stderr,"Cannot find video stream in file.\\n");
return -1;
// 创建解码器的参数集
AVCodecParameters* inVideoCodecPara = inFmtCtx->streams[inVideoSteamIndex]->codecpar;
// 查找解码器
if(!(inCodec = avcodec_find_decoder(inVideoCodecPara->codec_id)))
fprintf(stderr,"Cannot find valid video decoder.\\n");
return -1;
if(!(inCodecCtx = avcodec_alloc_context3(inCodec)))
fprintf(stderr,"Cannot alloc valid decode codec context.\\n");
return -1;
if(avcodec_parameters_to_context(inCodecCtx,inVideoCodecPara) < 0)
fprintf(stderr,"Cannot initialize parameters.\\n");
return -1;
// 打开编解码器
if(avcodec_open2(inCodecCtx,inCodec,NULL) < 0)
fprintf(stderr,"Cannot open codec.\\n");
return -1;
img_ctx = sws_getContext(inCodecCtx->width,inCodecCtx->height,inCodecCtx->pix_fmt,
inCodecCtx->width,inCodecCtx->height,AV_PIX_FMT_YUV420P,SWS_BICUBIC,NULL,NULL,NULL);
// 获取图像的大小
int num_bytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P,inCodecCtx->width,inCodecCtx->height,1);
// 创建out_buffer缓冲区
uint8_t *out_buffer = (unsigned char *)av_malloc(num_bytes*sizeof(unsigned char));
yuvFrame = av_frame_alloc();
srcFrame = av_frame_alloc();
// 将yuvframe和out_buffer进行关联
int ret = av_image_fill_arrays(yuvFrame->data,yuvFrame->linesize,out_buffer,AV_PIX_FMT_YUV420P,inCodecCtx->width,inCodecCtx->height,1);
if(ret < 0)
fprintf(stderr,"Fill arrays failed.\\n");
return -1;
3.输出H264文件部分
// 输出文件,编码器部分
const char* out_file = "output.h264";
if(avformat_alloc_output_context2(&outFmtCtx,NULL,NULL,out_file) < 0)
fprintf(stderr,"Cannot alloc output file context.\\n");
return -1;
outFmt = outFmtCtx->oformat;
// 打开输出文件
if(avio_open(&outFmtCtx->pb,out_file,AVIO_FLAG_READ_WRITE) < 0)
fprintf(stderr,"output file open failed.\\n");
return -1;
// 创建保存的H264流,并设置参数
outStream = avformat_new_stream(outFmtCtx,outCodec);
if(outStream == NULL)
fprintf(stderr,"create new video stream fialed.\\n");
return -1;
//
outStream->time_base.den = 30;
outStream->time_base.num = 1;
// 编码解码器相关的参数集
// 设置分辨率和bit率
AVCodecParameters *outCodecPara = outFmtCtx->streams[outStream->index]->codecpar;
outCodecPara->codec_type=AVMEDIA_TYPE_VIDEO;
outCodecPara->codec_id = outFmt->video_codec;
outCodecPara->width = 640;
outCodecPara->height = 360;
outCodecPara->bit_rate = 92000;
// 查找编码器
outCodec = avcodec_find_encoder(outFmt->video_codec);
if(outCodec == NULL)
fprintf(stderr,"Cannot find any encoder.\\n");
return -1;
// 设置编码器内容
outCodecCtx = avcodec_alloc_context3(outCodec);
avcodec_parameters_to_context(outCodecCtx,outCodecPara);
if(outCodecCtx==NULL)
fprintf(stderr,"Cannot alloc output codec content.\\n");
return -1;
outCodecCtx->codec_id = outFmt->video_codec;
outCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
outCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
outCodecCtx->width = inCodecCtx->width;
outCodecCtx->height = inCodecCtx->height;
outCodecCtx->time_base.num = 1;
outCodecCtx->time_base.den = 30;
outCodecCtx->bit_rate = 92000;
outCodecCtx->gop_size = 10;
// 根据编码器相关类型设置参数
// 设置H264相关的参数,q的参数
if(outCodecCtx->codec_id == AV_CODEC_ID_H264)
outCodecCtx->qmin = 10;
outCodecCtx->qmax = 51;
outCodecCtx->qcompress = (float)0.6;
else if(outCodecCtx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
outCodecCtx->max_b_frames = 2;
else if(outCodecCtx->codec_id == AV_CODEC_ID_MPEG1VIDEO)
outCodecCtx->mb_decision = 2;
// 打开编码器
if(avcodec_open2(outCodecCtx,outCodec,NULL) < 0)
fprintf(stderr,"Open encoder failed.\\n");
return -1;
// 设置yuvframe
yuvFrame->format = outCodecCtx->pix_fmt;
yuvFrame->width = outCodecCtx->width;
yuvFrame->height = outCodecCtx->height;
// 写H264的文件头
ret = avformat_write_header(outFmtCtx,NULL);
4.编解码开始部分
洗刷编码缓存区的代码
int flush_encoder(AVFormatContext *fmtCtx,AVCodecContext *codecCtx,int StreamaIndex)
int ret = 0;
AVPacket enc_pkt;
enc_pkt.data = NULL;
enc_pkt.size = 0;
av_init_packet(&enc_pkt);
printf("Flushing stream #%u encoder\\n",StreamaIndex);
// 进行编码一个frame
if(avcodec_send_frame(codecCtx,0) >= 0)
while(avcodec_receive_packet(codecCtx,&enc_pkt) >= 0)
printf("success encoder 1 frame.\\n");
enc_pkt.stream_index = StreamaIndex;
av_packet_rescale_ts(&enc_pkt,codecCtx->time_base,fmtCtx->streams[ StreamaIndex ]->time_base);
// 将编码好的写入到H264的文件
ret = av_interleaved_write_frame(fmtCtx, &enc_pkt);
if(ret < 0)
break;
return ret;
编解码部分
int count = 0;
// 读取一个frame的数据,放入pakcet中
while(av_read_frame(inFmtCtx,inPkt) >= 0 && count < 50)
// 判断是否是视频流
if(inPkt->stream_index == inVideoSteamIndex)
// 解码
if(avcodec_send_packet(inCodecCtx,inPkt) >= 0)
// 判断是否解码完成
while((ret = avcodec_receive_frame(inCodecCtx,srcFrame)) >= 0)
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return -1;
else if(ret < 0)
fprintf(stderr, "Error during decoding\\n");
exit(1);
// 解码完成
// 进行转换,由于摄像头输入的yuyv422的格式,因此需要进行转换,转换到yuv420p的格式
sws_scale(img_ctx,(const uint8_t* const*)srcFrame->data,srcFrame->linesize,
0,inCodecCtx->height,yuvFrame->data,yuvFrame->linesize);
yuvFrame->pts = srcFrame->pts;
// 解码完成之后进行编码
if(avcodec_send_frame(outCodecCtx,yuvFrame) >= 0)
if(avcodec_receive_packet(outCodecCtx,outPkt) >= 0)
printf("----encode one frame-----\\n");
++count;
outPkt->stream_index = outStream->index;
av_packet_rescale_ts(outPkt,outCodecCtx->time_base,outStream->time_base);
outPkt->pos = -1;
av_interleaved_write_frame(outFmtCtx,outPkt);
av_packet_unref(outPkt);
// 短暂的延迟
usleep(1000 * 24);
av_packet_unref(inPkt);
// 洗刷编码区
ret = flush_encoder(outFmtCtx,outCodecCtx,outStream->index);
if(ret < 0)
fprintf(stderr,"flushing encoder failed.\\n");
return -1;
// 写H264的文件尾
av_write_trailer(outFmtCtx);
5.收尾部分
收尾部分,主要进行内存空间的释放。由于是demo程序,内存空间释放写的比较简陋,其实很多错误检查的时候,应该使用goto语句,然后进行内存空间的释放。
av_packet_free(&inPkt);
avcodec_free_context(&inCodecCtx);
avcodec_close(inCodecCtx);
avformat_close_input(&inFmtCtx);
av_frame_free(&srcFrame);
av_frame_free(&yuvFrame);
av_packet_free(&outPkt);
avcodec_free_context(&outCodecCtx);
avcodec_close(outCodecCtx);
avformat_close_input(&outFmtCtx);
6.源码
在这里贴出demo程序的源码。
#include <unistd.h>
#include "libavcodec/avcodec.h"
#include "libavdevice/avdevice.h"
#include "libswresample/swresample.h"
#include "libavutil/avutil.h"
#include "libavutil/frame.h"
#include "libavutil/samplefmt.h"
#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
#include "libavutil/parseutils.h"
#include "libswscale/swscale.h"
#include "libavformat/avformat.h"
int flush_encoder(AVFormatContext *fmtCtx,AVCodecContext *codecCtx,int StreamaIndex)
int ret = 0;
AVPacket enc_pkt;
enc_pkt.data = NULL;
enc_pkt.size = 0;
av_init_packet(&enc_pkt);
printf("Flushing stream #%u encoder\\n",StreamaIndex);
// 进行编码一个frame
if(avcodec_send_frame(codecCtx,0) >= 0)
while(avcodec_receive_packet(codecCtx,&enc_pkt) >= 0)
printf("success encoder 1 frame.\\n");
enc_pkt.stream_index = StreamaIndex;
av_packet_rescale_ts(&enc_pkt,codecCtx->time_base,fmtCtx->streams[ StreamaIndex ]->time_base);
// 将编码好的写入到H264的文件
ret = av_interleaved_write_frame(fmtCtx, &enc_pkt);
if(ret < 0)
break;
return ret;
int main(int argc, char* argv[])
int ret = 0;
// 注册所有的设备
avdevice_register_all();
// 输入设备的相关参数
AVFormatContext *inFmtCtx = avformat_alloc_context();
AVCodec *inCodec = NULL;
AVCodecContext *inCodecCtx = NULL;
int inVideoSteamIndex = -1;
struct SwsContext *img_ctx = NULL;
AVFrame *yuvFrame = NULL;
AVFrame *srcFrame = NULL;
AVPacket *inPkt = av_packet_alloc();
// 输出文件的相关参数
AVFormatContext *outFmtCtx = avformat_alloc_context();
AVOutputFormat *outFmt = NULL;
AVStream *outStream = NULL;
AVCodecContext *outCodecCtx=NULL;
AVCodec *outCodec = NULL;
AVPacket *outPkt = av_packet_alloc();
do
// 解码部分
// 打开v4l2的相机输入
AVInputFormat *inFmt = 以上是关于FFmpeg4入门14:Linux下摄像头捕获并编码为h264的主要内容,如果未能解决你的问题,请参考以下文章
FFmpeg4.1编译:mac+android-ndk-14b+ffmpeg4.1成功编译
如何从相机(或网络摄像头)在 python 中捕获视频(和音频)