ffmpeg是基于最新版本,在官网下载http://ffmpeg.zeranoe.com/builds/。编译时VS2010配置相关头文件及库的路径即可。opencv的搭建参考上一个博客。

首先简单介绍以下视频文件的相关知识。我们平时看到的视频文件有许多格式,比如 avi, mkv, rmvb, mov, mp4等等,这些被称为容器Container), 不同的容器格式规定了其中音视频数据的组织方式(也包括其他数据,比如字幕等)。容器中一般会封装有视频和音频轨,也称为视频流(stream)和音频 流,播放视频文件的第一步就是根据视频文件的格式,解析(demux)出其中封装的视频流、音频流以及字幕(如果有的话),解析的数据读到包 (packet)中,每个包里保存的是视频帧(frame)或音频帧,然后分别对视频帧和音频帧调用相应的解码器(decoder)进行解码,比如使用 H.264编码的视频和MP3编码的音频,会相应的调用H.264解码器和MP3解码器,解码之后得到的就是原始的图像(YUV or RGB)和声音(PCM)数据,然后根据同步好的时间将图像显示到屏幕上,将声音输出到声卡,最终就是我们看到的视频。

好好看下下面的文章,很不错的。转载一部分:

有人会疑惑,为什么解码后的pFrame不直接用于显示,而是调用swscale()转换之后进行显示?

如果不进行转换,而是直接调用SDL进行显示的话,会发现显示出来的图像是混乱的。关键问题在于解码后的pFrame的linesize里存储的不是图像的宽度,而是比宽度大一些的一个值。其原因目前还没有仔细调查(大概是出于性能的考虑)。例如分辨率为480x272的图像,解码后的视频的linesize[0]为512,而不是480。以第1行亮度像素(pFrame->data[0])为例,从0-480存储的是亮度数据,而从480-512则存储的是无效的数据。因此需要使用swscale()进行转换。转换后去除了无效数据,linesize[0]变为480。就可以正常显示了。

100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)

下面直接看代码吧!

