最新版ffmpeg 提取视频关键帧

对于ffmpeg的配置请看我的上篇博客:http://blog.csdn.net/kuaile123/article/details/11367309

所用视频为 flv格式的,用的vs2010,电脑为64位,下面的也是64位,别下错了。

因为ffmpeg的函数和版本有关系,这里记录下我所用的整合的版本,是昨天下的最新版的,需要请下载

http://download.csdn.net/detail/kuaile123/6232827(因为博主没有积分可用了,所以需要积分)

32位的请去官网下载。

从网上找到的都是旧版本的函数,函数的讲解可用直接自己看里面include中的.h文件,自己根据新版的文件自己弄出来的。

需要用到libavformat 用来处理解析视频文件并将包含在其中的流分离出来, 而libavcodec 则处理原始音频和视频流的解码

还是上代码:

完整的代码下载:http://download.csdn.net/detail/kuaile123/6232905

//注册库中含有的所有可用的文件格式和编码器,这样当打开一个文件时,它们才能够自动选择相应的文件格式和编码器。
	av_register_all();

	int ret;
	// 打开视频文件
	if((ret=avformat_open_input(&pInputFormatContext, sourceFile, NULL, NULL))!=0){
		cout<<" can't open file "<<endl;
	    return -1;
	}
	// 取出文件流信息
	if(avformat_find_stream_info(pInputFormatContext,NULL)<0){ 
		cout<<" can't find suitable codec parameters"<<endl;
		return -1;
	}
	//用于诊断 //产品中不可用
	//dump_format(pInputFormatContext, 0, sourceFile, false);

	//仅仅处理视频流
	//只简单处理我们发现的第一个视频流
	//  寻找第一个视频流
	int videoIndex = -1;
	for(int i=0; i<pInputFormatContext->nb_streams; i++) {
		if(pInputFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
			videoIndex = i;
			break;
		}
	} 
	 if(-1 == videoIndex){
		 cout<<" can't find video stream !"<<endl;
		 return -1;
	 }
	 // 得到视频流编码上下文的指针
	 pInputCodecContext = pInputFormatContext->streams[videoIndex]->codec; 
	 //  寻找视频流的解码器
	 pInputCodec = avcodec_find_decoder(pInputCodecContext->codec_id);  

	 if(NULL == pInputCodec){
		 cout<<"can't decode "<<endl;
		 return -1;
	 }

 // 通知解码器我们能够处理截断的bit流,bit流帧边界可以在包中
	 //视频流中的数据是被分割放入包中的。因为每个视频帧的数据的大小是可变的,
	 //那么两帧之间的边界就不一定刚好是包的边界。这里,我们告知解码器我们可以处理bit流。
	 if(pInputCodec->capabilities & CODEC_CAP_TRUNCATED){
		 pInputCodecContext->flags|=CODEC_FLAG_TRUNCATED;
	 }


	 //打开解码器
	 if(avcodec_open2(pInputCodecContext, pInputCodec,NULL) != 0) {
		 cout<<"decode error"<<endl;
		 return -1;
	 }
	 int videoHeight;
	 int videoWidth;
	 videoWidth = pInputCodecContext->width;
	 videoHeight = pInputCodecContext->height; 

	 AVPacket InPack;
	 int len = 0;
	 AVFrame OutFrame;
	 int nComplete=0;

 int nFrame = 0;
	 AVRational avRation = pInputCodecContext->time_base;
	 float frameRate = (float)avRation.den/avRation.num;
	 //av_seek_frame(pInputFormatContext,0);
	 while((av_read_frame(pInputFormatContext, &InPack) >= 0)){
		 len = avcodec_decode_video2(pInputCodecContext, &OutFrame, &nComplete, &InPack);  

		  //判断是否是关键帧
		 if(nComplete > 0 && OutFrame.key_frame){ 
			 //解码一帧成功
			 SaveBmp(pInputCodecContext, &OutFrame, videoWidth, videoHeight,nFrame);  
			 nFrame++;
		 }
	 }
	 cout<<" save frame number: "<<nFrame<<endl;
	 avcodec_close(pInputCodecContext);  
	 av_free(pInputFormatContext);  


保存为bmp格式,保存函数如下:

