最近由于项目需求,要在界面中内嵌一个简单的视频播放器,能够打开视频,逐帧播放,进度条拖动等功能。

因此,首先尝试使用opencv编写。原因:1、便于后续处理;2、opencv提高的接口较完善。很快就动手写出了一个;基于OpenCV的视频播放器。

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <time.h>
#include <Windows.h>
#include <iostream>
#include <stdlib.h>using namespace std;
using namespace cv;int g_slider_position = 0;
int n_position = 0;
VideoCapture pCap;  // 回调函数
void onTrackbarSlide( int pos, void * )
{if (pos != n_position){pCap.set(CV_CAP_PROP_POS_FRAMES, pos); n_position = pos;g_slider_position = pos;}
}
int main( int argc, char *argv[] )
{   Mat pFrame; int nFrames = 0;double fps = 0; // 帧率  int spf = 0;    // 1/fps//char filename[200] = "768x576.avi";if (argc == 2)  {  sprintf(filename, "%s", argv[1]);}namedWindow("VideoPlayer", 0);    // 可改变窗口大小pCap.open(filename);if (!pCap.isOpened())  {  printf("Count not open video file/n");  exit(1);  }  // 获取视频帧率  fps = pCap.get(CV_CAP_PROP_FPS);  spf = (int)(1000/fps);  printf("fps = %.f\nspf = %d\n", fps, spf);  // 获取视频总帧数 nFrames = (int)(pCap.get(CV_CAP_PROP_FRAME_COUNT));printf("Total frames = %d\n", nFrames);// 如果由于编码方式问题获取不到帧数,则不创建滚动条  if (nFrames != 0)  {  createTrackbar("Position", "VideoPlayer", &g_slider_position,   nFrames, onTrackbarSlide);  }  while (1)  {pCap >> pFrame;if (pFrame.empty())        // 播放结束退出  {  break;  }  imshow("VideoPlayer", pFrame);  // 播放的过程中移动滚动条printf("current pos %d\n", n_position);n_position++;g_slider_position = n_position;setTrackbarPos("Position", "VideoPlayer", g_slider_position);char c = waitKey((int)(spf)); // 按原来的帧率播放视频  if (c == 27)        // 按下Esc退出播放  {  break;  }  }  pCap.release();pFrame.release();destroyWindow("VideoPlayer");destroyWindow("VideoPlayerControl");return 0;
}

在播放部分avi格式的视频时,拖动进度条会出现问题帧定位不准的问题,可能是定位到了关键帧。

google了一番,大家认为是从opencv2.x开始,开始使用ffmpeg。ffmpeg是一个开源的视频库,能够打开视频,转码等等。KMPlayer等等播放器都使用过这个库,只是因为违反了LGPL,被ffmpeg社区拉黑了。

下面给出的是X:\OpenCV\OpenCV231\modules\highgui\src\cap_ffmpeg_impl.hpp

bool CvCapture_FFMPEG::open( const char* _filename )
{unsigned i;bool valid = false;close();/* register all codecs, demux and protocols */av_register_all();#ifndef _DEBUG// av_log_level = AV_LOG_QUIET;
#endifint err = av_open_input_file(&ic, _filename, NULL, 0, NULL);if (err < 0) {CV_WARN("Error opening file");goto exit_func;}err = av_find_stream_info(ic);if (err < 0) {CV_WARN("Could not find codec parameters");goto exit_func;}for(i = 0; i < ic->nb_streams; i++) {
#if LIBAVFORMAT_BUILD > 4628AVCodecContext *enc = ic->streams[i]->codec;
#elseAVCodecContext *enc = &ic->streams[i]->codec;
#endifavcodec_thread_init(enc, get_number_of_cpus());#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 4, 0)#define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO#endifif( AVMEDIA_TYPE_VIDEO == enc->codec_type && video_stream < 0) {AVCodec *codec = avcodec_find_decoder(enc->codec_id);if (!codec ||avcodec_open(enc, codec) < 0)goto exit_func;video_stream = i;video_st = ic->streams[i];picture = avcodec_alloc_frame();rgb_picture.data[0] = (uint8_t*)malloc(avpicture_get_size( PIX_FMT_BGR24,enc->width, enc->height ));avpicture_fill( (AVPicture*)&rgb_picture, rgb_picture.data[0],PIX_FMT_BGR24, enc->width, enc->height );frame.width = enc->width;frame.height = enc->height;frame.cn = 3;frame.step = rgb_picture.linesize[0];frame.data = rgb_picture.data[0];break;}}if(video_stream >= 0) valid = true;// perform check if source is seekable via ffmpeg's seek function av_seek_frame(...)err = av_seek_frame(ic, video_stream, 10, 0);if (err < 0){filename=(char*)malloc(strlen(_filename)+1);strcpy(filename, _filename);// reopen videofile to 'seek' back to first framereopen();}else{// seek seems to work, so we don't need the filename,// but we still need to seek back to filestartfilename=NULL;int64_t ts    = video_st->first_dts;int     flags = AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD;av_seek_frame(ic, video_stream, ts, flags);}
exit_func:if( !valid )close();return valid;
}
err = av_seek_frame(ic, video_stream, 10, 0);

