ffmpeg Windows下采集摄像头一帧数据,并保存为bmp图片

这里请注意,在编译ffmpeg时,不要使用--disable-devices选项。

使用

--enable-encoder=rawvideo
 --enable-decoder=rawvideo

启用rawvideo codec。

代码如下:

#include 
#include 
#include 

#include 
#include 
#include 
#include 

#include 

#include 

#define MAX_INPUT_DEVICE_NUM 10

#ifdef _WIN32
int strcasecmp(const char *s1, const char *s2)
{
	while ((*s1 != '\0')
		&& (tolower(*(unsigned char *) s1) ==
		tolower(*(unsigned char *) s2))) 
	{
		s1++;
		s2++;
	}
	return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
}
int strncasecmp(const char *s1, const char *s2, unsigned int n)
{
	if (n == 0)
		return 0;
	while ((n-- != 0)
		&& (tolower(*(unsigned char *) s1) ==
		tolower(*(unsigned char *) s2))) {
			if (n == 0 || *s1 == '\0' || *s2 == '\0')
				return 0;
			s1++;
			s2++;
	}
	return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
}
#endif

void save_bmp(unsigned char * data,int data_size,int w,int h,FILE * out)
{
	// 位图文件头
	BITMAPFILEHEADER bmpheader; 
	BITMAPINFO bmpinfo; 
	int bit = 24;

	bmpheader.bfType = ('M' <<8)|'B'; 
	bmpheader.bfReserved1 = 0; 
	bmpheader.bfReserved2 = 0; 
	bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); 
	bmpheader.bfSize = bmpheader.bfOffBits + w*h*bit/8;

	bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
	bmpinfo.bmiHeader.biWidth = w; 
	bmpinfo.bmiHeader.biHeight = 0-h; 
	bmpinfo.bmiHeader.biPlanes = 1; 
	bmpinfo.bmiHeader.biBitCount = bit; 
	bmpinfo.bmiHeader.biCompression = BI_RGB; 
	bmpinfo.bmiHeader.biSizeImage = 0; 
	bmpinfo.bmiHeader.biXPelsPerMeter = 100; 
	bmpinfo.bmiHeader.biYPelsPerMeter = 100; 
	bmpinfo.bmiHeader.biClrUsed = 0; 
	bmpinfo.bmiHeader.biClrImportant = 0;

	fwrite(&bmpheader,sizeof(BITMAPFILEHEADER),1,out); 
	fwrite(&bmpinfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,out);
	fwrite(data,data_size,1,out);
}
int CaptureFromLocalCamera()
{
	AVFormatContext *ic = NULL;
	AVFormatParameters in_fmt_para={0};
	AVPacket packet;
	char buffer[MAX_PATH]={0};
	int width = 0,height = 0;
	int ret,video_stream = -1,i=0;

	//查找输入(vfwcap)格式
	AVInputFormat *in_fmt = av_find_input_format ("vfwcap"); 
	if (in_fmt == NULL) 
	{
		printf("not support input device vfwcap.\n");
		return -1;
	}
	memset (&in_fmt_para, 0, sizeof(in_fmt_para));
	//指定需要采集图像的高度
	in_fmt_para.height = height;
	//指定需要采集图像的宽度
	in_fmt_para.width  = width;

	//设置帧率
	av_parse_video_frame_rate(&in_fmt_para.time_base,"20");

	//打开摄像头设备,从"0"到MAX_INPUT_DEVICE_NUM依次尝试打开
	for( i=0 ; i < MAX_INPUT_DEVICE_NUM + 1; i++ )
	{
		sprintf(buffer,"%d",i);
		ret = av_open_input_file ( &ic, buffer, in_fmt,sizeof(in_fmt_para),&in_fmt_para);
		if ( ret == 0 && ic)
		{
			break;
		}
	}
	//open success?
	if(!ic || ret != 0)
	{
		if(ic)
			av_close_input_file(ic);
		printf("can not open input file.\n");
		return -2;
	}
	printf("input device no. is %d\n",i);
	//find the video stream
	for(i=0;inb_streams;i++)
	{
		if ( CODEC_TYPE_VIDEO == ic ->streams[i] ->codec ->codec_type )
		{
			video_stream = i;
			break;
		}
	}
	if(video_stream < 0)
	{
		av_close_input_file(ic);
		printf("can not find a video stream.\n");
		return -3;
	}
	//获取视频时间宽度和高度
	width  = ic ->streams[video_stream] ->codec ->width;
	height = ic ->streams[video_stream] ->codec ->height;
	printf("video size: %dx%d\n",width,height);
	//从摄像头获取图像数据
	if( 0 == av_read_frame(ic,&packet))
	{
		//find the decode codec
		AVCodec * decodec =  avcodec_find_decoder(ic ->streams[video_stream] ->codec ->codec_id);
		if(decodec)
		{
			//open the decode codec
			if( 0 == avcodec_open(ic ->streams[video_stream] ->codec,decodec) )
			{
				int got_picture = 0;
				AVFrame * frame = avcodec_alloc_frame();
				avcodec_decode_video2(ic ->streams[video_stream] ->codec,frame,&got_picture,&packet);
				//decode success
				if(got_picture)
				{
					uint8_t * buffer = NULL;
					size_t buffer_size = 0;
					struct SwsContext *pSwsCtx=NULL;
					AVFrame * rgb_frame = avcodec_alloc_frame();
					buffer_size = avpicture_get_size(PIX_FMT_BGR24,width,height);
					buffer = (uint8_t *)av_malloc(buffer_size);
					avpicture_fill((AVPicture*)rgb_frame,(uint8_t *)buffer,PIX_FMT_BGR24,width,height);
					//get swscale ctx
					pSwsCtx = sws_getContext(
						ic ->streams[video_stream] ->codec ->width,
						ic ->streams[video_stream] ->codec ->height,
						ic ->streams[video_stream] ->codec ->pix_fmt,
						width,
						height,
						PIX_FMT_BGR24,
						SWS_BILINEAR,
						NULL,
						NULL,
						NULL);
					if(pSwsCtx)
					{
						FILE *fp = NULL;
						SYSTEMTIME dt={0};
						//图像格式转换
						sws_scale(
							pSwsCtx,
							frame ->data,
							frame ->linesize,
							0,
							ic ->streams[video_stream] ->codec ->height,
							rgb_frame ->data,
							rgb_frame ->linesize);
						//create the image file name
						GetLocalTime(&dt);
						srand(0);
						sprintf(buffer,"imgs/%04d_%02d_%02d %02d_%02d_%02d %02d.bmp",dt.wYear,dt.wMonth,dt.wDay,dt.wHour,dt.wMinute,dt.wSecond,rand()%30);
						//
						CreateDirectoryA("imgs",NULL);
						//open file
						fp = fopen(buffer, "wb");
						if(fp)
						{
							save_bmp(rgb_frame ->data[0],rgb_frame ->linesize[0]*height,width,height,fp);
							fclose(fp);
						}
						//free sws ctx
						sws_freeContext(pSwsCtx);
					}
					//free buffer
					av_free(rgb_frame);
					av_free(buffer);
				}
				//free buffer
				av_free(frame);
				//close the decode codec
				avcodec_close(ic ->streams[video_stream] ->codec);
			}
		}
	}
		
	//close the input device
	av_close_input_file(ic);

	return 0;
}


int main()
{
	//avcodec_init();    
	avcodec_register_all();
	avdevice_register_all();
	CaptureFromLocalCamera();

	return 0;
}


 

你可能感兴趣的:(多媒体编程)