整个项目在https://github.com/ximikang/ffmpegThumbnail发布

生成缩略图的步骤

  1. 使用ffmpeg解码视频
  2. 帧格式转换
  3. 根据缩略图的数量从视频流中取帧
  4. 使用opencv建立画布并生成缩略图

ffmpeg解码视频

根据缩略图的数量从视频流中取帧

  1. 获取图片之间的时间间隔
 // Read media file and read the header information from container formatAVFormatContext* pFormatContext = avformat_alloc_context();if (!pFormatContext) {logging("ERROR could not allocate memory for format context");return -1;}if (avformat_open_input(&pFormatContext, inputFilePath.string().c_str(), NULL, NULL) != 0) {logging("ERROR could not open media file");}logging("format %s, duration %lld us, bit_rate %lld", pFormatContext->iformat->name, pFormatContext->duration, pFormatContext->bit_rate);cout << "视频时常:" << pFormatContext->duration / 1000.0 / 1000.0 << "s" << endl;int64_t video_duration = pFormatContext->duration;int sum_count = rowNums * colNums;//跳转的间隔 msint64_t time_step = video_duration / sum_count / 1000;
  1. 设置跳转时间获取不同的视频Packet
 for (int i = 0; i < sum_count ; ++i) {cv::Mat tempImage;// 每次读取相同时间间隔的图像并存入vImage中while (av_read_frame(pFormatContext, pPacket) >= 0) {if (pPacket->stream_index == video_stream_index) {response = decode_packet_2mat(pPacket, pCodecContext, pFrame, tempImage);// 返回}if (response == 0)// 成功读取一帧break;if (response < 0)continue;}vImage.push_back(tempImage);// 跳转视频av_seek_frame(pFormatContext, -1, ((double)time_step / (double)1000)* AV_TIME_BASE*(double)(i+1) + (double)pFormatContext->start_time, AVSEEK_FLAG_BACKWARD);}

3.获取Frame
在固定的时间点可能无法获取从当前时间点的Packet获取对应的Frame,所以需要对获取的Packet进行判断,如果没有获取到对应的Frame应该继续获取下一Packet直到获取到对应的Frame为止。

static int decode_packet_2mat(AVPacket* pPacket, AVCodecContext* pCodecContext, AVFrame* pFrame, cv::Mat& image) {int response = avcodec_send_packet(pCodecContext, pPacket);if (response < 0) {logging("Error while sending a packet to the decoder");return response;}while (response >= 0) {// return decoded out data from a decoderresponse = avcodec_receive_frame(pCodecContext, pFrame);if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {logging("averror averror_eof");break;}else if (response < 0) {logging("Error while receiving frame");return response;}if (response >= 0) {// 获取到Frameimage = frame2Mat(pFrame, pCodecContext->pix_fmt);} return 0;}
}

帧格式转换

由于从视频流获取的帧是YUV格式的Frame格式,后面使用opencv进行操作所以进行格式转换。

先使用ffmpeg中的SwsContext将从视频中抽取到的帧从YUV转换到BGR格式,再从BGRFrame中的内存中获取原始数据,并转换到opencv的Mat类型。

cv::Mat frame2Mat(AVFrame* pFrame, AVPixelFormat pPixFormat)
{// image initAVFrame* pRGBFrame = av_frame_alloc();uint8_t* out_buffer = new uint8_t[avpicture_get_size(AV_PIX_FMT_BGR24, pFrame->width, pFrame->height)];avpicture_fill((AVPicture*)pRGBFrame, out_buffer, AV_PIX_FMT_BGR24, pFrame->width, pFrame->height);SwsContext* rgbSwsContext = sws_getContext(pFrame->width, pFrame->height, pPixFormat, pFrame->width, pFrame->height, AV_PIX_FMT_BGR24,SWS_BICUBIC, NULL, NULL, NULL);if (!rgbSwsContext) {logging("Error could not create frame to rgbframe sws context");exit(-1);}if (sws_scale(rgbSwsContext, pFrame->data, pFrame->linesize, 0, pFrame->height, pRGBFrame->data, pRGBFrame->linesize) < 0) {logging("Error could not sws to rgb frame");exit(-1);}cv::Mat mRGB(cv::Size(pFrame->width, pFrame->height), CV_8UC3);mRGB.data = (uchar*)pRGBFrame->data[0];//注意不能写为:(uchar*)pFrameBGR->dataav_free(pRGBFrame);sws_freeContext(rgbSwsContext);return mRGB;
}

使用opencv建立画布并生成缩略图

通过画布需要的大小参数,画出白色画布,再对画布进行填充。

cv::Mat makeThumbnail(vector<cv::Mat> vImage, const unsigned int rowNums, const unsigned int colNums)
{// 判断图片时候满足条件if (vImage.size() != rowNums * colNums) {logging("Error image size not equal input size");logging("vImage length: %d, rowNums: %d, col number: %d", vImage.size(), rowNums, colNums);exit(-1);}int interval = 100;int height = vImage[0].size().height * rowNums + interval * (rowNums + 1);int width = vImage[0].size().width * colNums + interval * (colNums + 1);logging("thumbnail size: %d * %d", height, width);cv::Mat thumbnail(cv::Size(width, height), CV_8UC3);thumbnail.setTo(255);// 进行填充for (int i = 0; i < rowNums; ++i) {for (int j = 0; j < colNums; ++j) {int no = i * rowNums + j;int widthOffset = (vImage[0].size().width + interval) * j + interval;int heightOffset = (vImage[0].size().height + interval) * i + interval;vImage[no].copyTo(thumbnail(cv::Rect(widthOffset, heightOffset, vImage[0].size().width, vImage[0].size().height)));}}return thumbnail;
}

最后的效果

ffmpeg生成缩略图相关推荐

  1. 利用FFmpeg生成视频缩略图 2.1.8

    1.下载FFmpeg文件包,解压包里的\bin\下的文件解压到 D:\ffmpeg\ 目录下.下载地址 http://ffmpeg.zeranoe.com/builds/win32/static/D: ...

  2. php 图片生成视频,PHP基于ffmpeg实现转换视频,截图及生成缩略图的方法

    本文实例讲述了PHP基于ffmpeg实现转换视频,截图及生成缩略图的方法.分享给大家供大家参考,具体如下: 这里把ffmpeg 和  生成缩略图整合了一下: include("ImageRe ...

  3. FFmpeg截图以及生成缩略图

    介绍:FFmpeg是用于录制.转换和流化音频和视频的完整解决方案,一套领先的音/视频编解码类库.官方正式版ffmpeg不支持rmvb和rm格式. 不过有很多解决方法 FFmpeg的官方网址是 http ...

  4. 极速生成缩略图,Serverless 支撑赛事转播锁定冬奥亮点

    作者:西流.筱姜 "北京冬奥会在开赛的第四天便成为了历史上收视最高的一届冬奥会,其转播内容总生产量将达 6000 小时,超过平昌冬奥会的 5400 小时.关注北京冬奥会的人群比往届都多,北京 ...

  5. fastdfs上传文件资料(PDF,视频,图片,FileCaseUtil,FileUploadUtil)并生成缩略图

    javacv里面有类型转换器的使用,对视频图片的处理工具等等 一.UML图 二.代码 pom依赖 <!-- fastdfs--><dependency><groupId& ...

  6. php 图片生成封面,ffmpeg生成视频封面图

    ffmpeg 是一个视频处理软件 php-ffmpeg 是一个让 php 可以操作 ffmpeg 的 php插件,封装好了各种操作视频的名命令.直接调用对应的方法即可. 使用过程很曲折也很简单 曲折在 ...

  7. C#上传视频生成缩略图

    注意:需要FFmpeg软件,用到ffmpeg.exe:FFmpeg是一个开源免费跨平台的视频和音频流方案,属于自由软件,采用LGPL或GPL许可证(依据你选择的组件).它提供了录制.转换以及流化音视频 ...

  8. C# webform上传图片并生成缩略图

    其实里面写的很乱,包括修改文件名什么的都没有仔细去写,主要是想记录下缩略图生成的几种方式 ,大家明白就好! 1 void UpImgs() 2 { 3 if (FileUpload1.HasFile) ...

  9. C#编写的生成缩略图程序

    if(fileupload.PostedFile!=null)      {           //addto为要添加的属性,aboutfile为文件说明       string nam = fi ...

  10. 使用FileUpload控件上传图片并自动生成缩略图、自动生成带文字和图片的水印图

    本文借助vs2005中自带的FileUpload控件实现图片文件的上传并生成缩略图. 实现过程:选择图片上传成功后,取得已经存在服务器的文件生成缩略图,并且判断是否是图片类型的文件,这个的判断可以在程 ...

最新文章

  1. mySQL教程 第10章 事务和锁
  2. zookeeper实现分布式锁的原理及具体使用案例
  3. 科普: 中间件底层实现的分布式协议之Raft
  4. 基于netty的微服务架构
  5. 构成网络的多台计算机其硬件配置必须相同吗,计算机省一级2014年-2016年章节试题(答案).docx...
  6. SAP License:作业类型作为成本对象
  7. php url参数用–,php获取URL各部分参数
  8. 软考程序员2017下半年真题含答案解析
  9. ODBC、OLE DB、 ADO的区别
  10. 硬盘IDE模式与AHCI模式的区别
  11. ubuntu 安装音乐播放器
  12. SAP中由生产版本有误导致的生产报工时提示“错误确定成本核算”问题实例
  13. 掌握茼蒿施肥方式,想不高产都难。
  14. 克里奥服务器装系统,克里奥神模拟器
  15. 【Note】二十四节气英文表达(solar term)
  16. 在Unity中使用FFmpeg将视频绿色背景处理为透明背景
  17. Result统一响应数据
  18. 开一个水果店如何进货呢,水果店进货多少
  19. 【人工智能AI2.0】国产开源 ChatGPT: ChatGLM-6B 搭建属于你的永远免费的本地 ChatGPT
  20. Android 圆形停止按钮,跑步APP停止动画

热门文章

  1. python设置窗口位置_python中tkinter窗口位置
  2. 天合光能为澳大利亚太阳能农场供应双玻组件
  3. 微信小程序入门(一):小程序账号注册 + 微信开发者工具安装
  4. android 倒水动画,Android 模拟圆形水杯倒水的效果
  5. 如何使用商品历史价格查询网站
  6. 新世达380修改服务器密码,新时达AS380利用小键盘调试说明
  7. git 设置代理的方法
  8. [渝粤教育] 西南科技大学 信息组织与检索 在线考试复习资料2021版
  9. MSP430F149小系统开发板实现RS232串口通信
  10. 2018之后的Unity3d制作AR教程