FFMpeg读取摄像头数据流

本文介绍了如何使用DirectShow设备读取摄像头数据,并通过特定方法获取摄像头信息。通过调用show_dshow_device()和show_dshow_device_option()函数,可以获取设备名和选项信息。在获取到视频数据后,利用AVFrame结构体保存为BMP图片格式,实现了摄像头数据的读取与图片保存功能。演示了一秒内保存30张图片,验证了摄像头帧率为30fps。

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

和上一篇博客的区别只在于,视频流从读文件变成了读摄像头数据。

定义两个方法,用来获取摄像头信息。

void show_dshow_device(){  
    AVFormatContext *pFormatCtx = avformat_alloc_context();  
    AVDictionary* options = NULL;  
    av_dict_set(&options,"list_devices","true",0);  
    AVInputFormat *iformat = av_find_input_format("dshow");  
    printf("Device Info=============\n");  
    avformat_open_input(&pFormatCtx,"video=dummy",iformat,&options);  
    printf("========================\n");  
}

void show_dshow_device_option(){  
    AVFormatContext *pFormatCtx = avformat_alloc_context();  
    AVDictionary* options = NULL;  
    av_dict_set(&options,"list_options","true",0);  
    AVInputFormat *iformat = av_find_input_format("dshow");  
    printf("========Device Option Info======\n");  

    avformat_open_input(&pFormatCtx,"video=1.3M WebCam",iformat,&options);  
    printf("================================\n");  
} 

解释:

"dshow"是DirectShow设备,我笔记本上就是这个设备。这个设备的名字叫“1.3M WebCam”,所在在把数据通过avformat_open_input方法传到AVFormatContext这个结构体里。从而可以从pFormatCtx->streams[i]得到视频流了。


还是把整个工程放进来。

#include <stdio.h>
#include <stdlib.h> 
#include <string.h>
#include <windows.h>


#define __STDC_CONSTANT_MACROS 
extern "C"  
{  
	#include "libavcodec/avcodec.h"	
	#include "libavformat/avformat.h"
	#include "libavdevice/avdevice.h"
	#include "libavfilter/avfilter.h"
	#include "libswscale/swscale.h"
	#include "libswresample/swresample.h"
	#include "libavutil/avutil.h"
}  
   
#pragma comment(lib, "avcodec.lib") 
#pragma comment(lib, "avformat.lib") 
#pragma comment(lib, "avdevice.lib") 
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "swscale.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "avutil.lib")



void show_dshow_device(){  
    AVFormatContext *pFormatCtx = avformat_alloc_context();  
    AVDictionary* options = NULL;  
    av_dict_set(&options,"list_devices","true",0);  
    AVInputFormat *iformat = av_find_input_format("dshow");  
    printf("Device Info=============\n");  
    avformat_open_input(&pFormatCtx,"video=dummy",iformat,&options);  
    printf("========================\n");  
}

void show_dshow_device_option(){  
    AVFormatContext *pFormatCtx = avformat_alloc_context();  
    AVDictionary* options = NULL;  
    av_dict_set(&options,"list_options","true",0);  
    AVInputFormat *iformat = av_find_input_format("dshow");  
    printf("========Device Option Info======\n");  

    avformat_open_input(&pFormatCtx,"video=1.3M WebCam",iformat,&options);  
    printf("================================\n");  
} 

//定义BMP文件头   
  
  
  
