=====================================================

最简单的基于DirectShow的示例文章列表:

最简单的基于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的示例:视频播放器的更多相关文章

  1. 最简单的基于DirectShow的示例:视频播放器自定义版

    ===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...

  2. 最简单的基于DirectShow的示例:视频播放器图形界面版

    ===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...

  3. 最简单的基于DirectShow的示例:获取Filter信息

    ===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...

  4. 最简单的基于FFMPEG+SDL的视频播放器 ver2 (採用SDL2.0)

    ===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...

  5. 最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)

    ===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...

  6. 基于<最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)>的一些个人总结

    最近因为项目接近收尾阶段,所以变的没有之前那么忙了,所以最近重新拿起了之前的一些FFMPEG和SDL的相关流媒体播放器的例子在看. 同时自己也用FFMPEG2.01,SDL2.01结合MFC以及网上罗 ...

  7. 用JavaCV改写“100行代码实现最简单的基于FFMPEG+SDL的视频播放器 ”

    FFMPEG的文档少,JavaCV的文档就更少了.从网上找到这篇100行代码实现最简单的基于FFMPEG+SDL的视频播放器.地址是http://blog.csdn.net/leixiaohua102 ...

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

    转自:http://blog.csdn.net/leixiaohua1020/article/details/8652605 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] ...

  9. 最简单的基于FFMPEG+SDL的视频播放器:拆分-解码器和播放器

    ===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...

随机推荐

  1. bzoj2839: 集合计数 容斥+组合

    2839: 集合计数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 523  Solved: 287[Submit][Status][Discuss] ...

  2. PTA 字符串关键字的散列映射(25 分)

    7-17 字符串关键字的散列映射(25 分) 给定一系列由大写英文字母组成的字符串关键字和素数P,用移位法定义的散列函数H(Key)将关键字Key中的最后3个字符映射为整数,每个字符占5位:再用除留余 ...

  3. AsyncLocal 与 async await

    大家来看一张图 先猜猜看为什么会这样 关于async await的原理 建议查看 https://blog.csdn.net/brook_shi/article/details/50803957 这篇 ...

  4. Swift 3.0项目迁移的一些记录

    刚执行完Convert后报错600+,真是令人奔溃. 之后重新编译,仔细分析后发现其实真实错误远没有那么多.最终实际修改到的错误也就几十个,而且其中某些还是同一种错误. 这个项目是一个供自己使用的浏览 ...

  5. 关于java的Synchronized,你可能需要知道这些(上)

    对于使用java同学,synchronized是再熟悉不过了.synchronized是实现线程同步的基本手段,然而底层实现还是通过锁机制来保证,对于被synchronized修饰的区域每次只有一个线 ...

  6. 通讯协议序列化解读(一) Protobuf详解教程

    前言:说到JSON可能大家很熟悉,是目前应用最广泛的一种序列化格式,它使用起来简单方便,而且拥有超高的可读性.但是在越来越多的应用场景里,JSON冗长的缺点导致它并不是一种最优的选择. 一.常用序列化 ...

  7. linux下的静态库与动态库详解

    静态库 先说说我们为什么需要库? 当有些代码我们大量会在程序中使用比如(scanf,printf等)这些函数我们需要在程序中频繁使用,于是我们就把这些代码编译为库文件,在需要使用时我们直接链接即可. ...

  8. Django Views(视图函数)

    http请求中产生两个核心对象: http请求:HttpRequest对象 http响应:HttpResponse对象 所在位置:django.http 之前我们用到的参数request就是HttpR ...

  9. Winform DevExpress控件库(三) 使用NavBarControl控件定制导航栏

    NavBarControl控件:主要作用是制作包含多个选项组并且每个组里包含多个子选项的导航栏: 位于 工具箱 -> Navigation & Layout(导航栏与布局类控件) 目录下 ...

  10. DISC社交风格测试题--老虎 孔雀 考拉 猫头鹰

    凭直觉,迅速回答 "我是谁",而不是"我应该是谁,或我想我是谁". 1.关于人生观,我的内心其实是: A 希望能够有尽量多的人生体验,所以会有非常多样化的想法. ...