最简单的基于DirectShow的示例:视频播放器
=====================================================
最简单的基于DirectShow的示例文章列表:
最简单的基于DirectShow的示例:视频播放器图形界面版
最简单的基于DirectShow的示例:获取Filter信息
=====================================================
本文记录一个最简单的基于DirectShow的视频播放器。DirectShow是一个庞大的框架,可以在Windows下实现多种多样的视频处理需求。但是它的“庞大”也使得新手不太容易学习它的使用。本文的例子正是为解决这一问题而做的,它只包含了使用DirectShow播放一个视频文件所需要的最重要的函数。
流程图
最简单的使用DirectShow播放视频文件的流程如下图所示。
流程图中涉及到几个接口如下所示。
IGraphBuilder:继承自IFilterGraph,用于构建Filter Graph。相比于IFilterGraph来说IGraphBuilder提供了一些更加“智能”的方法,例如RenderFile()方法。
IMediaControl:提供和播放控制有关的一些接口。
IMediaEvent:用来处理Filter Graph发出的事件。
流程图中关键函数的作用如下所示。
CoInitialize() :初始化COM运行环境。
CoCreateInstance(…,pGraph) :用指定的类标识符创建一个Com对象。在该播放器中类标识符为“CLSID_FilterGraph”,用于创建IGraphBuilder。
pGraph->QueryInterface(…,pControl) :通过QueryInterface()查询某个组件是否支持某个特定的接口。在这里查询IMediaControl接口。
pGraph->QueryInterface(…,pEvent) :同上。在这里查询IMediaEvent接口。
pGraph->RenderFile("xxx.mkv"):为指定的文件智能的构建一个Filter Graph。
pControl->Run() :开始运行Filter Graph中的所有Filter。
pEvent->WaitForCompletion() :等待Filter Graph处理完所有数据。CoUninitialize():释放CoInitialize()初始化的COM运行环境。
注意上述几个函数是构建一个基于DirectShow的视频播放器所必须的函数,除了上述几个接口之外还经常用到以下几个接口:
IBasicVideo:提供和视频有关的一些接口。
IBasicAudio:提供和音频有关的一些接口。
IVideoWindow:提供和窗口有关的一些接口。
IMediaSeeking:提供和播放位置有关的一些接口。
源代码
/**
* 最简单的基于DirectShow的视频播放器
* Simplest DirectShow Player
*
* 雷霄骅 Lei Xiaohua
* leixiaohua1020@126.com
* 中国传媒大学/数字电视技术
* Communication University of China / Digital TV Technology
* http://blog.csdn.net/leixiaohua1020
*
* 本程序是一个最简单的基于DirectShow的播放器。
* 适合初学者学习DirectShow。
*
* This example is the simplest Player based on DirectShow.
* Suitable for the beginner of DirectShow.
*/
#include "stdafx.h"
#include <dshow.h>
#include <atlconv.h>
#define OUTPUT_INFO 1
//Show Filter in FilterGpragh
int show_filters_in_filtergraph(IGraphBuilder *pGraph){
printf("Filters in FilterGpragh=======\n");
USES_CONVERSION;
IEnumFilters *pFilterEnum=NULL;
if(FAILED(pGraph->EnumFilters(&pFilterEnum))){
pFilterEnum->Release();
return -1;
}
pFilterEnum->Reset();
IBaseFilter * filter = NULL;
ULONG fetchCount = 0;
//Pin Info
while (SUCCEEDED(pFilterEnum->Next(1, &filter, &fetchCount)) && fetchCount){
if (!filter){
continue;
}
FILTER_INFO FilterInfo;
if (FAILED(filter->QueryFilterInfo(&FilterInfo))){
continue;
}
printf("[%s]\n",W2A(FilterInfo.achName));
filter->Release();
}
pFilterEnum->Release();
printf("==============================\n");
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;
//Get some param--------------
HRESULT hr1;
IBasicVideo *pVideo=NULL;
IBasicAudio *pAudio=NULL;
IVideoWindow *pWindow=NULL;
IMediaSeeking *pSeeking=NULL;
// Init COM
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr)){
printf("Error - Can't init COM.");
return -1;
}
// Create FilterGraph
hr=CoCreateInstance(CLSID_FilterGraph, NULL,CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr)){
printf("Error - Can't create Filter Graph.");
return -1;
}
// Query Interface
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
// RenderFile
hr = pGraph->RenderFile(L"cuc_ieschool.mov", NULL);
if (FAILED(hr)){
printf("Error - Can't Render File.");
return -1;
}
#if OUTPUT_INFO
//Get some information----------
long video_w=0,video_h=0,video_bitrate=0,audio_volume=0;
long long duration_1=0,position_1=0;
REFTIME avgtimeperframe=0;
float framerate=0,duration_sec=0,progress=0,position_sec=0;
//Video
hr1=pGraph->QueryInterface(IID_IBasicVideo, (void **)&pVideo);
pVideo->get_VideoWidth(&video_w);
pVideo->get_VideoHeight(&video_h);
pVideo->get_AvgTimePerFrame(&avgtimeperframe);
framerate=1/avgtimeperframe;
//pVideo->get_BitRate(&video_bitrate);
//Audio
hr1=pGraph->QueryInterface(IID_IBasicAudio, (void **)&pAudio);
//Mute
//pAudio->put_Volume(-10000);
printf("Some Information:\n");
printf("Video Resolution:\t%dx%d\n",video_w,video_h);
printf("Video Framerate:\t%.3f\n",framerate);
//Window
hr1=pGraph->QueryInterface(IID_IVideoWindow, (void **)&pWindow);
pWindow->put_Caption(L"Simplest DirectShow Player");
//pWindow->put_Width(480);
//pWindow->put_Height(272);
//Seek
hr1=pGraph->QueryInterface(IID_IMediaSeeking, (void **)&pSeeking);
pSeeking->GetDuration(&duration_1);
//time unit:100ns=0.0000001s
duration_sec=(float)duration_1/10000000.0;
printf("Duration:\t%.2f s\n",duration_sec);
//pSeeking->SetPositions();
//PlayBack Rate
//pSeeking->SetRate(2.0);
//Show Filter in FilterGpagh
show_filters_in_filtergraph(pGraph);
//----------------------
#endif
printf("Progress Info\n");
printf("Position\tProgress\n");
if (SUCCEEDED(hr)){
// Run
hr = pControl->Run();
if (SUCCEEDED(hr)){
long evCode=0;
//pEvent->WaitForCompletion(INFINITE, &evCode);
while(evCode!=EC_COMPLETE){
//Info
#if OUTPUT_INFO
pSeeking->GetCurrentPosition(&position_1);
position_sec=(float)position_1/10000000.0;
progress=position_sec*100/duration_sec;
printf("%7.2fs\t%5.2f%%\n",position_sec,progress);
#endif
//1000ms
pEvent->WaitForCompletion(1000, &evCode);
}
}
}
// Release resource
pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();
return 0;
}
运行结果
程序运行后即可开始播放一个“cuc_ieschool.mov”文件。程序运行时候的截图如下所示。由图可见运行的同时程序在控制台中打印出了两种信息:
(1) 该视频的相关信息
(2) 播放该视频的 Filter Graph中的Filter(该功能通过函数show_filters_in_filtergraph()完成)。
可以通过定义在代码最前面宏OUTPUT_INFO控制是否输出视频的信息。定义成“0”的话则不会输出视频的信息。如下所示。
#define OUTPUT_INFO 1
下载
Simplest DirectShow Example
项目主页
SourceForge:https://sourceforge.net/projects/simplestdirectshowexample/
Github:https://github.com/leixiaohua1020/simplest_directshow_example
开源中国:http://git.oschina.net/leixiaohua1020/simplest_directshow_example
CDSN下载地址:http://download.csdn.net/detail/leixiaohua1020/8348163
本程序包含了DirectShow开发的示例程序。适合DirectShow初学者进行学习。
它包含了以下几个子程序:
simplest_directshow_player: 最简单的基于DirectShow的视频播放器。
simplest_directshow_player_custom: 最简单的基于DirectShow的视频播放器(Custom)。
playerGUI: 最简单的基于DirectShow的播放器-图形界面版。
simplest_directshow_info: 最简单的Directshow信息显示例子。
simplest_directshow_filter: 目前还未完成。
最简单的基于DirectShow的示例:视频播放器的更多相关文章
- 最简单的基于DirectShow的示例:视频播放器自定义版
===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...
- 最简单的基于DirectShow的示例:视频播放器图形界面版
===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...
- 最简单的基于DirectShow的示例:获取Filter信息
===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...
- 最简单的基于FFMPEG+SDL的视频播放器 ver2 (採用SDL2.0)
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
- 最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
- 基于<最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)>的一些个人总结
最近因为项目接近收尾阶段,所以变的没有之前那么忙了,所以最近重新拿起了之前的一些FFMPEG和SDL的相关流媒体播放器的例子在看. 同时自己也用FFMPEG2.01,SDL2.01结合MFC以及网上罗 ...
- 用JavaCV改写“100行代码实现最简单的基于FFMPEG+SDL的视频播放器 ”
FFMPEG的文档少,JavaCV的文档就更少了.从网上找到这篇100行代码实现最简单的基于FFMPEG+SDL的视频播放器.地址是http://blog.csdn.net/leixiaohua102 ...
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)【转】
转自:http://blog.csdn.net/leixiaohua1020/article/details/8652605 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] ...
- 最简单的基于FFMPEG+SDL的视频播放器:拆分-解码器和播放器
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
随机推荐
- hdu 2865 Polya计数+(矩阵 or 找规律 求C)
Birthday Toy Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
- spring boot新建项目启动报:Unregistering JMX-exposed beans on shutdown
原因为:SpringBoot内置Tomcat没有正常启动,在pom.xml 中添加: <dependency> <groupId>org.springframework.boo ...
- Python中生成器和迭代器的功能介绍
生成器和迭代器的功能介绍 1. 生成器(generator) 1. 赋值生成器 1. 创建 方法:x = (variable for variable in iterable) 例如:x = (i f ...
- VMWare 学习目录
Linux介绍 Linux入门--个人感想 Google怎么用linux 初入Linux Windows XP硬盘安装Ubuntu 12.04双系统图文详解 实例讲解虚拟机3种网络模式(桥接.nat. ...
- session.save()返回值问题
正常都应该返回插入的主键 但是 如果你用sessionFactory来写就一定返回0 先科普下持久化数据库的三个状态方便下面理解 一次会话状态中,持久化对象经历以下三种状态:1 transient:对 ...
- Linux阿里云挂载磁盘,并开机自动挂载
Linux下磁盘挂载 公司新订购阿里云ECS,需要挂载当前的磁盘.暂时没有运维,自己动手挂载磁盘. 具体步骤如下: 1.查看是否已经分配 [root@iZ2ze1tefvghtbgkdur3xfZ / ...
- [JCIP笔记](五)JDK并发包
这一节来讲一讲java.util.concurrent这个包里的一些重要的线程安全有关类. synchronized容器 synchronized容器就是把自己的内部状态封装起来,通过把每一个publ ...
- 1. 两数之和 LeetCode
给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 给定 nums = [, , , ], target = 因为 n ...
- MongoDB 关系
MongoDB 的关系表示多个文档之间在逻辑上的相互联系. 文档间可以通过嵌入和引用来建立联系. MongoDB 中的关系可以是: 1:1 (1对1) 1: N (1对多) N: 1 (多对1) N: ...
- C/C++ 函数指针
函数声明 例如: float func(int, int); 以上就是一个函数的声明,要注意它的实际功能并没有被实现,换句话说就是它并没有被定义,只是声明此函数的存在.要想调用次函数,你必须对对此函数 ...