是大家认为opencv只能定位关键帧的原因所在。因此,大家推荐的做法是将0改成AVSEEK_FLAG_ANY,然后重新编译opencv。

第二个问题是,opencv能够打开并播放mp4,ts等格式的视频文件,但是不能提供帧定位。只有拖动进度条重新定位,视频就会从头开始播放。面对这个问题甚是苦恼。

既然opencv使用的是ffmpeg,那么我可以直接用ffmpeg的库进行视频文件的操作。因此从www.ffmpeg.org下载最新的static、shared和dev文件,解压出dev和shared,将shared中的bin文件夹拷贝到dev中。(我只是为了用起来方便,请原谅我的轻度强迫症)

我把dev放在了c盘根目录下,命名为ffmpeg。将c:\ffmpeg\bin加入到环境变量的path。然后注销一下。

在工程中加入ffmpeg\include和ffmpeg\lib,并将ffmpeg\lib中的*.lib加入到链接库中。在代码中加入对应的头文件就可以了。

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <time.h>
#include <Windows.h>
#include <iostream>
#include <stdlib.h>
#include <math.h>#ifdef __cplusplus
extern "C" {
#endif
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#ifdef __cplusplus
}
#endif#define N 3#define INBUF_SIZE 4096
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096using namespace std;
using namespace cv;int main( int argc, char *argv[] )
{AVFormatContext *pFormatCtx;int codec_id = CODEC_ID_MPEG4;char filename[] = "Locust_Inspired_Jumping_Robot.flv";// Open video fileAVCodec *codec;AVCodecContext *c= NULL;int i, out_size, x, y, outbuf_size;FILE *f;AVFrame *picture;uint8_t *outbuf;int had_output = 0;av_register_all();printf("Encode video file %s\n", filename);codec = avcodec_find_encoder(CODEC_ID_H264);if (!codec) {fprintf(stderr, "codec not found\n");exit(1);}c = avcodec_alloc_context3(codec);picture = avcodec_alloc_frame();/* put sample parameters */c->bit_rate = 40000;//c->bit_rate_tolerance=30;/* resolution must be a multiple of two */c->width = 352;c->height = 288;/* frames per second */c->time_base.den=  25;c->time_base.num= 1;c->gop_size = 10; /* emit one intra frame every ten frames */c->max_b_frames=1;c->pix_fmt = PIX_FMT_YUV420P;if(codec_id == CODEC_ID_H264)av_opt_set(c->priv_data, "preset", "slow", 0);/* open it */if (avcodec_open2(c, codec, NULL) < 0) {fprintf(stderr, "could not open codec\n");exit(1);}f = fopen(filename, "wb");if (!f) {fprintf(stderr, "could not open %s\n", filename);exit(1);}/* alloc image and output buffer */outbuf_size = 100000 + 12*c->width*c->height;outbuf = (uint8_t*)malloc(outbuf_size); //CHANGED/* the image can be allocated by any means and av_image_alloc() is* just the most convenient way if av_malloc() is to be used */av_image_alloc(picture->data, picture->linesize, c->width, c->height, c->pix_fmt, 1);/* encode 1 second of video */for(i = 0; i < 25; i++) {fflush(stdout);/* prepare a dummy image *//* Y */for(y = 0; y < c->height; y++) {for(x = 0; x < c->width; x++) {picture->data[0][y * picture->linesize[0] + x] = x + y + i * 3;}}/* Cb and Cr */for(y = 0; y < c->height / 2; y++) {for(x = 0; x < c->width / 2; x++) {picture->data[1][y * picture->linesize[1] + x] = 128 + y + i * 2;picture->data[2][y * picture->linesize[2] + x] = 64 + x + i * 5;}}/* encode the image */out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture);had_output |= out_size;printf("encoding frame %3d (size=%5d)\n", i, out_size);fwrite(outbuf, 1, out_size, f);}/* get the delayed frames */for(; out_size || !had_output; i++) {fflush(stdout);out_size = avcodec_encode_video(c, outbuf, outbuf_size, NULL);had_output |= out_size;printf("write frame %3d (size=%5d)\n", i, out_size);fwrite(outbuf, 1, out_size, f);}/* add sequence end code to have a real mpeg file */outbuf[0] = 0x00;outbuf[1] = 0x00;outbuf[2] = 0x01;outbuf[3] = 0xb7;fwrite(outbuf, 1, 4, f);fclose(f);free(outbuf);avcodec_close(c);av_free(c);av_free(picture->data[0]);av_free(picture);printf("\n");return 0;
}

值得注意的是,在包含ffmpeg的头文件时一定要定义在extern “C”中,同时这些头文件必须在#include <math.h>之后。

然后编译一下,就可以运行了。目前做到这一步了,现挖个坑,等把如何用ffmpeg读取编码输出视频的问题解决了再继续写。

未完待续