void SaveBmp(AVCodecContext *CodecContex, AVFrame *Picture, int width, int height,int num)
{
	AVPicture pPictureRGB;//RGB图片

	static struct SwsContext *img_convert_ctx;
	img_convert_ctx = sws_getContext(width, height,	CodecContex->pix_fmt, width, height,\
		PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
	// 确认所需缓冲区大小并且分配缓冲区空间
	avpicture_alloc(&pPictureRGB, PIX_FMT_RGB24, width, height);
	sws_scale(img_convert_ctx, Picture->data, Picture->linesize,\
		0, height, pPictureRGB.data, pPictureRGB.linesize);

	int lineBytes = pPictureRGB.linesize[0], i=0;

	char fileName[1024]={0};
	char * bmpSavePath = "%d.bmp";
	//time_t ltime;
	//time(<ime);
	//sprintf(fileName,bmpSavePath , ltime);???????????????????????????
	sprintf(fileName,bmpSavePath , num);

	FILE *pDestFile = fopen(fileName, "wb");
	BITMAPFILEHEADER btfileHeader;
	btfileHeader.bfType = MAKEWORD(66, 77); 
	btfileHeader.bfSize = lineBytes*height; 
	btfileHeader.bfReserved1 = 0; 
	btfileHeader.bfReserved2 = 0; 
	btfileHeader.bfOffBits = 54;

	BITMAPINFOHEADER bitmapinfoheader;
	bitmapinfoheader.biSize = 40; 
	bitmapinfoheader.biWidth = width; 
	bitmapinfoheader.biHeight = height; 
	bitmapinfoheader.biPlanes = 1; 
	bitmapinfoheader.biBitCount = 24;
	bitmapinfoheader.biCompression = BI_RGB; 
	bitmapinfoheader.biSizeImage = lineBytes*height; 
	bitmapinfoheader.biXPelsPerMeter = 0; 
	bitmapinfoheader.biYPelsPerMeter = 0; 
	bitmapinfoheader.biClrUsed = 0; 
	bitmapinfoheader.biClrImportant = 0;

	fwrite(&btfileHeader, 14, 1, pDestFile);
	fwrite(&bitmapinfoheader, 40, 1, pDestFile);
	for(i=height-1; i>=0; i--)
	{
		fwrite(pPictureRGB.data[0]+i*lineBytes, lineBytes, 1, pDestFile);
	}

	fclose(pDestFile);
	avpicture_free(&pPictureRGB);
}
</pre><pre class="html" name="code" style="border: 1px solid rgb(255, 255, 204); font-family: 'Courier New'; overflow: auto; font-size: 16px; line-height: 24px; background-color: rgb(255, 255, 252);">http://m.blog.csdn.net/blog/dragonkuaile123/11378925
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 可以使用 ffmpeg 命令行工具提取视频的所有帧。命令格式如下: ``` ffmpeg -i input.mp4 -vf fps=1/60 frames/frame%d.jpg ``` 其,-i 后面是输入视频文件名,-vf fps=1/60 表示每秒提取 60 帧,frames/frame%d.jpg 表示输出的帧文件保存在 frames 文件夹,文件名格式为 frame1.jpg, frame2.jpg, frame3.jpg 等。 ### 回答2: FFmpeg 是一个开源的多媒体处理工具,可以用于处理音频、视频和字幕等多种多媒体格式。要提取视频的所有帧,可以使用 FFmpeg 的命令行工具来实现。 首先,需要确保安装了 FFmpeg 工具。然后,打开命令提示符或终端窗口,并输入以下命令: ffmpeg -i 视频文件路径 -r 帧率 图片文件名%04d.png 其视频文件路径是你要提取帧的视频文件的路径和文件名。帧率是指每秒钟的帧数,可以根据需要调整。图片文件名是你要保存帧的图像文件名的前缀,%04d.png 是一个占位符,表示帧序号。 命令执行后,FFmpeg 将会将视频的每一帧提取为一个独立的 PNG 图像文件,并按照指定的帧率和文件名保存在当前目录下。帧序号将以四位数的形式表示,例如,0001.png、0002.png、0003.png 等。 请注意,提取视频所有帧可能会占据大量的磁盘空间,特别是对于较长的视频文件来说。如果要提取视频很长或者帧率很高,可以根据需要增加保存帧的目录或缩小帧率。 总之,通过使用 FFmpeg 工具的命令行方式,我们可以方便地提取视频的所有帧。 ### 回答3: 通过使用FFmpeg提取视频的所有帧,您可以按照以下步骤进行操作: 1. 首先,您需要安装并设置好FFmpeg工具。您可以从FFmpeg官方网站(https://www.ffmpeg.org/)或其他可靠的软件源下载并安装FFmpeg。 2. 打开命令提示符(Windows)或终端(Mac或Linux)。 3. 切换到存储视频的文件夹所在的目录。例如,如果视频位于桌面上的一个文件夹,您可以使用以下命令进入该文件夹: ``` cd Desktop/folder_name ``` 4. 一旦您进入了视频所在的目录,您可以使用以下命令提取视频的所有帧: ``` ffmpeg -i input_video.mp4 output_frame%d.jpg ``` 在这个命令,'input_video.mp4'是您要提取帧的视频文件的名称,'output_frame%d.jpg'是您要保存提取的帧的文件名模板,其'%d'是帧的索引号。 5. 执行命令后,FFmpeg将开始提取视频的所有帧,并将它们以指定的文件名模板保存到当前目录。 6. 提取过程完成后,您将在当前目录看到许多图片文件,这些文件是视频的所有帧。 请注意,提取视频的所有帧可能需要一些时间,具体取决于视频的长度和计算机的性能。完成后,您可以在文件夹查找提取的帧并进行进一步的处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值