http://www.tuicool.com/articles/jiUzua

主题 FFmpeg
 

任务:需要把一个视频文件的每一帧提取出来,每帧存储成单独的文件。

以前用Matlab处理过这个问题,可是感觉比较慢,而且最近正在逐步转向使用开源的东西。因此搜到ffmpeg这个好东西。

ffmpeg可用来处理视频文件的提取和各种转换,跨平台,官网上有Linux,WINDOWS和MAC版本。

以下是windows 命令行下使用ffmpeg提取视频帧的方法:

SET PATH=%PATH%;[path_to_ffmpeg]
SET VIDEOFILE=demo.mp4
SET DESTDIR=video_frame\
ffmpeg -i %VIDEOFILE% -q:v 2 -f image2 %DESTDIR%%07d.jpeg
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

其中-i 后面是输入文件,-q:v 2 q代表质量quality, v代表视频流,2是控制质量的参数。-f指定输出的格式是image2. %07d是图片命名的pattern

//--------------------------------------------------------------------------------------------

第一次接触ffmpeg,可以算是hello world程序。

下面的代码全部都是直接可以使用的,借鉴了官方学习样例,也算是翻译吧。

但是解决了,保存bmp图像时,图像颠倒和色彩异常问题。

// x_ffmpeg.cpp : Defines the entry point for the console application.
// #include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <iosfwd>
#include <fstream>
using namespace std; #define FILE_OUT
#ifdef FILE_OUT
std::ofstream file_debugout("frameandpacketinfo.txt");
#endif static int av_create_bmp(char* filename,uint8_t *pRGBBuffer,int width,int height,int bpp)
{
BITMAPFILEHEADER bmpheader;
BITMAPINFO bmpinfo;
FILE *fp; fp = fopen(filename,"wb");
if(!fp)return -1; bmpheader.bfType = ('M'<<8)|'B';
bmpheader.bfReserved1 = 0;
bmpheader.bfReserved2 = 0;
bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp/8;
bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpinfo.bmiHeader.biWidth = width;
/*----注意,这里的bmpinfo.bmiHeader.biHeight变量的正负决定bmp文件的存储方式,如果
为负值,表示像素是倒过来的*/
bmpinfo.bmiHeader.biHeight = -height;
bmpinfo.bmiHeader.biPlanes = 1;
bmpinfo.bmiHeader.biBitCount = bpp;
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,fp);
fwrite(&bmpinfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
fwrite(pRGBBuffer,width*height*bpp/8,1,fp);
fclose(fp); return 0;
} static int av_create_bmp(char* filename, AVFrame *pRGBBuffer,int width,int height,int bpp)
{
BITMAPFILEHEADER bmpheader;
BITMAPINFO bmpinfo;
FILE *fp; fp = fopen(filename, "wb");
if(!fp)return -1; bmpheader.bfType = ('M'<<8)|'B';
bmpheader.bfReserved1 = 0;
bmpheader.bfReserved2 = 0;
bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp/8;
bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpinfo.bmiHeader.biWidth = width;
bmpinfo.bmiHeader.biHeight = -height;
bmpinfo.bmiHeader.biPlanes = 1;
bmpinfo.bmiHeader.biBitCount = 24;
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,fp);
fwrite(&bmpinfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
//fwrite(pRGBBuffer,width*height*bpp/8,1,fp);
for(int y=0; y<height; y++)
fwrite(pRGBBuffer->data[0] + y*pRGBBuffer->linesize[0], 1, width*3, fp);
fclose(fp);
return 0;
} static void print_packet_info(AVPacket info)
{
#ifdef FILE_OUT
file_debugout << "print_packet_info" << " convergence_duration:" << info.convergence_duration
<< " dts:" << info.dts
<< " duration:" << info.duration
<< " flags:" << info.flags
<< " pos:" << info.pos
<< " pts:" << info.pts
<< " size:" << info.size
<< " stream_index:" << info.stream_index << endl;
#else
cout << "print_packet_info" << " convergence_duration:" << info.convergence_duration
<< " dts:" << info.dts
<< " duration:" << info.duration
<< " flags:" << info.flags
<< " pos:" << info.pos
<< " pts:" << info.pts
<< " size:" << info.size
<< " stream_index:" << info.stream_index << endl;
#endif
} static void print_frame_info(AVFrame* pinfo)
{
#ifdef FILE_OUT
file_debugout << "print_frame_info" << " coded_picture_number:" << pinfo->coded_picture_number
<< " display_picture_number:" << pinfo->display_picture_number
<< " type:" << pinfo->type << endl;
#else
cout << "print_frame_info" << " coded_picture_number:" << pinfo->coded_picture_number
<< " display_picture_number:" << pinfo->display_picture_number
<< " type:" << pinfo->type << endl;
#endif } int decode_video_packet(AVFormatContext * fmt_ctx_for_decode, \
AVCodecContext* dec_ctx, int video_stream_index)
{
int ret = 0; AVFrame* pFrame=avcodec_alloc_frame();
AVFrame* pFrameRGB = avcodec_alloc_frame(); int numBytes=avpicture_get_size(PIX_FMT_BGR24, dec_ctx->width,dec_ctx->height);
uint8_t* buffer = new(std::nothrow) uint8_t[numBytes]; avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24,\
dec_ctx->width, dec_ctx->height); SwsContext *pSWSCtx = sws_getContext(dec_ctx->width, dec_ctx->height, \
dec_ctx->pix_fmt, dec_ctx->width, dec_ctx->height, PIX_FMT_BGR24,\
SWS_BICUBIC, NULL, NULL, NULL); if (NULL == pFrame || NULL == pFrameRGB || NULL == buffer || NULL == pSWSCtx)
{
ret = -1;
goto exit;
} AVPacket packet;
int key_frame_picture_count = 0; while (av_read_frame(fmt_ctx_for_decode, &packet) >= 0)
{
if (packet.stream_index == video_stream_index)
{
int got_frame = 0;
avcodec_decode_video2(dec_ctx, pFrame,&got_frame, &packet); if (got_frame) //一个完整的帧
{
if (pFrame->key_frame)
{
sws_scale(pSWSCtx, pFrame->data, pFrame->linesize,0, \
dec_ctx->height, pFrameRGB->data, pFrameRGB->linesize); // 保存到磁盘
char pic[200];
sprintf(pic,"keyframe%d.bmp", ++key_frame_picture_count);
av_create_bmp(pic,pFrameRGB->data[0],dec_ctx->width,dec_ctx->height,24);
//av_create_bmp(pic, pFrameRGB, dec_ctx->width,dec_ctx->height,24);
}
print_frame_info(pFrame); } print_packet_info(packet);
} } exit:
avcodec_free_frame(&pFrame);
avcodec_free_frame(&pFrameRGB);
delete [] buffer;
sws_freeContext(pSWSCtx);
return ret;
} static int open_input_file(const char *filename)
{
int ret;
bool video_codec_init = false;
int video_stream_index = -1;
AVCodecContext* suitable_dec_ctx = NULL;
AVFormatContext *video_fmt_ctx = NULL; if ((ret = avformat_open_input(&video_fmt_ctx, filename, NULL, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
return ret;
} if ((ret = avformat_find_stream_info(video_fmt_ctx, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
avformat_close_input(&video_fmt_ctx);
return ret;
} for (int i = 0; i < video_fmt_ctx->nb_streams; i++)
{
// 找到视频码流
if (video_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
video_stream_index = i;
// 初始化解码器信息
if (!video_codec_init)
{
suitable_dec_ctx = video_fmt_ctx->streams[i]->codec; AVCodec* pcodec = avcodec_find_decoder(suitable_dec_ctx->codec_id); if (NULL == pcodec)
{
printf("cannot find decoder");
avformat_close_input(&video_fmt_ctx);
return 1;
} if(0 != avcodec_open2(suitable_dec_ctx, pcodec, NULL))
{
printf("open codecer failed");
avformat_close_input(&video_fmt_ctx);
return 1;
} video_codec_init = true;
} }
} // 解码视频
if (video_codec_init && suitable_dec_ctx)
{
decode_video_packet(video_fmt_ctx, suitable_dec_ctx, video_stream_index);
} // 关闭文件
avformat_close_input(&video_fmt_ctx); return 0;
} int _tmain(int argc, _TCHAR* argv[])
{
// 注册库中所有可能有用的文件格式和编码器
av_register_all();
open_input_file("C:\\Users\\xukaijun.HIK\\Desktop\\hikvison.mp4"); #ifdef FILE_OUT
file_debugout.close();
#endif return 0;
}

【学习ffmpeg】打开视频文件,帧分析,并bmp保存关键帧的更多相关文章

  1. Java使用FFmpeg处理视频文件的方法教程

    这篇文章主要给大家介绍了关于Java使用FFmpeg处理视频文件的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧 前言 本文主要 ...

  2. Java使用FFmpeg处理视频文件指南

    Java使用FFmpeg处理视频文件指南 本文主要讲述如何使用Java + FFmpeg实现对视频文件的信息提取.码率压缩.分辨率转换等功能: 之前在网上浏览了一大圈Java使用FFmpeg处理音视频 ...

  3. python实现调用摄像头或打开视频文件

    目录: (一)调用摄像头或打开视频文件代码实现 (二)说明和补充 (一)调用摄像头或打开视频文件代码实现 1 # -*- coding=GBK -*- 2 import cv2 as cv 3 4 5 ...

  4. opencv打开视频文件出错

    使用C#调用mingw的so文件,在C++端使用opencv打开视频.这样的项目完成过了一个,第二次做的时候,发现opencv打开视频文件出错. 首先怀疑是opencv的opencv_ffmpeg24 ...

  5. php ffmpeg截取视频第一帧保存为图片的方法

    php ffmpeg截取视频第一帧保存为图片的方法 <pre> $xiangmupath = $this->getxiangmupath(); $filename = 'chengs ...

  6. 实战FFmpeg--iOS平台使用FFmpeg将视频文件转换为YUV文件

    做播放器的开发这里面涉及的东西太多,我只能一步步往前走,慢慢深入.播放器播放视频采用的是渲染yuv文件.首先,要知道yuv文件是怎么转换得来的,其次,要知道怎么把视频文件保存为yuv文件.雷神的文章1 ...

  7. 使用ffmpeg合并视频文件的三种方法

    ffmpeg合并视频的方法有三种.国内大多数仅介绍了其中之一.于是觉得有必要翻译一下.其实在ffmpeg的 FAQ文档中有比较详细的说明. 使用concat协议进行视频文件的合并 这种方式的适用场景是 ...

  8. 使用FFmpeg处理视频文件:视频转码、剪切、合并、播放速调整

    安装 略. 转码 最简单命令如下: ffmpeg -i out.ogv -vcodec h264 out.mp4ffmpeg -i out.ogv -vcodec mpeg4 out.mp4ffmpe ...

  9. ffmpeg实现视频文件合并/截取预览视频/抽取音频/crop(裁剪)(ffmpeg4.2.2)

    一,ffmpeg的安装 请参见: https://www.cnblogs.com/architectforest/p/12807683.html 说明:刘宏缔的架构森林是一个专注架构的博客,地址:ht ...

随机推荐

  1. Windows应用程序运行权限设置

    在Vista以后的windows版本中,有些时候需要提升编译后生成程序的权限,即希望让生成的程序以管理员身份运行.虽然在一般情况下,可以使用鼠标右键选择的方式来强行以管理员身份运行,但它并没有屏蔽普通 ...

  2. Docker入门与应用系列(七)Docker图形界面管理之DockerUI

    1.dockeruiDockerrUI是一个基于Docker API提供图形化页面简单的容器管理系统,支持容器管理.镜像管理.1.1 下载镜像 docker pull abh1nav/dockerui ...

  3. DB水平切换要点

    分区健选择 数据应该怎样拆分,依照什么纬度来拆分 节点路由 应用程序写死/客户端(TDDL,cobar-client)/中间层(cobar-server) 固定分配/动态分配/混合 分片数据均衡 某些 ...

  4. Entity Frameword 查询 sql func linq 对比

    Entity Framework是个好东西,虽然没有Hibernate功能强大,但使用更简便.今天整理一下常见SQL如何用EF来表达,Func形式和Linq形式都会列出来(本人更多在用Func形式,l ...

  5. shiro权限笔记

    shiro框架运行流程 认证:系统提供的用于识别用户身份的功能,通常就是登录功能.----让系统知道你是谁??授权:系统提供的为用户分配访问系统某些功能的能力.----让系统知道你能做什么?? 官网: ...

  6. net.mvc中并发限制

    浏览器限制 会话限制 线程限制 这篇文章讲的很详细: https://weblogs.asp.net/imranbaloch/concurrent-requests-in-asp-net-mvc 明白 ...

  7. 处理界面上使用两个jq的报错

    转载:http://www.365mini.com/page/jquery_noconflict.htm <script src="jquery-1.9.1.js">& ...

  8. 我的Android进阶之旅------>解决Error: specified for property 'mergedManifest' does not exist.

    错误描述 刚运行从Github上面下载而来的代码时,爆了如下所示的bug,错误描述如下所示: Error:A problem was found with the configuration of t ...

  9. KMP算法最浅显理解——一看就明确

    说明 KMP算法看懂了认为特别简单,思路非常easy,看不懂之前.查各种资料,看的稀里糊涂.即使网上最简单的解释,依旧看的稀里糊涂. 我花了半天时间,争取用最短的篇幅大致搞明确这玩意究竟是啥. 这里不 ...

  10. 对数值数据的格式化处理(保留小数点后N位)

    项目中有时会遇到对数值部分进行保留操作,列如保留小数点后2位,所有的数据都按这种格式处理, //保留小数点后2位,都按这种格式处理,没有补0 DecimalFormat df = new Decima ...