#ifndef _WINGDI_    
#define _WINGDI_    
typedef struct tagBITMAPFILEHEADER {    
    WORD    bfType;     
    DWORD   bfSize;     
    WORD    bfReserved1;     
    WORD    bfReserved2;     
    DWORD   bfOffBits;     
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;       
  
typedef struct tagBITMAPINFOHEADER{     
    DWORD      biSize;     
    LONG       biWidth;     
    LONG       biHeight;     
    WORD       biPlanes;     
    WORD       biBitCount;     
    DWORD      biCompression;     
    DWORD      biSizeImage;     
    LONG       biXPelsPerMeter;     
    LONG       biYPelsPerMeter;     
    DWORD      biClrUsed;     
    DWORD      biClrImportant;    
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;      
#endif      
//保存BMP文件的函数    
void SaveAsBMP (AVFrame *pFrameRGB, int width, int height, int index, int bpp)    
{   char buf[5] = {0};   //bmp头     
BITMAPFILEHEADER bmpheader;     
BITMAPINFOHEADER bmpinfo;     
FILE *fp;      
char *filename = new char[255];  //文件存放路径,根据自己的修改     
sprintf_s(filename,255,"%s_%d.bmp","C:/test",index);    
if ( (fp=fopen(filename,"wb+")) == NULL )   {      
    printf ("open file failed!\n");        
    return;    
 }       
    bmpheader.bfType = 0x4d42;    
    bmpheader.bfReserved1 = 0;    
    bmpheader.bfReserved2 = 0;      
    bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);    
    bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp/8;      
    bmpinfo.biSize = sizeof(BITMAPINFOHEADER);     
    bmpinfo.biWidth = width;     
    bmpinfo.biHeight = height;     
    bmpinfo.biPlanes = 1;     
    bmpinfo.biBitCount = bpp;     
    bmpinfo.biCompression = BI_RGB;      
    bmpinfo.biSizeImage = (width*bpp+31)/32*4*height;     
    bmpinfo.biXPelsPerMeter = 100;     
    bmpinfo.biYPelsPerMeter = 100;     
    bmpinfo.biClrUsed = 0;     
    bmpinfo.biClrImportant = 0;       
    fwrite (&bmpheader, sizeof(bmpheader), 1, fp);     
    fwrite (&bmpinfo, sizeof(bmpinfo), 1, fp);      
    fwrite (pFrameRGB->data[0], width*height*bpp/8, 1, fp);     
    fclose(fp);    
}  

int main ()  
{  
	AVFormatContext *pFormatCtx;  
    unsigned int i = 0, videoStream = -1;   
    AVCodecContext  *pCodecCtx;  
    AVCodec         *pCodec;  
    AVFrame *pFrame,*pFrameRGB;  
	struct SwsContext *pSwsCtx; 

	int frameFinished;  
    int PictureSize;  
    AVPacket packet;  
    uint8_t *buf; 

    av_register_all();  
    avformat_network_init();  
    pFormatCtx = avformat_alloc_context();  
      
  
    //Register Device  
    avdevice_register_all(); 

	//Show Dshow Device  
    show_dshow_device();  
    //Show Device Options  
    show_dshow_device_option();  
	AVInputFormat *ifmt=av_find_input_format("dshow");  
    //Set own video device's name  
    if(avformat_open_input(&pFormatCtx,"video=1.3M WebCam",ifmt,NULL)!=0){  
        printf("Couldn't open input stream.\n");  
        return -1;  
    }

	if(avformat_find_stream_info(pFormatCtx,NULL)<0)  
    {  
        printf("Couldn't find stream information.\n");  
        return -1;  
    } 

  //获取视频数据  
    for(int i=0;i<pFormatCtx->nb_streams;i++)  
          
        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){  
            videoStream = i ;  
        }  
          
        if(videoStream == -1){  
            printf("%s\n","find video stream failed");  
            exit(1);      
        }  
        pCodecCtx = pFormatCtx->streams[videoStream]->codec;  
        pCodec = avcodec_find_decoder(pCodecCtx->codec_id);  
  
        if(pCodec ==NULL){  
            printf("%d\n","avcode find decoder failed!");  
            exit(1);  
        }  
        //打开解码器  
        if(avcodec_open2(pCodecCtx,pCodec,NULL)<0){  
            printf("avcode open failed!\n");  
            exit(1);  
        }  
  
        //为每帧图像分配内存  
        pFrame = av_frame_alloc();  
        pFrameRGB = av_frame_alloc();  
  
        if(pFrame==NULL||pFrameRGB==NULL){  
            printf("av frame alloc failed!\n");  
            exit(1);  
        }  
        //获得帧图大小  
        PictureSize = avpicture_get_size(AV_PIX_FMT_BGR24,pCodecCtx->width,pCodecCtx->height);  
        buf = (uint8_t*)av_malloc(PictureSize);  
        if(buf ==NULL){  
            printf("av malloc failed!\n");  
            exit(1);  
        }  
          
        avpicture_fill((AVPicture *)pFrameRGB,buf,AV_PIX_FMT_BGR24,pCodecCtx->width,pCodecCtx->height);  
        //设置图像转换上下文  
        pSwsCtx = sws_getContext(pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,AV_PIX_FMT_BGR24,SWS_BICUBIC,NULL,NULL,NULL);  
        i = 0;  
          
        while(av_read_frame(pFormatCtx,&packet)>=0){  
            if(packet.stream_index==videoStream){  
                //真正的解码  
                avcodec_decode_video2(pCodecCtx,pFrame,&frameFinished,&packet);  
                if(frameFinished){  
                    //饭庄图像,否则是上下颠倒的  
                    pFrame->data[0]+=pFrame->linesize[0]*(pCodecCtx->height-1);  
                    pFrame->linesize[0]*=-1;  
                    pFrame->data[1]+=pFrame->linesize[1]*(pCodecCtx->height/2-1);  
                    pFrame->linesize[1]*=-1;  
                    pFrame->data[2]+=pFrame->linesize[2]*(pCodecCtx->header_bits/2-1);  
                    pFrame->linesize[2]*=-1;  
  
                    //转换图像格式,将解压出来的YUV420P的图像转换为BRG24的图像  
                    sws_scale(pSwsCtx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrameRGB->data,pFrameRGB->linesize);  
                    //保存为bmp图  
                    SaveAsBMP(pFrameRGB,pCodecCtx->width,pCodecCtx->height,i,24);  
                    i++;  
                }  
                av_free_packet(&packet);  
            }  
        }  
        sws_freeContext(pSwsCtx);  
        av_free(pFrame);  
        av_free(pFrameRGB);  
        avcodec_close(pCodecCtx);  
        avformat_close_input(&pFormatCtx);  
        return 0; 
}  

