Linux下使用FFmpeg实现采集摄像头数据

本文介绍了如何在Linux系统下利用FFmpeg采集摄像头数据。首先,讲解了查看Linux摄像头设备的方法,接着详细展示了从参数声明到解码设置、输出H264文件、编解码操作以及收尾过程的完整代码实现。最后,给出了运行结果,包括生成的H264文件的播放验证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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);
        
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值