/*File : playvideo.cpp*Auth : sjin*Date : 20141029*Mail : 413977243@qq.com*/#include <stdio.h>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#ifdef __cplusplus
extern "C" {
#endif#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "avcodec.lib")
#pragma comment (lib, "avdevice.lib")
#pragma comment (lib, "avfilter.lib")
#pragma comment (lib, "avformat.lib")
#pragma comment (lib, "avutil.lib")
#pragma comment (lib, "swresample.lib")
#pragma comment (lib, "swscale.lib")#ifdef __cplusplus
}
#endifstatic void CopyDate(AVFrame *pFrame,int width,int height,int time)
{if(time <=0 ) time = 1;int      nChannels;int       stepWidth;uchar  *  pData;  cv::Mat frameImage(cv::Size(width, height), CV_8UC3, cv::Scalar(0));stepWidth = frameImage.step;nChannels = frameImage.channels();pData = frameImage.data;for(int i = 0; i < height; i++){for(int j = 0; j < width; j++){pData[i * stepWidth + j * nChannels + 0] = pFrame->data[0][i * pFrame->linesize[0] + j * nChannels + 2];pData[i * stepWidth + j * nChannels + 1] = pFrame->data[0][i * pFrame->linesize[0] + j * nChannels + 1];pData[i * stepWidth + j * nChannels + 2] = pFrame->data[0][i * pFrame->linesize[0] + j * nChannels + 0];}}cv::namedWindow("Video", CV_WINDOW_AUTOSIZE);cv::imshow("Video", frameImage);cv::waitKey(time);
}static void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame)
{FILE *pFile;char szFilename[32];int  y;// Open filesprintf(szFilename, "frame%d.ppm", iFrame);pFile=fopen(szFilename, "wb");if(pFile==NULL)return;// Write headerfprintf(pFile, "P6\n%d %d\n255\n", width, height);// Write pixel datafor(y=0; y<height; y++)fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);// Close filefclose(pFile);
}int main(int argc, char * argv[])
{AVFormatContext *pFormatCtx = NULL;int             i, videoStream;AVCodecContext  *pCodecCtx;AVCodec         *pCodec;AVFrame         *pFrame; AVFrame         *pFrameRGB;AVPacket        packet;int             frameFinished;int             numBytes;uint8_t         *buffer;/*注册了所有的文件格式和编解码器的库*/av_register_all();// 打开视频文件/*这个函数读取文件的头部并且把信息保存到我们给的AVFormatContext结构体中。*第二个参数 要打开的文件路径*/if(avformat_open_input(&pFormatCtx, "test.264", NULL, NULL)!=0){return -1; // Couldn't open file}// 读取数据包获取流媒体文件的信息if(avformat_find_stream_info(pFormatCtx,NULL)<0){return -1; // Couldn't find stream information}//打印输入或输出格式的详细信息,如时间、比特率,溪流,容器,程序,元数据,基础数据,编解码器和时间。av_dump_format(pFormatCtx, 0, "test.264", false);//查找第一个视频流videoStream=-1;for(i = 0; i < pFormatCtx->nb_streams; i++){if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){videoStream = i;break;}}if(videoStream == -1){//未发现视频流退出return -1; }//获得视频编解码器的上下文pCodecCtx = pFormatCtx->streams[videoStream]->codec;// 找到视频解码器pCodec = avcodec_find_decoder(pCodecCtx->codec_id);if(pCodec == NULL){//未发现视频编码器return -1; }// 打开视频解码器if(avcodec_open2(pCodecCtx, pCodec, 0) < 0){return -1; //打开失败退出}/*有些人可能会从旧的指导中记得有两个关于这些代码其它部分:*添加CODEC_FLAG_TRUNCATED到 pCodecCtx->flags和添加一个hack来粗糙的修正帧率。*这两个修正已经不在存在于ffplay.c中。因此,我必需假设它们不再必 要。我们移除*了那些代码后还有一个需要指出的不同点:pCodecCtx->time_base现在已经保存了帧率*的信息。time_base是一 个结构体,它里面有一个分子和分母 (AVRational)。我们使*用分数的方式来表示帧率是因为很多编解码器使用非整数的帧率(例如NTSC使用29.97fps)。**if(pCodecCtx->time_base.num > 1000 && pCodecCtx->time_base.den == 1){*  pCodecCtx->time_base.den = 1000;*}*/// 分配保存视频帧的空间pFrame = avcodec_alloc_frame();// 分配一个AVFrame结构/*准备输出保存24位RGB色的PPM文件,我们必需把帧的格式从原来的转换为RGB。FFMPEG将为我们做这些转换*/pFrameRGB = avcodec_alloc_frame();if(pFrameRGB==NULL){return -1;}/*即使我们申请了一帧的内存,当转换的时候,我们仍然需要一个地方来放置原始的数据。*我们使用avpicture_get_size来获得我们需要的大小,然后手工申请内存空间:*/numBytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);buffer = (uint8_t *)av_malloc( numBytes*sizeof(uint8_t));// 基于指定的图像参数,设置图片字段所提供的图像数据缓冲区。avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,pCodecCtx->width, pCodecCtx->height);/*读取数据帧*通过读取包来读取整个视频流,然后把它解码成帧,最好后转换格式并且保存。*/i=0;long prepts = 0;while(av_read_frame(pFormatCtx, &packet) >= 0){if(packet.stream_index == videoStream){/*判断读取的是否为需要的视频帧数据*/// 解码视频帧avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);if(frameFinished){static struct SwsContext *img_convert_ctx;#if 0//就的转换模式已经废除img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, (AVPicture*)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
#endifif(img_convert_ctx == NULL) {int w = pCodecCtx->width;int h = pCodecCtx->height;//分配和返回一个SwsContext。您需要执行缩放/转换操作使用sws_scale()。img_convert_ctx = sws_getContext(w, h, pCodecCtx->pix_fmt, w, h, PIX_FMT_RGB24, SWS_BICUBIC,NULL, NULL, NULL);if(img_convert_ctx == NULL) {fprintf(stderr, "Cannot initialize the conversion context!\n");exit(1);}}转换图像格式,将解压出来的YUV420P的图像转换为BRG24的图像sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);//保存前五帧数据if(i++ <= 5){SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);}CopyDate(pFrameRGB, pCodecCtx->width, pCodecCtx->height,packet.pts-prepts);prepts = packet.pts;}}//释放空间av_free_packet(&packet);}//释放空间av_free(buffer);av_free(pFrameRGB);// 释放 YUV frameav_free(pFrame);//关闭解码器avcodec_close(pCodecCtx);//关闭视频文件avformat_close_input(&pFormatCtx);system("Pause");return 0;
}

运行如下图:

参考资料:
http://www.cnblogs.com/dyllove98/archive/2013/07/03/3170272.html
http://blog.csdn.net/hsp494980719/article/details/7986400