使用opencv开发视频播放器一相关推荐

  1. 基于FFmpeg开发视频播放器, 基本流程(一)

    刚开始学习FFmpeg,用几篇文章记录下,使用ffmpeg开发一个简单的视频播放器,大概的过程.这里只讨论核心代码,如解封装,音频的解码播放,视频的解码播放,音视频同步,不涉及UI布局. 基于FFmp ...

  2. typescript 从零开发视频播放器

    typescript 从零开发视频播放器 前言 项目架构设计 技术栈 双端支持 元素的显示和隐藏说明 组件化开发 组件之间的通讯 拖拽行为 初始化模板 video 标签组件 控制器的显示和隐藏 显示时 ...

  3. python开发视频播放器_python视频播放器

    广告关闭 100GB直播流量包仅需9.9元,10TB点播流量包仅需999元,参与活动还赠移动直播SDK,短视频SDK,小程序插件等,大促100%中奖率 最近研究了python的两个gui包,tkint ...

  4. python开发视频播放器_Python应用03 使用PyQT制作视频播放器实例

    最近研究了Python的两个GUI包,Tkinter和PyQT.这两个GUI包的底层分别是Tcl/Tk和QT.相比之下,我觉得PyQT使用起来更加方便,功能也相对丰富.这一篇用PyQT实现一个视频播放 ...

  5. 音视频开发第一课-使用C语言开发视频播放器 650元IT外包开发全程记录

    界面设计 目标效果: 创建MFC对话框项目,或者直接使用项目模板 主要选择64位平台. 拖放控件 设置播放器区域的背景 把资源bg.bmp拷贝到项目目录的res目录下. 把bg.bmp添加当项目的资源 ...

  6. Opencv 简单视频播放器

    最近看了一下[1]_2011_OpenCV 2 Computer Vision Application Programming Cookbook.pdf,写了一个利用Opencv库实现的简单视频播放器 ...

  7. 只有你项目不到,Electron也可以开发视频播放器

    一.桌面版视频播放器 今天又发现一款强大的开源软件,electron 开发的一个可以播放国内主流视频(腾讯.爱奇艺.优酷.芒果.乐视)的播放器.而且播放视频可直接跳过广告.好的开源项目第一时间分享给大 ...

  8. 只有你想不到,Electron也可以开发视频播放器

    ## 一.桌面版视频播放器 今天又发现一款强大的开源软件,electron 开发的一个可以播放国内主流视频(腾讯.爱奇艺.优酷.芒果.乐视)的播放器.而且播放视频可直接跳过广告.好的开源项目第一时间分 ...

  9. python开发视频播放器_Python使用PyQT制作视频播放器

    最近研究了Python的两个GUI包,Tkinter和PyQT.这两个GUI包的底层分别是Tcl/Tk和QT.相比之下,我觉得PyQT使用起来更加方便,功能也相对丰富.这一篇用PyQT实现一个视频播放 ...

最新文章

  1. 悬浮按钮app_分享一款网页转App的神器,绝对值得一用
  2. sybase asa转mysql_为Sybase ASA创建外部存储过程(Java示例)
  3. hdu1879 继续畅通工程 最小生成树
  4. SpringMVC-web.xml头代码
  5. Codeforces Round #419 (Div. 2)
  6. BZOJ5292 洛谷4457 LOJ2513:[BJOI2018]治疗之雨——题解
  7. delphi gui编辑工具源码_Python 快速构建一个简单的 GUI 应用
  8. python数据可视化的特点_6 种 Python 数据可视化工具
  9. 4x4矩阵键盘工作原理及扫描程序_基于复杂可编程逻辑器件实现键盘接口电路的设计...
  10. ndnsim r语言 ubuntu_Ubuntu14.04下配置ndnSIM-nom-rapid-car2car
  11. BZOJ 3207: 花神的嘲讽计划Ⅰ
  12. 吴恩达机器学习编程作业
  13. android重复点击屏幕,手机不ROOT.推荐一款android能用的屏幕连点器,类似按键精灵!...
  14. Word:表格中绘制斜线表头
  15. 自己动手写iPhone wap浏览器之BSD Socket引擎篇
  16. 数据库原理及应用教程(第4版|微课版)陈志泊-第三章习题
  17. 2008 mysql 本地安全_apache在windows2003或win2008环境中的安全设置
  18. android studio 56 下载网络歌曲 代码
  19. 自创小说《彩虹雨》 连载(四)
  20. B - Integral Array

热门文章

  1. 注册表单是要左对齐还是右对齐
  2. Focusky教程 | 如何解决双击工程文件后提示文件不存在的问题?
  3. vba 转换多种格式日期
  4. 数据分析案例-股票数据分析
  5. 使用vscode ssh连接linux虚拟机
  6. mybatis能否预防SQL注入
  7. 解决windows电脑系统图片不显示缩略图预览的2种办法
  8. CTex的安装与使用【待续】
  9. XMind 8过滤功能效果展示
  10. 计算机软件资格水平考试办公室,信息系统项目管理师考试大纲-全国计算机技术与软件专业技术资格(水平)考试办公室.pdf...