文章意义在于可以读摄像头并可以对帧进行处理。

跑了几秒钟,保存了很多图片。数了数,一秒钟保存30张。意思是我的摄像头的帧率是30。

源文件下载地址:http://download.csdn.net/download/bless2015/10129278

### 使用 FFmpeg摄像头捕获并处理实时视频流 #### 列出可用的摄像头设备 为了查找当前系统中的可用摄像头设备,可以通过执行如下命令来枚举所有可能的输入源: ```bash ffmpeg -list_devices true -f dshow -i dummy ``` 这条指令会显示一系列的信息,在其中可以找到标记为`DirectShow video devices`的部分,这里列出了所有的视频采集装置名称[^2]。 #### 开始捕捉视频流 一旦确认了要使用的具体摄像机标识符或描述符之后,就可以利用下面这样的语法结构启动实际的数据抓取过程: 对于Windows平台上的DirectShow兼容型外设而言: ```bash ffmpeg -f dshow -i video="USB Video Device" ``` 此处需替换`"USB Video Device"`为之前查询所得确切字符串表示形式的名字。 而对于Linux操作系统,则通常采用Video4Linux2 (V4L2)作为底层驱动程序框架来进行交互操作;相应的调用方式变为: ```bash ffmpeg -f v4l2 -i /dev/video0 output.mp4 ``` 这里的`/dev/video0`代表第一个被识别出来的影像摄录单元节点位置,而`output.mp4`则是指定保存录制下来的内容所存放在本地磁盘里的目标文件路径[^4]。 #### 实现实时推流至 RTMP 服务器 当希望把经过编码压缩后的媒体流传送给远端的服务端实例时,可参照以下模板配置推送链接参数: ```bash ffmpeg -f v4l2 -b:v 500k -f flv rtmp://server/live/streamkey ``` 此脚本片段里包含了几个重要的选项设置说明: - `-c:v libx264`: 指定H.264视频编解码器; - `-preset ultrafast`: 设置编码速度优先级为最快模式以减少延迟时间; - `-tune zerolatency`: 进一步优化低延时场景下的表现效果; - `-b:v 500k`: 控制输出比特率大小保持在一个合理的范围内; - `rtmp://server/live/streamkey`: 替换成真实的RTMP服务地址以及频道密钥[^3]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值