ffmpeg和opencv 播放视频文件并显示相关推荐

  1. ffmpeg和opencv 播放视频文件和显示器

    ffmpeg它是基于最新版本,在官网下载http://ffmpeg.zeranoe.com/builds/.编译时VS2010配置相关头文件及库的路径就可以.opencv的搭建參考上一个博客. 首先简 ...

  2. api c语言 播放视频,使用OpenCV播放视频文件(C/C++ API比较)

    OpenCV库很强大,不仅能够显示图片,还能解码显示各种格式的视频文件,而且提供的API接口也很多,包括C.C++.Python.下面比较一下分别使用C和C++播放一段视频文件的实现: C语言实现 $ ...

  3. Jrtplib发送视频文件 + FFMPEG解码+VFW播放视频 (回调方式)

    在上篇文章<Jrtplib收发H264文件 + FFMPEG解码+VFW播放视频> 里,我们采用的模式是发送端读取本地H264文件, 把完整的Naul(包含起始码) 逐个发送给接收端,接收 ...

  4. Qt+OpenCV打开视频文件并在窗口界面上显示

    Qt+OpenCV打开视频文件并在窗口界面上显示 1.新建一个Qt Widgets Application,工程配置文件(.pro文件)内容如下: #------------------------- ...

  5. OpenCV python 播放视频文件(.avi)

    OpenCV python 播放视频文件(.avi) 同文件夹存放文件[test.avi] import cv2def main():# 1.初始化读取视频对象cap = cv2.VideoCaptu ...

  6. FFmpeg播放视频文件流程

    一.FFmpeg解码播放主要流程,如图1-1所示: 使用播放一个媒体文件时,通常需要经过以下几个步骤: 图1-1    FFmpeg 播放视频文件流程 1.解封装(Demuxing):就是将输入的封装 ...

  7. 使用ffmpeg播放视频文件的过程

    本文中,红色字体部分是涉及到的ffmpeg部分,其他函数是视频显示部分或者内部封装函数(文中没有给出实现). 本文的主要目的,在于记录播放视频文件时用到的ffmpeg函数,及其用法. typedef ...

  8. opencv播放视频实时显示帧速(FPS),即是每秒帧数

    FPS是测量用于保存.显示动态视频的信息数量.通俗来讲就是指每秒变化的画面数. getTickCount: 它返回从操作系统启动到当前所经过的毫秒数,常常用来判断某个方法执行的时间,其函数原型是DWO ...

  9. java opencv 读取视频_java使用OpenCV从视频文件中获取帧

    本文实例为大家分享了java使用OpenCV从视频文件中获取帧的具体代码,供大家参考,具体内容如下 实现功能:使用Java获取mp4.mov.avi等视频文件中的图像帧,每秒获取一帧图像,并保存 环境 ...

最新文章

  1. sourcetree管理git
  2. java接口多实现super_Java 8:自动合成多个接口的默认方法
  3. eclipse中运行tomcat提示端口被占的4种解决方案
  4. Javascript 限制文本字节数
  5. 二分图的最大带权匹配
  6. C++函数返回多个变量
  7. 数据中心机房供电需求有哪些?供配电系统如何布置??
  8. 新建django项目
  9. 谷歌五笔输入法电脑版_“五笔输入法”打字速度更快,为什么却没啥人用?
  10. 如何在hexo中支持Mathjax
  11. XYGame-AI设计3-行为树-第1版本
  12. 跨域异常与nginx的underscores_in_headers on
  13. org.springframework.beans.factory.BeanDefin…
  14. Linux的NFS(net file systen)
  15. youtube下载视屏和字幕办法
  16. RHCA回忆录---RH236介绍
  17. net的曲线救国,学习路径 MVVM (一)
  18. dict.keys 键视图
  19. windowns11系统下安装Proteus_8.7教程
  20. 简阳市简阳中学2021年高考成绩查询,2021年简阳中学升学率怎么样?

热门文章

  1. Python矩阵计算类:计算矩阵加和、矩阵乘积、矩阵转置、矩阵行列式值、伴随矩阵和逆矩阵
  2. 基于android平台的出题软件---- 每日30题
  3. db2嵌套查询效率_提高DB2 查询性能的常用方法
  4. 余额宝 算法 php,把10000元放进余额宝,一年后支付宝会给多少利息?你计算过吗?...
  5. v380云存储怎么查看_v380的云存储
  6. Linux查看硬件信息以及驱动设备的命令
  7. Visual Micro for Microsoft Visual Studio 2022.08
  8. tensorflow报No OpKernel was registered to support Op ‘NcclAllReduce‘
  9. 单片机课程设计,基于AT89C51和LCD-12864的贪吃蛇游戏
  10. 中国县城生活实录:上楼因特网,下楼码长城