开源项目之Splayer 射手影音播放器


Splayer
射手影音播放器)是一款高画面、低消耗、智能化、精致美观的影音播放器。

具有如下八个独创:

独创ShaderEngineTM图像增强引擎,4倍速驱动,降低画面噪点,锐利画质呈现,低画质视频照样全屏放
独创LiveColorTM彩色增强算法,画面色彩更艳丽
独创SmartAmplifyTM智能音场平衡技术,声效更显震撼

独创FastMotionTM解码优化技术,大幅降低CPU和内存占用。多核 SSE2 SSE3 MMX GPU优化
独创PowerTravelTM旅行节电模式,降低能耗,增加笔记本的巡航时间
独创EyeCareTM护眼模式,久看不疲劳,健康最重要

独创Anti-SillyTM智能免配置,数百逻辑分支自动根据硬件配置选择最佳模式。
独创CloudMatchingTM智能显示字幕技术,外语片从此不再需要找寻匹配字幕

Splayer 是一款开源项目,项目总共有87个工程(含测试工程),如图:


效果如图:




这是我目前接触最大的项目,刚接触时不知道如何下手,于是把所有的库都大致的分析了一遍,由于缺少资料所以很多分析都带有主观,难免有瑕疵,

但我然仍贴出来,以鼓励我继续研究,我计划把Splayer集成为一个视频播放的控件,现在计划已经进行了38%,但由于工作原因,这项计划被搁置了,

但我相信我会慢慢把它完成,因为我是一个码农,o(∩_∩)o 哈哈!~~~

2012tvod项目如图:



效果如图:




 进入主题了,由于Splayer项目过多,所以把它分成二个部分(主程序、类库),现在从类库开始分析了。

libpng   libpng是OSI认证开源软件,主要负责读写png文件。该库是用来创立和操作png格式的图像文件.png格式是设计来替代gif,他对于更小范围的tiff(标记图
象文件格式)。Splayer中类CPngIMage是对该库的应用,该类在libpng.h中。

decss   DVD解密源码,专门针对DVD安全机制设计的破解其内容混合系统的,利用decss的功能从网上下载DVD格式的数字电影,还可以用DivX软件将下载的数字电影
压缩存储到硬盘或光盘上。该类库需要用到BaseClasses库。 该库有五个类,分别是CDeCSSInputPin、CVobDec、CDVDSession、CLBAFile、CVobFile。
dsutil   directshow工具类库,主要负责视频处理、捕获应用…等操作。该类库需要用到BaseClasses库和foundation库。该库还有类:IDSMPropertyBagImpl 编码器选项设置接口、CDSMResource、IDSMResourceBagImpl、CDSMChapter、IDSMChapterBagImpl、CDSMChapterBag、CFontInstaller 字体的初始化、CGolombBuffer、CH264Nalu、CHdmvClipInfo、CMediaTypeEx、CNullRenderer、CNullVideoRenderer、CNullUVideoRenderer、CNullAudioRenderer、CNullUAudioRenderer、CNullTextRenderer、CCpuID。其中DSUtil.h 包含很多视频操作函数。

foundation  该库是一个辅助库,内含:base64编解码、同步类CriticalSection/AutoCSLock、文件路径操作类FilePath、信息输出类LogController、加载资源类ResLoader、定义字符串Strings、多线程辅助模块ThreadHelperImpl、实例生成模块LazyInstanceImpl。
id3lib 该库是用于读、写和操纵ID3v1和ID3v2标签的对于媒体类型的文件,它能够调用id3lib库来获取诸如作者,唱片年代,风格等tag信息,如果是视频媒体文件,它还会抓图。

libssf 该库为一个操作 影视字幕以及特效的类库。
lyriclib 该库为歌词匹配类库。
subpic 该库为操作位图类库(例如 字幕图片显示)。
sqlitepp 该库是一个C++封装的 SQLite组件,开源、免费。目的是使用面向对象的方式来简化SQLite的使用,具有面向对象的访问方式。程序将通过它生成数据库,该数据库是settings.db 负责记录设置信息。
subtitles 该库是操作视频字幕的库。
svplib  该库是一个 字幕获取功能库,内含:CSVPEqualizer、CSVPRarLib 压缩包rar文件操作、CSVPSubfilterLib、CSVPToolBox 文件路径操作类。
yaml-cpp 是一个 开源的YAML 解析器。
CmdUI 是一个界面设置属性的对话框
ResizableLib 为一个界面库,可以根据父窗口的位置和大小动态调整控件窗口的大小。
sizecbar 为实现浮动工具条!
TreePropSheet 为树控件目录即文件目录
Updater 程序的升级程序
libmad 该库是一个MPEG音频解码库,是一个高-品质的??的的的MPEG音频解码器。目前,它支持MPEG-1和MPEG-2扩展到较低的采样频率,以及所谓的MPEG 2.5格式,是一个独立库。

filters 该库是滤波函数库等,该库主要有程序类CFilterApp、CInternalPropertyPageWnd属性窗体、CInternalPropertyPage属性页、CInternalPropertyPageTempl模块、CPinInfoWnd。
liba52  该库是一个解码ATSC A/52流的库,还包括一个MPEG-1和MPEG-2节目流复用器(音频和视频)。编码的环绕立体声缩混  大多数用户明显增加任意缩混扬声器配置,并实施动态范围压缩。
libdts  该库是一个DTS相干声学解码器库 负责解码DTS相干声学流,用于一个跨平台的视频播放和流VLC媒体播放器。
zlib 该库是一个压缩算法的库,提供数据压缩用的函式库。
libfaad 该库是软高级音频(AAC)解码器,含丁苯橡胶解码。其中in_mp4 - Winamp的MPEG-4 AAC文件输入插件,QCD的 - 典型的球员的AAC插件,QCDMp4 - 典型的播放器MP4插件,XMMS - XMMS的AAC插件,MPEG4IP - 为MPEG4IP播放器插件。
libdirac 该库是一个开源的视频编解码器。它采用了传统的混合视频编解码器架构,是与小波转换而不是通常的块转换。运动补偿使用重叠的块,以减少区块会扰乱变换编码阶段的文物。
baseclasses 该库是DirectX 自带的一个库,是微软推出的一套基于Windows系统的多媒体应用程式接口APIs函式。
libflac   该库是FLAC文件解码器的一个库,是无损音频编解码器库。
libavcodec  该库是非常先进的音频/视频编解码库,用于各种类型声音/图像编解码,无法使用VS2008编译。
libvorbisidec 该库是Ogg文件编解码器。
libmpeg2 该库是一个解码MPEG-2和MPEG-1视频的库。
SyncClock   该库是同步卡与服务器的时间设置库,该库主要有:CSyncClock、CSyncClockFilter。
BaseMuxer 该库为输入/输出流混合器基库,合成器可将特定的音视频流合成为特定的媒体容器格式,并交给文件写滤镜写入到磁盘中,从而最终实现媒体格式的转换。特定的合成器需要与特定的音视频编码器配合才能起作用,只不过有些合成器比较挑食,只能容纳一种类型的音视频编码,而有些合成器胃口很好,可容纳的多种音视频编码,如WMV和ASF的合成器只能容纳下WMA音频和WMV视频,而AVI的合成器则可以容纳从非压缩的RGB视频及PCM音频到高压缩率的DivX视频及MP3音频,至于MKV和DSM的合成器,几乎算是万能合成器了,该库主要有CBaseMuxerFilter、CBaseMuxerInputPin、CBaseMuxerOutputPin、CBaseMuxerRawOutputPin。
DSMMuxer 介绍同上,该库主要有CDSMMuxerFilter类
MatroskaMuxer 介绍同上,是负责将音频流和视频流合成为MKV格式,但要输出,还需要一个文件写出滤镜(File writer),它负责把“Matroska Muxer”合成的结果写入到磁盘当中,该类库主要有CMatroskaMuxerInputPin、CMatroskaMuxerOutputPin、CMatroskaMuxerFilter等类。
wavdest 主要用于将采集到的视频流写入到指定的文件,文件格式是.WAV。该库主要有CWavDestOutputPin、CWavDestFilter等类
streamdrivethru  该库是驱动流通过输入/输出引脚过滤器,该库主要有CStreamDriveThruInputPin、CStreamDriveThruOutputPin、CStreamDriveThruFilter等类。
AviSplitter  该库是AVI的滤镜分离器,默认用System的,因稳定性和兼容性最好;Gabest的可以读下载不完整的AVI文件;而Haali的支持多音轨的切换。该库涉及:BaseSplitter库、BaseClasses库,该库主要有:CAviFile、CAviPlotterWnd、CAviReportWnd、CAviSplitterOutputPin、CAviSplitterFilter、
CAviSourceFilter。
basesplitter 该库是分词基类,该库涉及dsutil、unrar、AudioSwitcher类库,该库主要有:CAsyncFileReader、CAsyncUrlReader、Packet、CPacketQueue、CBaseSplitterInputPin、CBaseSplitterOutputPin、CBaseSplitterFilter、CBaseSplitterFile、CBaseSplitterFileEx、CMultiFiles。
diracSplitter  该库是dirac滤镜分离器库,该库涉及:BaseSplitter库、BaseClasses库,该库主要有CDiracSplitterFilter、CDiracSourceFilter、CDiracVideoDecoder、CDiracSplitterFile。
DSMSplitter  该库是dsm滤镜分离器库,该库涉及:BaseSplitter库、BaseClasses库,该库主要有CDSMSplitterFilter、CDSMSourceFilter、CDSMSplitterFile等类。
EASplitter  该库是ea滤镜分离器库,该库涉及:BaseSplitter库、BaseClasses库、DSUtil库、ffmpeg库等,该库主要有CEAFile、CEASpliterFilter、CEASourceFilter。
flvsplitter  该库是flv滤镜分离器库,该库涉及:BaseSplitter库、BaseClasses库、DSUtil库、libVP62(flash vp6解码器)库,该库主要有CFLVSplitterFilter、CFLVSourceFilter、VP62。
MatroskaSplitter 该库是MKV滤镜分离器库(MKV视频的分离器),该库主要涉及:BaseSplitter库、BaseClasses库、DSUtil库。该库类较多。
mp4splitter  该库是MP4滤镜分离器库,该库主要涉及:BaseSplitter库、BaseClasses库、DSUtil库、Zlib库。该库主要有:CMP4SplitterFilter、CMP4SourceFilter、CMPEG4VideoSplitterFilter、CMPEG4VideoSourceFilter、CMP4SplitterFile……等等。
MpaSplitter  该库是Mpa滤镜分离器库,该库主要涉及:BaseSplitter库、BaseClasses库、DSUtil库。该库主要有:CMpaSplitterFilter、CMpaSplitterFile等类。
MpegSplitter  该库是MPEG滤镜分离器库,一个MPEG的分割工具,可将大尺寸MPEG文件分割成数个小尺寸的MPEG文件。该库主要涉及:BaseSplitter库、BaseClasses库、DSUtil库。该库主要有:CMpegSplitterFilter、CMpegSourceFilter、CMpegSplitterFile、CMpegSplitterSettingsWnd等类。
WMVSpliter 该库为WMV滤镜分离器库,WMA是一种视频编码格式,该库主要有StreamOnAsyncReader、ptr_shared_count(线程安全的共享数)、StreamInput、WMFOutputPin(输出引脚,提供的解码器的压缩数据)、IEncapsulatedAccess(分配缓冲区WMF时,我们需要返回一个IMediaSample对象周围的包装/INSSBuffer的接口)、EncapsulateSample、WMFDemuxFilter(分析器过滤器本身)、
NutSplitter  该库主要涉及:BaseSplitter库、BaseClasses库、DSUtil库。该库主要有:CNutFile、CNutSplitterFilter、CNutSourceFilter等类。
OggSplitter  该库是Ogg滤镜分离器库,Ogg是一种新的音频压缩格式,类似于MP3等的音乐格式。该库主要涉及:BaseSplitter库、BaseClasses库、DSUtil库。该库主要有:OggPage类、COggFile类、OggPacket类、COggSplitterOutputPin类、COggVorbisOutputPin类、COggDirectShowOutputPin类、COggS treamOutputPin类、COggSplitterFilter类、COggSourceFilter类…等等。
RealMediaSplitter 该库是real滤镜分离器库,是real播放器为除realplay外播放器播放real格式,比如RM,RMVB等等格式的播放插件.有了这个插件,其他播放器才能够播放REAL格式的视频,音频等文件.
RoQSplitter 该库是分离式联轴器的旋转编码器,该库主要有CRoQSplitterFilter、CRoQSourceFilter、CRoQVideoDecoder、CRoQAudioDecoder等类。
ssfsplitter 该库是特效字幕d的滤镜分离器,该库主要有CSSFSplitterFilter、CSSFSourceFilter等类。
asyncreader 该库是读取网络上的编码后的视频数据库,读取后交给解码filter。该库主要有:CAsyncStream、CAsyncIo、CAsyncOutputPin、CAsyncReader。
cddareader 该库是开源滤镜MPC,DTS技术编码的音频具有细节丰富、定位精确的特点,是传统CD和Dolby环绕声效的后继者。该库主要有:CCDDAStream、CCDDAReader类。
cdxareader  该库为系统滤镜,该库主要有CCDXAStream、CCDXAReader类。
udpreader   该库为系统滤镜,该库主要有CUDPStream、CUDPReader类。
vtsreader   该库为系统滤镜,该库主要有CVTSStream、CVTSReader类。
MpcAudioRenderer 该库为使用WASAPI音频输出MPC音频渲染器,该库主要有CMpcAudioRenderer类。
basesource  该库是解码文件的基础库,该库主要有:CBaseSource、CBaseStream等类。
dtsac3source该库是DTS/AC3输出滤镜的库,DTS(Digital Theater Systems)是一种高质量的多声道音频编码方式,目前主要用作DVD的伴音。DTS 5.1的最大码率(Bitrate)与LPCM(LPCM是数位非经压缩的声音规格,音质佳,所占容量空间较大)相同,可达1536Kbps,远高于目前另一种流行的多声道编码系统──Dolby Digital AC3的 448Kbps,虽然同样是有损压缩,但它可提供更为逼真,细节更为丰富的音响效果。用DVD中DTS音轨来制作音乐CD无疑是非常理想的。该库主要有:CDTSAC3Source、CDTSAC3Stream等类。
flicsource  该库是处理fli文件的库,主要有CFLICSource、CFLICStream等类。
flacsource  该库是音频压缩编解码库,其特点是无损压缩。不同于其他有损压缩编码如MP3 及 AAC,它不会破坏任何原有的音频资讯,所以可以还原音乐光盘音质。该库主要有:CFlacSource、CFlacStream类。该库主要牵涉
shoutcastsource  该库是采用了MPEG Layer 3(MP3)技术,实现了因特网上的音频流的实时广播或者点播。该库主要有:CShoutcastSource、CShoutcastStream等类。
d2vsource 该库为d2v输出滤镜的库,d2v即数字化视频,该库主要有CMPEG2Dec、CD2VSource、CMPEG2Dec等类。
subtitlesource 该库为字幕输出滤镜的库,该库主要有CSubtitleSource、CSubtitleStream等类。
audioswitcher  该库是一个自动切换扬声器的库,涉及主程序的eqPerset负责设置音频,该库主要有:AudioStreamResampler、CAudioSwitcherFilter、CStreamSwitcherPassThru、CStreamSwitcherAllocator、CStreamSwitcherInputPin、CStreamSwitcherOutputPin、CStreamSwitcherFilter。
Mpeg2DecFilter 该库是为测试程序是libmpeg2。它解码MPEG-1和MPEG-2视频流,还包括一个MPEG-1和MPEG-2解复用器节目流。该库牵涉:BaseVideoFilter.lib libmpeg2.lib dsutil.lib 等库,该库主要有:IMpeg2DecFilter接口、CMpeg2Info、CMpeg2Dec、CMpeg2DecFilter、CMpeg2DecInputPin、CMpeg2DecOutputPin、CSubpicInputPin、CMpe g2DecSettingsWnd等类。
avi2ac3filter 该库为AC3音效辅助插件库,目前DVDrip在制作音频部分时普遍采用两种方式:MP3格式压缩音轨和保留DVD中原有的AC3音频文件。一般来说,Windows操作系统已经自带了MP3的解码器——Fhg Radium MP3 codec,因此采用MP3格式做的DVDrip音频我们都可以听到。但对于以AC3音频文件制作的DVDrip,我们就只能看到图像而听不到声音了,该库主要有CAVI2AC3Filter类。
bufferfilter 该库为滤镜输出缓冲区库,该库主要有CBufferFilter、CBufferFilterOutputPin等类。
decssfilter 该库为CSS滤镜,对常规的CSS的一个扩展子集,可以使应用对象(文字,图片...)产生类似于PHOTOSHOP中的模糊,通透,边缘发光等效果。该库主要有CDeCSSFilter类。
Mpeg2DecFilter 该库为mpeg1、mpeg2解码过滤器,该库主要有CMpeg2Info、CMpeg2Dec、CMpeg2DecFilter、CMpeg2DecInputPin、CMpeg2DecOutputPin、CSubpicInputPin、CClosedCaptionOutputPin、CMpeg2DecSettingsWnd等类。
MpaDecFilter  该库为MPC H264/VC1硬解码器(主音频解码器),该库主要有CMpaDecFilter、CMpaDecInputPin、CMpaDecSettingsWnd等类。
basevideofilter 该库为解码视频播放过滤器基库,该库主要有CBaseVideoFilter、CBaseVideoInputAllocator、CBaseVideoInputPin、CBaseVideoInputPin、CBaseVideoOutputPin等类。
MPCVideoDec 该库为主视频解码类库,该库主要有CMPCAudioDecFilter、CMPCVideoDecFilter、CMPCVideoDecSettingsWnd等类。
svpfilter 该库为字幕滤镜类库,该库主要有CSVPSubFilter类。


mplayerc为主程序,主程序自绘控件,以及应用视频音频编解码播放,此处就简单的看看涉及视频播放主要有哪些类!

//渲染操作图像基类 定义如下
class CBaseGraph
	: public CUnknown
	, public IGraphBuilder2  //IGraphBuilder接口允许应用程序调用时的过滤器图表管理器试图建立一个完整的过滤器图表
	, public IMediaControl  //IMediaControl接口提供控制的数据流通过过滤器图的方法。它包括运行,暂停和停止图形的方法
	, public IMediaEventEx  //其中包含了用于检索事件通知和用于重写筛选器图形的默认事件处理的方法
	, public IMediaSeeking  //IMediaSeeking接口包含寻求内流的位置,并设置播放速度的方法
	, public IVideoWindow  //IVideoWindow接口设置视频窗口的属性。应用程序可以使用它来 ​​设置窗口的所有者窗口的位置和尺寸,和其他属性。
	, public IBasicVideo  //IBasicVideo接口设置视频属性,如目标和源矩形。
	, public IBasicAudio   //IBasicAudio接口控制音频流的音量和平衡。
	, public IAMOpenProgress    //IAMOpenProgress接口报告的文件打开操作的进度,使应用程序能够取消操作。
	, public IGraphEngine	//渲染引擎接口
//播放flash类
class CShockwaveGraph : public CBaseGraph
class CMacrovisionKicker
	: public CUnknown
	, public IKsPropertySet	//IKsPropertySet接口的最初目的是作为一种有效的方式来设置和检索WDM驱动程序的设备属性,使用KSProxy翻译用户模式COM方法调用进入内核模式属性的WDM流类驱动程序所使用的设置
interface __declspec(uuid("165BE9D6-0929-4363-9BA3-580D735AA0F6")) IGraphBuilder2 : public IFilterGraph2
//IFilterGraph2接口扩展IFilterGraph的的IGraphBuilder接口,其中包含建立过滤器图表的方法。
//筛选器图形管理器实现了这个接口。应用程序可以使用它建立图表时,利用它提供的其他方法的优势。
class __declspec(uuid("96F3E0BE-1BA4-4E79-973D-191FE425C86B")) CDeinterlacerFilter : public CTransformFilter
//CTransformFilter类是为实施变换过滤器的基类。这个类是专为实施变换过滤器与一个输入引脚和一个输出引脚。
//它使用的输入引脚和输出引脚独立的分配器。要创建一个过滤器,数据处理,使用CTransInPlaceFilter类。
	//DX7分配器演示
	class CDX7AllocatorPresenter
		: public ISubPicAllocatorPresenterImpl  //图像分配操作接口
	//DX9分配器演示
	class CDX9AllocatorPresenter
		: public ISubPicAllocatorPresenterImpl //图像分配操作接口
	//DXR分配器演示
	class CDXRAllocatorPresenter:
		public ISubPicAllocatorPresenterImpl  //图像分配操作接口
//EVR方式输出
class COuterEVR:
	public CUnknown,
	public IVMRffdshow9,
	public IVMRMixerBitmap9,  //使应用程序从位图或Direct3D表面上的视频流,混合静态图像,当使用视频混合渲染过滤器(VMR-9)。
	public IBaseFilter   //IBaseFilter接口是DirectShow过滤器的主界面
//EVR分配器演示
class CEVRAllocatorPresenter:
	public CDX9AllocatorPresenter,
	public IMFGetService,  //查询指定的服务接口的对象。
	public IMFTopologyServiceLookupClient,  //初始化视频混合器或演示。此接口由混频器和演示,使他们能够增强视频渲染器(EVR)查询接口指针。
	public IMFVideoDeviceID,  //返回视频渲染组件支持的设备标识符。实现此接口由混频器和增强视频渲染器(EVR)的主持人。
	public IMFVideoPresenter,  //增强视频渲染器(EVR)提供了一个默认的视频演示,应用程序可以实现自定义的主持人。
	public IDirect3DDeviceManager9,  //使两个线程共享相同的Direct3D 9设备,并提供访问的DirectX视频加速(DXVA)功能的设备。
	public IMFAsyncCallback,  //回调接口的异步方法完成时通知应用程序。
	public IQualProp,			//IQualProp接口提供视频渲染性能信息检索的方法。
	public IMFRateSupport,			//查询范围的支持,包括反向播放的播放率。	
	public IMFVideoDisplayControl,	//控制如何增强型视频渲染器(EVR)显示视频。
	public IEVRTrustedVideoPlugin		//1启用插件在增强视频渲染器(EVR)与保护媒体工作的组成部分。
//映射过滤器
class CFilterMapper2 : 
	protected CUnknown, 
	public IFilterMapper2	//注册和取消注册的过滤器,并在注册表中找到过滤器。
//过滤器重叠 (找最近的过滤器)
class FilterOverride
//FG过滤器
class CFGFilter
//FG过滤器注册
class CFGFilterRegistry :
	public CFGFilter
//FG过滤器文件
class CFGFilterFile :
	public CFGFilter
//FG过滤器视频渲染
class CFGFilterVideoRenderer : 
	public CFGFilter
//FG过滤器管理
class CFGManager
	: public CUnknown
	, public IGraphBuilder2
	, public IGraphBuilderDeadEnd
	, public CCritSec			//CCritSec类提供了一个线程锁。
//添加过滤器
class CFGManagerCustom : public CFGManager
//视频播放时触发 寻找和链接过滤器
class CFGManagerPlayer 
	: public CFGManagerCustom
//DVD播放时触发 添加对应的过滤器以及渲染图像
class CFGManagerDVD 
	: public CFGManagerPlayer
//视频捕捉触发
class CFGManagerCapture 
	: public CFGManagerPlayer
//合成器
class CFGManagerMuxer 
	: public CFGManagerCustom
//FG聚合 可以根据riid查询对应的接口
class CFGAggregator 
	: public CUnknown
	//同步锁
	class CGenlock
//QT视图操作接口
interface __declspec(uuid("A6AE36F7-A6F2-4157-AF54-6599857E4E20")) IQTVideoSurface : public IUnknown
//视频解码设置类 读取显卡信息
class MPCVideoDecSetting
//VMR9方式输出
class COuterVMR9:
	public CUnknown,
	public IVideoWindow,	//视频窗口接口
	public IBasicVideo2,  //视频渲染过滤器和视频混合渲染过滤器实现这个接口,但通过过滤器图表管理器的应用程序接口暴露。
	public IVMRWindowlessControl,	//IVMRWindowlessControl界面控制视频混合渲染过滤器(VMR-7)如何呈现在一个容器内窗口的视频流
	public IVMRffdshow9,
	public IVMRMixerBitmap9	//IVMRMixerBitmap9接口,使应用程序从位图或Direct3D表面上的视频流,混合静态图像,当使用视频混合渲染过滤器(VMR-9)
//像素着色器编译器
class CPixelShaderCompiler
	//QT7分配器演示
	class CQT7AllocatorPresenter
		: public CDX7AllocatorPresenter //
		, public IQTVideoSurface  //qt视图操作接口
	//QT9分配器演示
	class CQT9AllocatorPresenter:
		public CDX9AllocatorPresenter,
		public IQTVideoSurface //QT视图操作接口
	//实现QuickTime多媒体文件播放
	class CQuicktimeWindow : public CPlayerWindow
//QuickTime多媒体文件渲染
class CQuicktimeGraph :
	public CBaseGraph,  //基类渲染
	public IVideoFrameStep	//实现单帧前进后退
	//实现RealMedia多媒体文件播放
	class CRealMediaPlayer
		: public CUnknown
		, public IRMAErrorSink //错误处理接口
		, public IRMAClientAdviseSink //能够使 RealPlayer的上层感知内核中播放 状态的改变以及其他相关信息
		, public IRMAAuthenticationManager	//可以控制网络上多个数码复合机的认证数据,并能对每个用户的认证数据进行简单有效的设置。
		, public IRMASiteSupplier  //rma站点提供接口
		, public IRMAPassiveSiteWatcher	//通过站点观察接口
		, public IRMAAudioHook		//音频钩子接口
//RealMedia媒体视频视图操作
class CRealMediaVideoSurface
	: public CUnknown
	, public IRMAVideoSurface //视图操作接口
	//RM7分配器演示
	class CRM7AllocatorPresenter
		: public CDX7AllocatorPresenter
		, public IRMAVideoSurface  //视图操作接口
	//RM9分配器演示
	class CRM9AllocatorPresenter: 
		public CDX9AllocatorPresenter,
		public IRMAVideoSurface  //RMA视图操作接口
	//VMR7分配器演示
	class CVMR7AllocatorPresenter
		: public CDX7AllocatorPresenter
		, public IVMRSurfaceAllocator	//分配器演示使用这个接口进行通信的VMR
		, public IVMRImagePresenter	//IVMRImagePresenter9接口来实现的默认分配器演示视频混合呈现过滤器(VMR-9),VMR-9使用此接口通知分配器演示的,它应该呈现的视频帧中所提供的Direct3D表面。
		, public IVMRWindowlessControl	//显示窗口控制接口
	//VMR9分配器演示
	class CVMR9AllocatorPresenter
		: public CDX9AllocatorPresenter, 
		public IVMRSurfaceAllocator9,	//分配器演示使用这个接口进行通信的VMR
		public IVMRImagePresenter9,		//IVMRImagePresenter9接口来实现的默认分配器演示视频混合呈现过滤器(VMR-9),VMR-9使用此接口通知分配器演示的,它应该呈现的视频帧中所提供的Direct3D表面。
		public IVMRWindowlessControl9	//显示窗口控制接口
class __declspec(uuid("96F3E0BE-1BA4-4E79-973D-191FE425C86B")) CDeinterlacerFilter 
	: public CTransformFilter // 用来浏览视频 时候旋转 
class __declspec(uuid("E2BA9B7B-B65D-4804-ACB2-89C3E55511DB")) CTextPassThruFilter : 
	public CBaseFilter, 
	public CCritSec


视频播放大致跟这些类/接口有关!

主程序是如何播放的?先来看看主程序的几个成员函数:

  // Operations   准备视频播放操作
  bool OpenMediaPrivate(CAutoPtr<OpenMediaData> pOMD);
  // 准备关闭当前视频操作
  void CloseMediaPrivate();
	//创建渲染对象
  void OpenCreateGraphObject(OpenMediaData* pOMD);
  //路径操作
  HRESULT OpenMMSUrlStream(CString szFn);
  //打开目标文件
  void OpenFile(OpenFileData* pOFD);
  //打开DVD
  void OpenDVD(OpenDVDData* pODD);
  //打开视频捕捉
  void OpenCapture(OpenDeviceData* pODD);
  //通用渲染
  void OpenCustomizeGraph();
  //初始化视频操作
  void OpenSetupVideo();
  //初始化音频操作
  void OpenSetupAudio();
这些函数进行了视频相关操作!~

当打开文件时触发

 m_pGraphThread = (CGraphThread*)AfxBeginThread(RUNTIME_CLASS(CGraphThread));
if(m_pGraphThread)
    m_pGraphThread->SetMainFrame(this);
销毁时触发

  if(m_pGraphThread)
  {
    CAMEvent e;
    m_pGraphThread->PostThreadMessage(CGraphThread::TM_EXIT, 0, (LPARAM)&e);
    if(!e.Wait(5000))
    {
      TRACE(_T("ERROR: Must call TerminateThread() on CMainFrame::m_pGraphThread->m_hThread\n")); 
      TerminateThread(m_pGraphThread->m_hThread, -1);
    }
  }

打开文件流程分析:
void CMainFrame::OnFileOpenQuick()
{
   正在加载或列表未生成 则直接返回
  if(m_iMediaLoadState == MLS_LOADING || !IsWindow(m_wndPlaylistBar)) return;

   近期文件列表
  CRecentFileList& MRU = AfxGetAppSettings().MRU;

  CString szLastFile;  最后一次看的视频文件

  MRU.ReadList();    读取列表的文件路径

  if(MRU.GetSize() > 0){
    szLastFile = MRU[0];    把读取的文件信息取出
  }

  CString filter;
  CAtlArray<CString> mask;
  从设置里面读取过滤的设置
  AfxGetAppSettings().Formats.GetFilter(filter, mask);

  COpenFileDlg fd(mask, true, NULL, szLastFile, 
    OFN_EXPLORER|OFN_ENABLESIZING|OFN_HIDEREADONLY|OFN_ALLOWMULTISELECT|OFN_ENABLEINCLUDENOTIFY, 
    filter, this);
  if(fd.DoModal() != IDOK) return;    显示出打开文件对话框

  CAtlList<CString> fns;

  POSITION pos = fd.GetStartPosition();
  while(pos) fns.AddTail(fd.GetNextPathName(pos)); 把选中的文件加入进来

  bool fMultipleFiles = false;

  判断是否多选 或选中的是目录
  if(fns.GetCount() > 1 
    || fns.GetCount() == 1 
    && (fns.GetHead()[fns.GetHead().GetLength()-1] == '\\'
    || fns.GetHead()[fns.GetHead().GetLength()-1] == '*'))
  {
    fMultipleFiles = true;
  }

  猜测 关闭Media
  SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA);

  ShowWindow(SW_SHOW);
  SetForegroundWindow();

  列表打开文件
  m_wndPlaylistBar.Open(fns, fMultipleFiles);

  播放列表个数为一 且可见 并且不是自由的 则显示或隐藏
  if(m_wndPlaylistBar.GetCount() == 1 && m_wndPlaylistBar.IsWindowVisible() && !m_wndPlaylistBar.IsFloating())
  {
    ShowControlBar(&m_wndPlaylistBar, FALSE, TRUE);
  }

  OpenCurPlaylistItem();  打开当前列表选中项
}

进入 OpenCurPlaylistItem 函数分析  参数为树节点 默认为零
void CMainFrame::OpenCurPlaylistItem(REFERENCE_TIME rtStart)
{
  如果列表中没有  则直接退出
  if(m_wndPlaylistBar.GetCount() == 0)    return;

  CPlaylistItem pli;
   得到当前选中项 如果没有则选中第一项
  if(!m_wndPlaylistBar.GetCur(pli)) m_wndPlaylistBar.SetFirst();
  if(!m_wndPlaylistBar.GetCur(pli)) return;

  AppSettings& s = AfxGetAppSettings();

  if(rtStart == 0){
    CString fn;
    fn = pli.m_fns.GetHead(); 获得文件路径

    // SVP_LogMsg5(L"GetFav Start1 %s", fn);
    favtype ft ;
    ft = FAV_FILE;

    if (!fn.IsEmpty() && s.autoResumePlay){
      文件存在 且 自动恢复播放
      std::string str = Strings::WStringToString(fn.GetBuffer());
      CString szMatchmd5 = HashController::GetInstance()->GetMD5Hash(str.c_str(), str.length()).c_str();

      SVP_LogMsg5(L"GetFav Start %s", szMatchmd5);

      CAtlList<CString> sl;
      s.GetFav(ft, sl, TRUE); 得到以前保存的数据

      CString PosStr ;
      POSITION pos = sl.GetHeadPosition(); 获得
      while(pos){   //判断以前是否播放过
        PosStr = sl.GetNext(pos) ;
        if( PosStr.Find(szMatchmd5 + _T(";")) == 0 ){
          break;
        }else{
          PosStr.Empty();
        }
      }
      if(!PosStr.IsEmpty()){  如果未播放 则记录


        int iPos = PosStr.ReverseFind( _T(';') );
        if(iPos >= 0){
          CString s2 = PosStr.Right( PosStr.GetLength() - iPos - 1 );
          _stscanf(s2, _T("%I64d"), &rtStart); // pos
        }
        SVP_LogMsg5(L"Got %f", double(rtStart) );
      }
      是否恢复退出时的状态
      m_is_resume_from_last_exit_point = TRUE;
      //SVP_LogMsg5(L"GetFav Done");
    }
  }else if(rtStart == -1){
    rtStart = 0;
  }
  
   打开媒体文件  根据OpenMediaData*初始化 OpenMediaData里面保存了路径和rtStart
  CAutoPtr<OpenMediaData> p(m_wndPlaylistBar.GetCurOMD(rtStart));

  if(p) OpenMedia(p); 根据CAutoPtr<OpenMediaData> 进行打开播放
}


  进入OpenMedia进行 打开播放
void CMainFrame::OpenMedia(CAutoPtr<OpenMediaData> pOMD)
{
  // shortcut 
  if(OpenDeviceData* p = dynamic_cast<OpenDeviceData*>(pOMD.m_p))
  {
    如果是DeviceData数据 
    if(m_iMediaLoadState == MLS_LOADED && pAMTuner
      && m_VidDispName == p->DisplayName[0] && m_AudDispName == p->DisplayName[1])
    {
      m_wndCaptureBar.m_capdlg.SetVideoInput(p->vinput);
      m_wndCaptureBar.m_capdlg.SetVideoChannel(p->vchannel);
      m_wndCaptureBar.m_capdlg.SetAudioInput(p->ainput);
      return;
    }
  }

  如果当前正在播放则关闭
  if(m_iMediaLoadState != MLS_CLOSED)
    CloseMedia();

  更改状态
  m_iMediaLoadState = MLS_LOADING; // HACK: hides the logo
  m_wndView.Invalidate();

  AppSettings& s = AfxGetAppSettings();

  bool fUseThread = true;

  if(OpenFileData* p = dynamic_cast<OpenFileData*>(pOMD.m_p))
  {
     如果是打开的文件
    if(p->fns.GetCount() > 0)
    {
      解码类型
      engine_t e = s.Formats.GetEngine(p->fns.GetHead());
      如果是DirectShow  类型  只有.ram .rm .ra .qt .mov .ram 不需要
      fUseThread = e == DirectShow /*|| e == RealMedia || e == QuickTime*/;
    }
  }
  else if(OpenDeviceData* p = dynamic_cast<OpenDeviceData*>(pOMD.m_p))
  {
    fUseThread = false;
  }

   如果渲染线程存在 且 需要使用线程 且 需要打开工作线程
  if(m_pGraphThread && fUseThread&&AfxGetAppSettings().fEnableWorkerThreadForOpening)
    m_pGraphThread->PostThreadMessage(CGraphThread::TM_OPEN, 0, (LPARAM)pOMD.Detach());
  else
    OpenMediaPrivate(pOMD);
}

进入 CGraphThread::TM_OPEN 事件  用一个新的线程打开播放文件
void CGraphThread::OnOpen(WPARAM wParam, LPARAM lParam)
{
  if(m_pMainFrame)
  {
    CAutoPtr<OpenMediaData> pOMD((OpenMediaData*)lParam);
    m_pMainFrame->OpenMediaPrivate(pOMD);
  }
}

进入OpenMediaPrivate 分析
bool CMainFrame::OpenMediaPrivate(CAutoPtr<OpenMediaData> pOMD)
{
  CString err, aborted(_T("Aborted"));
  AppSettings& s = AfxGetAppSettings(); 获得设置信息

  {
    打开关闭锁
    CAutoLock mOpenCloseLock(&m_csOpenClose);
    s.bIsIVM = false;
    s.szCurrentExtension.Empty();

    如果状态不是关闭 且 不是正在加载  则出错
    一定要是加载状态 或是关闭状态
    if(m_iMediaLoadState != MLS_CLOSED && m_iMediaLoadState != MLS_LOADING)
    {
      ASSERT(0);
      return(false);
    }

    s.bExternalSubtitleTime = false;

    设置Slider
    m_wndSeekBar.SetRange(0, 100);

    记录
    s.szFGMLog.Empty();

    设置声道
    s.SetNumberOfSpeakers(s.iDecSpeakers , -1);

    正在加载状态
    m_iMediaLoadState = MLS_LOADING;

    2.5秒加载
    SetTimer(TIMER_LOADING, 2500, NULL); 

    不显示关闭
    // FIXME: Don't show "Closed" initially
    PostMessage(WM_KICKIDLE);              调用主线程更新的东西

    m_fUpdateInfoBar = false;

    try
    {
      打开终止 异常
      if(m_fOpeningAborted) throw aborted;

      if(OpenFileData* pOFD = dynamic_cast<OpenFileData*>(pOMD.m_p))
      {
        文件不存在异常
        if(pOFD->fns.IsEmpty()) throw ResStr(IDS_MSG_THROW_FILE_NOT_FOUND);

        CString fn = pOFD->fns.GetHead();

        取出格式
        s.szCurrentExtension = fn.Right(4).MakeLower();

        格式比较
        .ivm格式
        if(s.szCurrentExtension == _T(".ivm"))
          s.bIsIVM = true;

        s.bDisableSoftCAVCForce = false;
        
        .mkv格式
        if(!(s.useGPUAcel && s.bHasCUDAforCoreAVC) && !s.bDisableSoftCAVC 
             && s.szCurrentExtension == _T(".mkv"))
        {
          FILE* fp;
          if ( _wfopen_s( &fp, fn, _T("rb")) == 0)
          {
            char matchbuf[0x4000];
            size_t iRead = fread(matchbuf, sizeof( char ), 0x4000 ,fp);
            if( iRead > 200 && find_string_in_buf(matchbuf, iRead-100, "wpredp=2") > 0 )
              s.bDisableSoftCAVCForce = true;

            fclose(fp);
          }
        }

        int i = fn.Find(_T(":\\"));
        if(i > 0)
        {
          判断文件所在盘
          CString drive = fn.Left(i+2);
          UINT type = GetDriveType(drive);
          CAtlList<CString> sl;

           可移动的 驱动  
          if(type == DRIVE_REMOVABLE || type == DRIVE_CDROM && GetCDROMType(drive[0], sl) != CDROM_Audio)
          {
            int ret = IDRETRY;
            while(ret == IDRETRY)
            {
              WIN32_FIND_DATA findFileData;
              HANDLE h = FindFirstFile(fn, &findFileData);
              if(h != INVALID_HANDLE_VALUE)
              {
                FindClose(h);
                ret = IDOK;
              }
              else
              {
                CString msg;
                msg.Format(ResStr(IDS_MSG_WARN_NOT_FOUND_AND_PLS_INSERT_DISK), fn);
                ret = AfxMessageBox(msg, MB_RETRYCANCEL);
              }
            }

            if(ret != IDOK) throw aborted;
          }else{
            否则是本地盘  判断文件是否存在
            CSVPToolBox svpTool;
            if(!svpTool.ifFileExist(fn, true)){
              //SVP_LogMsg5(L"SVP 文件不存在" );
              throw ResStr(IDS_MSG_THROW_FILE_NOT_EXIST);
            }
          }
        }
      }

      打开终止异常
      if(m_fOpeningAborted) throw aborted;

      创建渲染对象  关键一
      OpenCreateGraphObject(pOMD);   待分析

      打开终止异常
      if(m_fOpeningAborted) throw aborted;

      m_pCAP2 = NULL;
      m_pCAP = NULL;
      m_pSVPSub = NULL;

      判断打开的文件的类型  待分析
      if(OpenFileData* p = dynamic_cast<OpenFileData*>(pOMD.m_p)) OpenFile(p);
      else if(OpenDVDData* p = dynamic_cast<OpenDVDData*>(pOMD.m_p)) OpenDVD(p);
      else if(OpenDeviceData* p = dynamic_cast<OpenDeviceData*>(pOMD.m_p)) OpenCapture(p);
      else throw _T("Can't open, invalid input parameters");

      查找相关接口
      pGB->FindInterface(__uuidof(ISubPicAllocatorPresenter), (void**)&m_pCAP, FALSE);
      pGB->FindInterface(__uuidof(ISubPicAllocatorPresenterRender), (void**)&m_pCAPR, TRUE);
      pGB->FindInterface(__uuidof(ISubPicAllocatorPresenter2), (void**)&m_pCAP2, TRUE);
      pGB->FindInterface(__uuidof(IVMRMixerControl9),(void**)&m_pMC,  TRUE);

       如果未找到 则用另外一种方法查找
      if(!m_pCAP){
        CComQIPtr<ISubPicAllocatorPresenter> pCAP =  FindFilter(__uuidof(CSVPSubFilter), pGB);
        if(pCAP){
          m_pCAP = pCAP;
          CComQIPtr<ISVPSubFilter> pSVPSub= pCAP;
          if(pSVPSub)
            m_pSVPSub = pSVPSub;
        }
      }

       如果找到 则进行相关操作
      if (m_pMC)
      {
        if (SetVMR9ColorControl(s.dBrightness, s.dContrast, s.dHue, s.dSaturation) == FALSE)
          OsdMsg_SetShader();
        else
        {
          CString  szMsg;
          szMsg.Format(ResStr(IDS_OSD_MSG_BRIGHT_CONTRAST_CHANGED), s.dBrightness, s.dContrast);
          SendStatusMessage(szMsg, 3000);
        }
        SetShaders(true);
      }

      // === EVR !
      pGB->FindInterface(__uuidof(IMFVideoDisplayControl), (void**)&m_pMFVDC,  TRUE);
      if (m_pMFVDC)
      {
        RECT Rect;
        ::GetClientRect (m_wndView.m_hWnd, &Rect);
        m_pMFVDC->SetVideoWindow (m_wndView.m_hWnd);
        m_pMFVDC->SetVideoPosition(NULL, &Rect);
      }

      打开终止异常
      if(m_fOpeningAborted) throw aborted;

      打开自定义大小的图像
      OpenCustomizeGraph();   待分析

      打开终止异常
      if(m_fOpeningAborted) throw aborted;

      打开初始化视频
      OpenSetupVideo();    待分析

      打开终止异常
      if(m_fOpeningAborted) throw aborted;

      打开初始化音频
      OpenSetupAudio();    待分析

      打开终止异常
      if(m_fOpeningAborted) throw aborted;

      打开终止异常
      if(m_fOpeningAborted) throw aborted;

      改变声道
      if(m_iAudioChannelMaping)
        OnAudioChannalMapMenu(IDS_AUDIOCHANNALMAPNORMAL+m_iAudioChannelMaping);  待分析

      加载完毕
      m_iMediaLoadState = MLS_LOADED;

      记录开始播放时间
      time(&m_tPlayStartTime);

      发送暂停消息
      PostMessage(WM_COMMAND, ID_PLAY_PAUSE);  待分析

      如果是打开  则发送播放消息
      if(!(AfxGetAppSettings().nCLSwitches&CLSW_OPEN))
        PostMessage(WM_COMMAND, ID_PLAY_PLAY);          待分析

      AfxGetAppSettings().nCLSwitches &= ~CLSW_OPEN;

      if(OpenFileData* p = dynamic_cast<OpenFileData*>(pOMD.m_p))
      {
        如果有记录 则跳到记录位置
        if(p->rtStart > 0)
          PostMessage(WM_RESUMEFROMSTATE, (WPARAM)PM_FILE, (LPARAM)(p->rtStart/10000)); // REFERENCE_TIME doesn't fit in LPARAM under a 32bit env.
      }
      else if(OpenDVDData* p = dynamic_cast<OpenDVDData*>(pOMD.m_p))
      {
        if(p->pDvdState)
          PostMessage(WM_RESUMEFROMSTATE, (WPARAM)PM_DVD, (LPARAM)(CComPtr<IDvdState>(p->pDvdState).Detach())); // must be released by the called message handler
      }
      else if(OpenDeviceData* p = dynamic_cast<OpenDeviceData*>(pOMD.m_p))
      {
        m_wndCaptureBar.m_capdlg.SetVideoInput(p->vinput);
        m_wndCaptureBar.m_capdlg.SetVideoChannel(p->vchannel);
        m_wndCaptureBar.m_capdlg.SetAudioInput(p->ainput);
      }

      进行加载字幕
      if(m_pCAP && (!m_fAudioOnly || m_fRealMediaGraph))
      {
        POSITION pos = pOMD->subs.GetHeadPosition();
        while(pos){ LoadSubtitle(pOMD->subs.GetNext(pos));}
      }

      当前进程是不是主线程
      if(::GetCurrentThreadId() == AfxGetApp()->m_nThreadID)
      {
        OnFilePostOpenmedia();
      }
      else
      {
        PostMessage(WM_COMMAND, ID_FILE_POST_OPENMEDIA);    待分析
      }

      初始化标题
      OpenSetupWindowTitle(pOMD->title);    待分析

      初始化打开时间
      time_t tOpening = time(NULL);

      当状态不是加载完成或正在加载 则循环  还在加载前则循环
      while(m_iMediaLoadState != MLS_LOADED 
        && m_iMediaLoadState != MLS_CLOSING // FIXME
        )
      {
        if( (time(NULL) - tOpening) > 10)
          throw aborted;
        Sleep(50);
      }
    }
    catch(LPCTSTR msg)
    {
      err = msg;
    }
    catch(CString msg)
    {
      err = msg;
    }
  }

  if(!err.IsEmpty())
  {
    存在错误
    SendStatusMessage(err, 3000);
    CloseMediaPrivate();
    m_closingmsg = err;

    OpenFileData* p = dynamic_cast<OpenFileData*>(pOMD.m_p);
    if(p && err != aborted)
    {
      m_wndPlaylistBar.SetCurValid(false);
      if(m_wndPlaylistBar.GetCount() > 1)
      {
        CPlaylistItem pli[2];
        m_wndPlaylistBar.GetCur(pli[0]);
        m_wndPlaylistBar.SetNext();
        m_wndPlaylistBar.GetCur(pli[1]);
        if(pli[0].m_id != pli[1].m_id)
        {
          //CAutoPtr<OpenMediaData> p(m_wndPlaylistBar.GetCurOMD());
          //if(p) OpenMediaPrivate(p);
        }
      }
    }
  }
  else
  {
    m_wndPlaylistBar.SetCurValid(true);  列表设置
  }

  调用主线程更新的东西
  PostMessage(WM_KICKIDLE); // calls main thread to update things  
  return(err.IsEmpty());
}

————————————————————————————————————————————
 2.5秒 循环载入
  case TIMER_LOADING:
    {
      KillTimer(TIMER_LOADING);
      if (IsSomethingLoading())
      {
        SetTimer( TIMER_LOADING , 1000, NULL);
        CString msg;
        if (m_fBuffering)
        {
          BeginEnumFilters(pGB, pEF, pBF)
          {
            if (CComQIPtr<IAMNetworkStatus, &IID_IAMNetworkStatus> pAMNS = pBF)
            {
              long BufferingProgress = 0;
              if (SUCCEEDED(pAMNS->get_BufferingProgress(&BufferingProgress)) && BufferingProgress > 0 && BufferingProgress < 99)
              {
                msg.Format(ResStr(IDS_CONTROLS_BUFFERING), BufferingProgress);
                SendStatusMessage(msg,1000);
                SVP_LogMsg5(msg);
              }
              break;
            }
          }
          EndEnumFilters
        }
        else if (pAMOP)
        {
          __int64 t = 0, c = 0;
          if (SUCCEEDED(pAMOP->QueryProgress(&t, &c)) && t > 0 && c < t)
          {
            msg.Format(ResStr(IDS_CONTROLS_BUFFERING), c*100/t);
            SendStatusMessage(msg,1000);
            SVP_LogMsg5(msg);
          }
        }
        else
          SendStatusMessage(ResStr(IDS_CONTROLS_OPENING), 1000);
      }
    }
    break;

   进入CMainFrame::OpenCreateGraphObject  分析
void CMainFrame::OpenCreateGraphObject(OpenMediaData* pOMD)
{
  解码接口不为空
  ASSERT(pGB == NULL);
  m_fCustomGraph = false;
  m_fRealMediaGraph = m_fShockwaveGraph = m_fQuicktimeGraph = false;

  AppSettings& s = AfxGetAppSettings();

  if(OpenFileData* p = dynamic_cast<OpenFileData*>(pOMD))
  {
    获得解码类型
    engine_t engine = s.Formats.GetEngine(p->fns.GetHead());

    std::wstring ct = ContentType::Get(p->fns.GetHead());

    if(ct == L"video/x-ms-asf")
    {
      // TODO: put something here to make the windows media source filter load later
    }
    else if (ct == L"audio/x-pn-realaudio"
      || ct == L"audio/x-pn-realaudio-plugin"
      || ct == L"audio/x-realaudio-secure"
      || ct == L"video/vnd.rn-realvideo-secure"
      || ct == L"application/vnd.rn-realmedia"
      || ct.find(L"vnd.rn-") != ct.npos
      || ct.find(L"realaudio") != ct.npos
      || ct.find(L"realvideo") != ct.npos)
    {
      // TODO: go fuck this!!!
      engine = RealMedia;
    }
    else if (ct == L"application/x-shockwave-flash")
    {
      engine = ShockWave;
    }
    else if (ct == L"video/quicktime"
      || ct == L"application/x-quicktimeplayer")
    {
      engine = QuickTime;
    }
    if (engine == RealMedia)
      engine = DirectShow;

    SVP_LogMsg5(L"got content type %s %d", ct.c_str(), engine );

    HRESULT hr;
    CComPtr<IUnknown> pUnk;

    if(engine == RealMedia)
    { 
      if(!(pUnk = (IUnknown*)(INonDelegatingUnknown*)new CRealMediaGraph(m_wndView.m_hWnd, hr)))
        throw _T("Out of memory");

      if(SUCCEEDED(hr) && !!(pGB = CComQIPtr<IGraphBuilder>(pUnk)))
        m_fRealMediaGraph = true;
    }
    else if(engine == ShockWave)
    {
      if(!(pUnk = (IUnknown*)(INonDelegatingUnknown*)new CShockwaveGraph(m_wndView.m_hWnd, hr)))
        throw _T("Out of memory");

      if(FAILED(hr) || !(pGB = CComQIPtr<IGraphBuilder>(pUnk)))
        throw _T("Can't create shockwave control");

      m_fShockwaveGraph = true;
    }
    else if(engine == QuickTime)
    {
      if(!(pUnk = (IUnknown*)(INonDelegatingUnknown*)new CQuicktimeGraph(m_wndView.m_hWnd, hr)))
        throw _T("Out of memory");

      if(SUCCEEDED(hr) && !!(pGB = CComQIPtr<IGraphBuilder>(pUnk)))
        m_fQuicktimeGraph = true;
    }

    m_fCustomGraph = m_fRealMediaGraph || m_fShockwaveGraph || m_fQuicktimeGraph;

    if(!m_fCustomGraph)
    {
      视频播放解码 生成接口
      pGB = new CFGManagerPlayer(_T("CFGManagerPlayer"), NULL, s.SrcFilters, s.TraFilters, m_wndView.m_hWnd);
    }
  }
  else if(OpenDVDData* p = dynamic_cast<OpenDVDData*>(pOMD))
  {
    pGB = new CFGManagerDVD(_T("CFGManagerDVD"), NULL, s.SrcFilters, s.TraFilters, m_wndView.m_hWnd);
  }
  else if(OpenDeviceData* p = dynamic_cast<OpenDeviceData*>(pOMD))
  {
    pGB = new CFGManagerCapture(_T("CFGManagerCapture"), NULL, s.SrcFilters, s.TraFilters, m_wndView.m_hWnd);
  }

  if(!pGB)
  {
    throw _T("Failed to create the filter graph object");
  }

  pGB->AddToROT();

  把视频解码接口赋值给其它
  pMC = pGB; pME = pGB; pMS = pGB; // general
  pVW = pGB; pBV = pGB; // video
  pBA = pGB; // audio
  pFS = pGB;

  if(!(pMC && pME && pMS)
    || !(pVW && pBV)
    || !(pBA))
  {
    throw ResStr(IDS_MSG_THROW_BROKEN_DIRECTX_SUPPORT);
  }

  发送WM_GRAPHNOTIFY 消息
  if(FAILED(pME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0)))
  {
    throw _T("Could not set target window for graph notification");
  }

  m_pProv = (IUnknown*)new CKeyProvider();   键盘提供者接口

  if(CComQIPtr<IObjectWithSite> pObjectWithSite = pGB)
    pObjectWithSite->SetSite(m_pProv);     键盘站点  捕获键盘消息


  m_pCB = new CDSMChapterBag(NULL, NULL); dstuil库中类
}

  进入OpenFile分析
void CMainFrame::OpenFile(OpenFileData* pOFD)
{
  if(pOFD->fns.IsEmpty())   文件为空  则抛出异常
    throw _T("Invalid argument");

  AppSettings& s = AfxGetAppSettings();  获得设置信息

  bool fFirst = true;

  POSITION pos = pOFD->fns.GetHeadPosition();
  while(pos)
  {
    CString fn = pOFD->fns.GetNext(pos);

    fn.Trim();
    if(fn.IsEmpty() && !fFirst)
      break;

    CString fnLower = fn;
    fnLower.MakeLower();

    HRESULT hr = -1;
    如果不是mms://路径或mmsh://路径
    if(FAILED(hr) && ( fnLower.Find(_T("mms://")) == 0 || fnLower.Find(_T("mmsh://")) == 0 )){ // 
      //render mms our own way
      hr = OpenMMSUrlStream(fn);
    }
    if(FAILED(hr))  渲染文件  持续了很长时间
      hr = pGB->RenderFile(CStringW(fn), NULL);  

    如果是网络文件  则大概网络流
    if(FAILED(hr) && ( fnLower.Find(_T("http") == 0 || fnLower.Find(_T("https://")) == 0
      || fnLower.Find(_T("udp://")) == 0 || fnLower.Find(_T("tcp://")) == 0)) ){ // 
        //render mms our own way
        hr = OpenMMSUrlStream(fn);
    }

    /* not sure why this is not work for http youku etc  不知道这是为什么不适用于HTTP优酷等
    HRESULT hr = -1;
    if( ( fn.MakeLower().Find(_T("mms://")) == 0 || fn.MakeLower().Find(_T("mmsh://")) == 0 || (fn.MakeLower().Find(_T("http:")) == 0 && fn.MakeLower().Find(_T(":8902")) > 0 ))){ 
    //render mms our own way 
    hr = OpenMMSUrlStream(fn);
    }

    if(FAILED(hr))
    hr = pGB->RenderFile(CStringW(fn), NULL);
    */

    依然失败 则寻找错误  记录错误
    if(FAILED(hr))
    {
      if(fFirst)
      {
        //if(s.fReportFailedPins)
        {
          CComQIPtr<IGraphBuilderDeadEnd> pGBDE = pGB;
          if(pGBDE && pGBDE->GetCount()) CMediaTypesDlg(pGBDE, this).DoModal();
        }

        CString err;

        switch(hr)
        {
        case E_ABORT: err = ResStr(IDS_MSG_THROW_OPRATION_CANCELED); break;
        case E_FAIL: case E_POINTER: default: 
          err.Format(ResStr(IDS_MSG_THROW_UNABLE_OPEN_FILE) , hr);
          break;
        case E_INVALIDARG: err = ResStr(IDS_MSG_THROW_ILLEGE_FILENAME); break;
        case E_OUTOFMEMORY: err = ResStr(IDS_MSG_THROW_OUTOF_MEMORY); break;
        case VFW_E_CANNOT_CONNECT: err = ResStr(IDS_MSG_THROW_UNABLE_DECODE); break;
        case VFW_E_CANNOT_LOAD_SOURCE_FILTER: err = ResStr(IDS_MSG_THROW_UNSUPPORT_SOURCE); break;
        case VFW_E_CANNOT_RENDER: err = ResStr(IDS_MSG_THROW_FAIL_CREATE_RENDER); break;
        case VFW_E_INVALID_FILE_FORMAT: err = _T("Invalid file format"); break;
        case VFW_E_NOT_FOUND: err = ResStr(IDS_MSG_THROW_FILE_NOT_FOUND); break;
        case VFW_E_UNKNOWN_FILE_TYPE: err = ResStr(IDS_MSG_THROW_UNKNOWN_FILE_TYPE); break;
        case VFW_E_UNSUPPORTED_STREAM: err = ResStr(IDS_MSG_THROW_UNSUPPORT_STREAM_TYPE); break;
        }

        throw err;
      }
    }

    是否保存记录
    if(s.fKeepHistory)
    {
      if(this->m_lastUrl == fn){   本次与上次是否相同
        CRecentFileList* pMRU = &s.MRUUrl;
        pMRU->ReadList();
        pMRU->Add(fn);
        pMRU->WriteList();
        this->m_lastUrl.Empty();
      }else{
        不同则写入
        CRecentFileList* pMRU = fFirst ? &s.MRU : &s.MRUDub;
        pMRU->ReadList();
        pMRU->Add(fn);
        pMRU->WriteList();
      }
    }

    if(fFirst)  第一次运行? 搜索字幕
    {
      AppSettings& s = AfxGetAppSettings();
      pOFD->title = fn;
      m_fnCurPlayingFile = fn;
      //是否有字幕? 沒有则下载字幕
      CSVPToolBox svpTool;
      //搜索目录下同名字幕
      CAtlArray<CString> subSearchPaths;
      subSearchPaths.Add(_T("."));
      subSearchPaths.Add(s.GetSVPSubStorePath());
      subSearchPaths.Add(svpTool.GetPlayerPath(L"SVPSub"));
      subSearchPaths.Add(_T(".\\subtitles"));
      subSearchPaths.Add(_T(".\\Subs"));
      subSearchPaths.Add(_T("c:\\subtitles"));

      CAtlArray<SubFile> ret;

      POSITION pos = pOFD->subs.GetHeadPosition();
      while(pos){
        POSITION cur = pos;
        CString szSubFn = pOFD->subs.GetNext(pos);
        if(!svpTool.ifFileExist(szSubFn))
          pOFD->subs.RemoveAt(cur);
      }
      CSVPRarLib svpRar;
      if( svpRar.SplitPath(fn) ){
        GetSubFileNames(svpRar.m_fnRAR, subSearchPaths, ret);
        CAtlArray<SubFile> ret2;
        GetSubFileNames(svpRar.m_fnInsideRar, subSearchPaths, ret2);
        ret.Append(ret2);
      }else{
        GetSubFileNames(fn, subSearchPaths, ret);
        //AfxMessageBox(fn);
      }
      for(int i = 0; i < ret.GetCount(); i++){
        SubFile szBuf = ret.GetAt(i);
        //AfxMessageBox(szBuf.fn);
        if ( pOFD->subs.Find( szBuf.fn ) == NULL && svpTool.ifFileExist(szBuf.fn)){
          pOFD->subs.AddTail(szBuf.fn);
          //AfxMessageBox(szBuf.fn);
        }
      }
      //AfxMessageBox(_T("1"));
      if ( pOFD->subs.GetCount() <= 0){
        // AfxMessageBox(_T("2"));




        if(s.autoDownloadSVPSub){
          CPath fPath(fn);
          CString szExt;
          szExt.Format(_T(" %s;"),fPath.GetExtension());
          if(s.CheckSVPSubExts.Find(szExt) >= 0 ){
            SVPSubDownloadByVPath(fn);
          }else{
            //SendStatusMessage(  _T("正在播放的文件类型看来不需要字幕,终止自动智能匹配"), 1000);
          }
        }
      }
    }
    fFirst = false;

    if(m_fCustomGraph) break;
  }   智能匹配字幕结束

  //if(s.fReportFailedPins)
  {  如果绘图挂了 类型对话框弹出
    CComQIPtr<IGraphBuilderDeadEnd> pGBDE = pGB;
    if(pGBDE && pGBDE->GetCount()) CMediaTypesDlg(pGBDE, this).DoModal();
  }   

  if(!(pAMOP = pGB))
  {
    BeginEnumFilters(pGB, pEF, pBF)
      if(pAMOP = pBF) break;
    EndEnumFilters
  }

  if(FindFilter(__uuidof(CShoutcastSource), pGB))
    m_fUpdateInfoBar = true;

  SetupChapters();  初始化章节

  枚举 寻找IKeyFrameInfo 接口
  CComQIPtr<IKeyFrameInfo> pKFI;
  BeginEnumFilters(pGB, pEF, pBF)
    if(pKFI = pBF) break;
  EndEnumFilters
    UINT nKFs = 0, nKFsTmp = 0;
  if(pKFI && S_OK == pKFI->GetKeyFrameCount(nKFs) && nKFs > 0)
  {
    m_kfs.SetCount(nKFsTmp = nKFs);
    if(S_OK != pKFI->GetKeyFrames(&TIME_FORMAT_MEDIA_TIME, m_kfs.GetData(), nKFsTmp) || nKFsTmp != nKFs)
      m_kfs.RemoveAll();
  }

  m_iPlaybackMode = PM_FILE;
}

进入SetupChapters() 初始化章节
void CMainFrame::SetupChapters()
{
  ASSERT(m_pCB); 解码不为空

  m_pCB->ChapRemoveAll();

  查找过滤接口  并添加到pBFs
  CInterfaceList<IBaseFilter> pBFs;
  BeginEnumFilters(pGB, pEF, pBF) 
    pBFs.AddTail(pBF);
  EndEnumFilters
  
    POSITION pos;

  循环遍历过滤接口 进行追加操作 具体什么 待分析
  pos = pBFs.GetHeadPosition();
  while(pos && !m_pCB->ChapGetCount())
  {
    IBaseFilter* pBF = pBFs.GetNext(pos);

    CComQIPtr<IDSMChapterBag> pCB = pBF;
    if(!pCB) continue;

    for(DWORD i = 0, cnt = pCB->ChapGetCount(); i < cnt; i++)
    {
      REFERENCE_TIME rt;
      CComBSTR name;
      if(SUCCEEDED(pCB->ChapGet(i, &rt, &name)))
        m_pCB->ChapAppend(rt, name);
    }
  }

  循环遍历过滤接口 进行追加操作 具体什么 待分析
  pos = pBFs.GetHeadPosition();
  while(pos && !m_pCB->ChapGetCount())
  {
    IBaseFilter* pBF = pBFs.GetNext(pos);

    CComQIPtr<IChapterInfo> pCI = pBF;
    if(!pCI) continue;

    CHAR iso6391[3];
    ::GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, iso6391, 3);
    CStringA iso6392 = ISO6391To6392(iso6391);
    if(iso6392.GetLength() < 3) iso6392 = "eng";

    UINT cnt = pCI->GetChapterCount(CHAPTER_ROOT_ID);
    for(UINT i = 1; i <= cnt; i++)
    {
      UINT cid = pCI->GetChapterId(CHAPTER_ROOT_ID, i);

      ChapterElement ce;
      if(pCI->GetChapterInfo(cid, &ce))
      {
        char pl[3] = {iso6392[0], iso6392[1], iso6392[2]};
        char cc[] = "  ";
        CComBSTR name;
        name.Attach(pCI->GetChapterStringInfo(cid, pl, cc));
        m_pCB->ChapAppend(ce.rtStart, name);
      }
    }
  }

  循环遍历过滤接口 进行追加操作 具体什么 待分析
  pos = pBFs.GetHeadPosition();
  while(pos && !m_pCB->ChapGetCount())
  {
    IBaseFilter* pBF = pBFs.GetNext(pos);

    CComQIPtr<IAMExtendedSeeking, &IID_IAMExtendedSeeking> pES = pBF;
    if(!pES) continue;

    long MarkerCount = 0;
    if(SUCCEEDED(pES->get_MarkerCount(&MarkerCount)))
    {
      for(long i = 1; i <= MarkerCount; i++)
      {
        double MarkerTime = 0;
        if(SUCCEEDED(pES->GetMarkerTime(i, &MarkerTime)))
        {
          CStringW name;
          name.Format(L"Chapter %d", i);

          CComBSTR bstr;
          if(S_OK == pES->GetMarkerName(i, &bstr))
            name = bstr;

          m_pCB->ChapAppend(REFERENCE_TIME(MarkerTime*10000000), name);
        }
      }
    }
  }

  循环遍历过滤接口 进行追加操作 具体什么 待分析
  pos = pBFs.GetHeadPosition();
  while(pos && !m_pCB->ChapGetCount())
  {
    IBaseFilter* pBF = pBFs.GetNext(pos);

    if(GetCLSID(pBF) != CLSID_OggSplitter)
      continue;

    BeginEnumPins(pBF, pEP, pPin)
    {
      if(m_pCB->ChapGetCount()) break;

      if(CComQIPtr<IPropertyBag> pPB = pPin)
      {
        for(int i = 1; ; i++)
        {
          CStringW str;
          CComVariant var;

          var.Clear();
          str.Format(L"CHAPTER%02d", i);
          if(S_OK != pPB->Read(str, &var, NULL)) 
            break;
          int h, m, s, ms;
          WCHAR wc;
          if(7 != swscanf(CStringW(var), L"%d%c%d%c%d%c%d", &h, &wc, &m, &wc, &s, &wc, &ms)) 
            break;
          CStringW name;
          name.Format(L"Chapter %d", i);
          var.Clear();
          str += L"NAME";
          if(S_OK == pPB->Read(str, &var, NULL))
            name = var;
          m_pCB->ChapAppend(10000i64*(((h*60 + m)*60 + s)*1000 + ms), name);
        }
      }
    }
    EndEnumPins
  }
  m_pCB->ChapSort();
}

   进入OpenCustomizeGraph  自定义图像大小
void CMainFrame::OpenCustomizeGraph()
{
  总共有enum {PM_NONE, PM_FILE, PM_DVD, PM_CAPTURE}种模式

  PM_CAPTURE 模式 不支持自定义图像大小
  if(m_iPlaybackMode == PM_CAPTURE)    return;

  CleanGraph();   清楚画像

  if(m_iPlaybackMode == PM_FILE)  文件模式
  {
    if(m_pCAP) {
      if(AfxGetAppSettings().fAutoloadSubtitles) {
        AddTextPassThruFilter();    进行了很多连接  需要分析
      }
    }
  }
  
  同步视频
  AppSettings& s = AfxGetAppSettings();
  if (s.m_RenderSettings.bSynchronizeVideo)
  {
    HRESULT hr;
    m_pRefClock = DNew CSyncClockFilter(NULL, &hr);
    CStringW name;
    name.Format(L"SyncClock Filter");
    pGB->AddFilter(m_pRefClock, name);

    CComPtr<IReferenceClock> refClock;
    m_pRefClock->QueryInterface(IID_IReferenceClock, reinterpret_cast<void**>(&refClock));
    CComPtr<IMediaFilter> mediaFilter;
    pGB->QueryInterface(IID_IMediaFilter, reinterpret_cast<void**>(&mediaFilter));
    mediaFilter->SetSyncSource(refClock);
    mediaFilter = NULL;
    refClock = NULL;

    m_pRefClock->QueryInterface(IID_ISyncClock, reinterpret_cast<void**>(&m_pSyncClock));
  }

  BeginEnumFilters(pGB, pEF, pBF)
  {
    查找CLSID_OggSplitter 控件
    if(GetCLSID(pBF) == CLSID_OggSplitter)
    {
       查找IAMStreamSelect接口
      if(CComQIPtr<IAMStreamSelect> pSS = pBF)
      {
        LCID idAudio = AfxGetAppSettings().idAudioLang;
        if(!idAudio) idAudio = GetUserDefaultLCID();
        LCID idSub = AfxGetAppSettings().idSubtitlesLang;
        if(!idSub) idSub = GetUserDefaultLCID();

        DWORD cnt = 0;
        pSS->Count(&cnt);
        for(DWORD i = 0; i < cnt; i++)
        {
          AM_MEDIA_TYPE* pmt = NULL;
          DWORD dwFlags = 0;
          LCID lcid = 0;
          DWORD dwGroup = 0;
          WCHAR* pszName = NULL;
          if(SUCCEEDED(pSS->Info((long)i, &pmt, &dwFlags, &lcid, &dwGroup, &pszName, NULL, NULL)))
          {
            CStringW name(pszName), sound(L"Sound"), subtitle(L"Subtitle");

            if(idAudio != -1 && (idAudio&0x3ff) == (lcid&0x3ff) // sublang seems to be zeroed out in ogm...
              && name.GetLength() > sound.GetLength()
              && !name.Left(sound.GetLength()).CompareNoCase(sound))
            {
              if(SUCCEEDED(pSS->Enable(i, AMSTREAMSELECTENABLE_ENABLE)))
                idAudio = -1;
            }

            if(idSub != -1 && (idSub&0x3ff) == (lcid&0x3ff) // sublang seems to be zeroed out in ogm...
              && name.GetLength() > subtitle.GetLength()
              && !name.Left(subtitle.GetLength()).CompareNoCase(subtitle)
              && name.Mid(subtitle.GetLength()).Trim().CompareNoCase(L"off"))
            {
              if(SUCCEEDED(pSS->Enable(i, AMSTREAMSELECTENABLE_ENABLE)))
                idSub = -1;
            }

            if(pmt) DeleteMediaType(pmt);
            if(pszName) CoTaskMemFree(pszName);
          }
        }
      }
    }
  }
  EndEnumFilters

    CleanGraph();
}

 进入OpenSetupVideo() 初始化视频
void CMainFrame::OpenSetupVideo()
{
  只自动?
  m_fAudioOnly = true;

  if (m_pMFVDC) // EVR 
  {
    EVR  不支持
    m_fAudioOnly = false;
  }
  else if(m_pCAPR)
  {
     获得视频大小
    CSize vs = m_pCAPR->GetVideoSize();
    m_fAudioOnly = (vs.cx <= 0 || vs.cy <= 0);
  }
  else
  {
    否则其它
    {
      long w = 0, h = 0;

      if(CComQIPtr<IBasicVideo> pBV = pGB)
      {
        pBV->GetVideoSize(&w, &h);
      }

      if(w > 0 && h > 0)
      {
        m_fAudioOnly = false;
      }
    }

    if(m_fAudioOnly)
    {
      BeginEnumFilters(pGB, pEF, pBF)
      {
        long w = 0, h = 0;


        if(CComQIPtr<IVideoWindow> pVW = pBF)
        {
          long lVisible;
          if(FAILED(pVW->get_Visible(&lVisible)))
            continue;

          pVW->get_Width(&w);
          pVW->get_Height(&h);
        }

        if(w > 0 && h > 0)
        {
          m_fAudioOnly = false;
          break;
        }
      }
      EndEnumFilters
    }
  }

  if(m_fShockwaveGraph)  flash控件
  {
    m_fAudioOnly = false;
  }

  if(m_pCAP)
  {
    SetShaders();
  }
  // else
  {
    // TESTME

    pVW->put_Owner((OAHWND)m_wndView.m_hWnd);
    pVW->put_WindowStyle(WS_CHILD|WS_CLIPSIBLINGS|WS_CLIPCHILDREN);
    pVW->put_MessageDrain((OAHWND)m_hWnd);

    for(CWnd* pWnd = m_wndView.GetWindow(GW_CHILD); pWnd; pWnd = pWnd->GetNextWindow())
      pWnd->EnableWindow(FALSE); // little trick to let WM_SETCURSOR thru
  }
}

 进入SetShaders( BOOL silent )  设置着色
void CMainFrame::SetShaders( BOOL silent )
{
  if(!m_pCAPR) return;   不存在则直接返回

  AppSettings& s = AfxGetAppSettings();

  CAtlStringMap<const AppSettings::Shader*> s2s;

  POSITION pos = s.m_shaders.GetHeadPosition();
  while(pos)
  {
    const AppSettings::Shader* pShader = &s.m_shaders.GetNext(pos); 关键取值
    s2s[pShader->label] = pShader;
  }
  if(!silent){
    m_pCAPR->SetPixelShader(NULL, NULL);
    if (m_pCAP2)
      m_pCAP2->SetPixelShader2(NULL, NULL, true);
  }

  CAtlList<CString> labels;

  pos = m_shaderlabels.GetHeadPosition();
  while(pos)
  {
    const AppSettings::Shader* pShader = NULL;
    if(s2s.Lookup(m_shaderlabels.GetNext(pos), pShader))
    {
      CStringA target = pShader->target;
      CStringA srcdata = pShader->srcdata;

      HRESULT hr = m_pCAPR->SetPixelShader(srcdata, target );

      if(FAILED(hr))
      {
        //m_pCAP->SetPixelShader(NULL, NULL);
        if (m_pCAP2)
          hr = m_pCAP2->SetPixelShader2(srcdata, target, true);
        if(FAILED(hr)){
          // if (m_pCAP2)
          // m_pCAP2->SetPixelShader2(NULL, NULL, true,  !silent);
          if(!silent)
          {
            CString label = pShader->label;
            OsdMsg_SetShader(&label);
          }
        }
        return;
      }
      labels.AddTail(pShader->label);
    }
  }

  if(m_iMediaLoadState == MLS_LOADED)
  {
    CString str = Implode(labels, '|');
    str.Replace(_T("|"), _T(", "));
    if(!silent) SendStatusMessage(_T("Shader: ") + str, 3000);
  }
  if(!silent){
    if (SetVMR9ColorControl(s.dBrightness , s.dContrast, 0, 0, true) == FALSE)
      OsdMsg_SetShader();
  }
}

  进入OpenSetupAudio()  初始化音频
void CMainFrame::OpenSetupAudio()
{
  赋值
  pBA->put_Volume(m_wndToolBar.Volume);

  // FIXME
  // 又是从设置中取得数据
  int balance = AfxGetAppSettings().nBalance;
  int sign = balance>0?-1:1;
  balance = max(100-abs(balance), 1);
  balance = (int)((log10(1.0*balance)-2)*5000*sign);
  balance = max(min(balance, 10000), -10000);
  pBA->put_Balance(balance);
}

  进入CMainFrame::OpenSetupWindowTitle 初始化标题
void CMainFrame::OpenSetupWindowTitle(CString fn)
{
  CString title(MAKEINTRESOURCE(IDR_MAINFRAME));

  AppSettings& s = AfxGetAppSettings();

  int i = s.iTitleBarTextStyle;

  if(!fn.IsEmpty() && (i == 0 || i == 1))
  {
    if(i == 1)
    {
      if(m_iPlaybackMode == PM_FILE)
      {
        fn.Replace('\\', '/');
        CString fn2 = fn.Mid(fn.ReverseFind('/')+1);
        if(!fn2.IsEmpty()) fn = fn2;

        if(s.fTitleBarTextTitle)
        {
          BeginEnumFilters(pGB, pEF, pBF)
          {
            if(CComQIPtr<IAMMediaContent, &IID_IAMMediaContent> pAMMC = pBF)
            {
              CComBSTR bstr;
              if(SUCCEEDED(pAMMC->get_Title(&bstr)) && bstr.Length())
              {
                fn = CString(bstr.m_str);
                break;
              }
            }
          }
          EndEnumFilters
        }
      }
      else if(m_iPlaybackMode == PM_DVD)
      {
        fn = _T("DVD");
      }
      else if(m_iPlaybackMode == PM_CAPTURE)
      {
        fn = _T("Live");
      }
    }
    title = fn + _T(" - ") + title;
  }
  //CString szBuild;
  //szBuild.Format(_T(" (Build %s)"),SVP_REV_STR);
  //title += szBuild;
  //SetWindowText(title);
  m_szTitle = title;
  RedrawNonClientArea();
}

在OpenMediaPrivate()中
PostMessage(WM_COMMAND, ID_PLAY_PAUSE);
if(!(AfxGetAppSettings().nCLSwitches&CLSW_OPEN))
        PostMessage(WM_COMMAND, ID_PLAY_PLAY);

 紧紧只是更新UI?
ON_UPDATE_COMMAND_UI(ID_PLAY_PLAY, OnUpdatePlayPauseStop)

   进入OnUpdatePlayPauseStop 分析
void CMainFrame::OnUpdatePlayPauseStop(CCmdUI* pCmdUI)
{
  OAFilterState fs = m_fFrameSteppingActive ? State_Paused : GetMediaState();

  UI消息
  pCmdUI->SetCheck(fs == State_Running && pCmdUI->m_nID == ID_PLAY_PLAY
    || fs == State_Paused && pCmdUI->m_nID == ID_PLAY_PAUSE
    || fs == State_Stopped && pCmdUI->m_nID == ID_PLAY_STOP
    || (fs == State_Paused || fs == State_Running) && pCmdUI->m_nID == ID_PLAY_PLAYPAUSE);

  bool fEnable = false;

  if(fs >= 0)
  {
    if(m_iPlaybackMode == PM_FILE || m_iPlaybackMode == PM_CAPTURE)
    {
      fEnable = true;

      不能进入暂停状态,从停止使用rm
      if(fs == State_Stopped && pCmdUI->m_nID == ID_PLAY_PAUSE && m_fRealMediaGraph) fEnable = false; // can't go into paused state from stopped with rm
      else if(m_fCapturing) fEnable = false;
      else if(m_fLiveWM && pCmdUI->m_nID == ID_PLAY_PAUSE) fEnable = false;
    }
    else if(m_iPlaybackMode == PM_DVD)
    {
      fEnable = m_iDVDDomain != DVD_DOMAIN_VideoManagerMenu 
        && m_iDVDDomain != DVD_DOMAIN_VideoTitleSetMenu;

      if(fs == State_Stopped && pCmdUI->m_nID == ID_PLAY_PAUSE) fEnable = false;
    }
  }
  if(pCmdUI->m_nID == ID_PLAY_PLAY || pCmdUI->m_nID == ID_PLAY_PLAYPAUSE) fEnable = true;
  pCmdUI->Enable(fEnable);
}

ON_COMMAND(ID_PLAY_PAUSE, OnPlayPause)
void CMainFrame::OnPlayPause()
//支持ffdshow的排队。
//为了避免暂停黑掉,我们以锁定g_ffdshowReceive同步与ReceiveMine的。
void CMainFrame::OnPlayPause()
{
  // Support ffdshow queueing.
  // To avoid black out on pause, we have to lock g_ffdshowReceive to synchronize with ReceiveMine.
  time(&m_tPlayPauseTime);
  if(queueu_ffdshow_support)
  {
    CAutoLock lck(&g_ffdshowReceive);
    return OnPlayPauseI();
  }
  OnPlayPauseI();
}

  进入OnPlayPauseI()分析
void CMainFrame::OnPlayPauseI()
{
  if(m_iMediaLoadState == MLS_LOADED)   已经加载
  {
    if(m_iPlaybackMode == PM_FILE)
    {
      pMC->Pause();   停止
    }
    else if(m_iPlaybackMode == PM_DVD)
    {
      pMC->Pause();
    }
    else if(m_iPlaybackMode == PM_CAPTURE)
    {
      pMC->Pause();
    } 

    SetTimer(TIMER_STREAMPOSPOLLER, 40, NULL);
    SetTimer(TIMER_STREAMPOSPOLLER2, 500, NULL);
    SetTimer(TIMER_STATS, 1000, NULL);

    KillTimer(TIMER_IDLE_TASK);
    SetTimer(TIMER_IDLE_TASK, 30000, NULL);

    SetAlwaysOnTop(AfxGetAppSettings().iOnTop);  设置置顶
  }
  MoveVideoWindow();
}

    移动视频窗体
void CMainFrame::MoveVideoWindow(bool fShowStats)
{
   视频已经加载  不是自动  窗体可见
  if(m_iMediaLoadState == MLS_LOADED && !m_fAudioOnly && IsWindowVisible())
  {
    AppSettings &s = AfxGetAppSettings();
    CRect wr;

    if(!m_fFullScreen && (s.bUserAeroUI() || (!s.bUserAeroUI() && ( s.nCS & CS_TOOLBAR ))) )
    {
      m_wndView.GetClientRect(wr);
    }
    else
    {
      GetWindowRect(&wr);
      // HACK
      CRect r;
      m_wndView.GetWindowRect(&r);
      wr -= r.TopLeft();
    }
    CRect vr = CRect(0,0,0,0);

    OAFilterState fs = GetMediaState();
    if(fs == State_Paused || fs == State_Running || fs == State_Stopped && (m_fShockwaveGraph || m_fQuicktimeGraph))
    {
      CSize arxy = GetVideoSize();

      int iDefaultVideoSize = AfxGetAppSettings().iDefaultVideoSize;

      CSize ws = 
        iDefaultVideoSize == DVS_HALF ? CSize(arxy.cx/2, arxy.cy/2) :
        iDefaultVideoSize == DVS_NORMAL ? arxy :
        iDefaultVideoSize == DVS_DOUBLE ? CSize(arxy.cx*2, arxy.cy*2) :
        wr.Size();

      int w = ws.cx;
      int h = ws.cy;

      if(!m_fShockwaveGraph) //&& !m_fQuicktimeGraph)
      {
        if(iDefaultVideoSize == DVS_FROMINSIDE || iDefaultVideoSize == DVS_FROMOUTSIDE)
        {
          h = ws.cy;
          w = MulDiv(h, arxy.cx, arxy.cy);

          if(iDefaultVideoSize == DVS_FROMINSIDE && w > ws.cx
            || iDefaultVideoSize == DVS_FROMOUTSIDE && w < ws.cx)
          {
            w = ws.cx;
            h = MulDiv(w, arxy.cy, arxy.cx);
          }
        }
      }

      CSize size(
        (int)(m_ZoomX*w), 
        (int)(m_ZoomY*h));

      CPoint pos(
        (int)(m_PosX*(wr.Width()*3 - m_ZoomX*w) - wr.Width()), 
        (int)(m_PosY*(wr.Height()*3 - m_ZoomY*h) - wr.Height()));

      /* CPoint pos(
      (int)(m_PosX*(wr.Width() - size.cx)), 
      (int)(m_PosY*(wr.Height() - size.cy)));


      */
      vr = CRect(pos, size);
    }

    wr |= CRect(0,0,0,0);
    vr |= CRect(0,0,0,0);

    //CString szLog;
    //szLog.Format(_T("WVSize3 %d %d %d %d %d %d %d "), wr.Width(), wr.Height(), vr.Width(), vr.Height(), m_AngleX , m_AngleY , m_AngleZ);
    //SVP_LogMsg(szLog);
    if(m_pCAPR)
    {
      m_pCAPR->SetPosition(wr, vr);
      m_pCAPR->SetVideoAngle(Vector(DegToRad(m_AngleX), DegToRad(m_AngleY), DegToRad(m_AngleZ)));
    }
    else
    {
      HRESULT hr;
      hr = pBV->SetDefaultSourcePosition();
      hr = pBV->SetDestinationPosition(vr.left, vr.top, vr.Width(), vr.Height());
      hr = pVW->SetWindowPosition(wr.left, wr.top, wr.Width(), wr.Height());

      if (m_pMFVDC) m_pMFVDC->SetVideoPosition (NULL, wr);
    }
    //SVP_LogMsg5(_T("MoveVideoWindow %d ") , wr.Height());
    m_wndView.SetVideoRect(wr);

    if(fShowStats && vr.Height() > 0)
    {
      CString info(L"正在使用智能拖拽功能。可在画面右上角进行拖拽");
      // info.Format(_T("Pos %.2f %.2f, Zoom %.2f %.2f, AR %.2f"), m_PosX, m_PosY, m_ZoomX, m_ZoomY, (float)vr.Width()/vr.Height());
      SendStatusMessage(info, 3000);
    }
  }
  else
  {
    m_wndView.SetVideoRect();
  }

  CRect r;
  m_wndView.GetClientRect(r);
  if(m_iMediaLoadState == MLS_LOADED){
    float fViewRatio = (float)r.Width() / r.Height();
    CSize vsize = GetVideoSize();
    float fVideoRatio = (float)vsize.cx / vsize.cy;
    m_fScreenHigherThanVideo = (fViewRatio < fVideoRatio );
  }
}

  仅仅只是更新UI
void CMainFrame::OnUpdatePlayPauseStop(CCmdUI* pCmdUI)
{
  OAFilterState fs = m_fFrameSteppingActive ? State_Paused : GetMediaState();

  pCmdUI->SetCheck(fs == State_Running && pCmdUI->m_nID == ID_PLAY_PLAY
    || fs == State_Paused && pCmdUI->m_nID == ID_PLAY_PAUSE
    || fs == State_Stopped && pCmdUI->m_nID == ID_PLAY_STOP
    || (fs == State_Paused || fs == State_Running) && pCmdUI->m_nID == ID_PLAY_PLAYPAUSE);

  bool fEnable = false;

  if(fs >= 0)
  {
    if(m_iPlaybackMode == PM_FILE || m_iPlaybackMode == PM_CAPTURE)
    {
      fEnable = true;

      if(fs == State_Stopped && pCmdUI->m_nID == ID_PLAY_PAUSE && m_fRealMediaGraph) fEnable = false; // can't go into paused state from stopped with rm
      else if(m_fCapturing) fEnable = false;
      else if(m_fLiveWM && pCmdUI->m_nID == ID_PLAY_PAUSE) fEnable = false;
    }
    else if(m_iPlaybackMode == PM_DVD)
    {
      fEnable = m_iDVDDomain != DVD_DOMAIN_VideoManagerMenu 
        && m_iDVDDomain != DVD_DOMAIN_VideoTitleSetMenu;

      if(fs == State_Stopped && pCmdUI->m_nID == ID_PLAY_PAUSE) fEnable = false;
    }
  }
  if(pCmdUI->m_nID == ID_PLAY_PLAY || pCmdUI->m_nID == ID_PLAY_PLAYPAUSE) fEnable = true;
  pCmdUI->Enable(fEnable);
}

// play 播放事件
void CMainFrame::OnPlayPlay()
{
  if(m_iMediaLoadState == MLS_LOADED) 必须载入
  {
    if(GetMediaState() == State_Stopped) {  m_iSpeedLevel = 0; time(&m_tPlayStartTime);} 记录
    try
    {
      if(m_iPlaybackMode == PM_FILE)  文件格式
      {
        time_t ttNow;
        time(&ttNow);
        if( m_tPlayPauseTime > m_tPlayStartTime){
          m_tPlayStartTime += (ttNow - m_tPlayPauseTime);
        }
        if(m_fEndOfStream){   如果文件流没有 则停止
          SendMessage(WM_COMMAND, ID_PLAY_STOP);
          Sleep(1500);
        }
        pMC->Run();   运行
      }
      else if(m_iPlaybackMode == PM_DVD) DVD格式
      {
        double dRate = 1.0;
        //if(m_iSpeedLevel != -4 && m_iSpeedLevel != 0)
        // dRate = pow(2.0, m_iSpeedLevel >= -3 ? m_iSpeedLevel : (-m_iSpeedLevel - 8));
        dRate = 1.0 + m_iSpeedLevel * 0.1;
        pDVDC->PlayForwards(dRate, DVD_CMD_FLAG_Block, NULL);
        pDVDC->Pause(FALSE);
        pMC->Run();
      }
      else if(m_iPlaybackMode == PM_CAPTURE)  CAPTURE 格式
      { 
        pMC->Stop(); // audio preview won't be in sync if we run it from paused state
        pMC->Run();
      }
    }
    catch (...)
    {
      SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA);  异常 就关闭视频
      return;
    }
    SetTimer(TIMER_STREAMPOSPOLLER, 40, NULL);  位置信息
    SetTimer(TIMER_STREAMPOSPOLLER2, 500, NULL);  位置2信息
    SetTimer(TIMER_STATS, 1000, NULL);   状态信息

    if(m_fFrameSteppingActive) // FIXME   第一次  设置声音
    {
      m_fFrameSteppingActive = false;
      pBA->put_Volume(m_VolumeBeforeFrameStepping);
    }

    SetAlwaysOnTop(AfxGetAppSettings().iOnTop);   置顶
    m_wndColorControlBar.CheckAbility();   控件状态位置等信息
    MoveVideoWindow();   移动视频
  }else if(m_iMediaLoadState == MLS_CLOSED){  如果是关闭状态 则重新播放
    if(m_WndSizeInited >= 2){
      if(m_wndPlaylistBar.GetCount()){
        OpenCurPlaylistItem();
        //}else
        // SendMessage(WM_COMMAND, ID_FILE_OPENMEDIA);
      }
    }
  }
  //KillTimer(TIMER_SNAP);
  //SetTimer(TIMER_SNAP, 10000, NULL);
}

  进入OnFilePostOpenmedia() 分析
void CMainFrame::OnFilePostOpenmedia()
{
  OpenSetupClipInfo();  初始化剪切板信息
  //A-B Control
  m_aRefTime = 0;
  m_bRefTime = 0;
  ABControlOn = FALSE;

  OpenSetupCaptureBar();  初始化控件

  AppSettings& s = AfxGetAppSettings();
  m_wndColorControlBar.CheckAbility();  检查能力

  if(m_wndToolBar.IsVisible())
    ShowControls(AfxGetAppSettings().nCS | CS_SEEKBAR, false);  显示控件

  __int64 rtDur = 0;
  pMS->GetDuration(&rtDur);   从视频接口获得当前位置
  m_wndPlaylistBar.SetCurTime(rtDur);  设置控件位置

  if(m_iPlaybackMode == PM_CAPTURE)
  {
    ShowControlBar(&m_wndPlaylistBar, FALSE, TRUE);
    ShowControlBar(&m_wndCaptureBar, TRUE, TRUE);
  }
  
/ /重要:不能调用任何窗口封邮件之前
  / /这一点上,它会僵局时OpenMediaPrivate
  / /仍在运行,并创建渲染窗口
  / /相同的工作者线程
  std::wstring szFileHash = HashController::GetInstance()->GetSPHash(m_fnCurPlayingFile);

  CString FPath = szFileHash.c_str();

   加载第二字幕
  if(m_pCAP && (!m_fAudioOnly || m_fRealMediaGraph))
  {
    if(m_pSubStreams.GetCount() == 0){
      if ( !m_wndPlaylistBar.m_pl.szPlayListSub.IsEmpty() ){
        int delayms = 0 - m_wndPlaylistBar.GetTotalTimeBeforeCur();
        LoadSubtitle(m_wndPlaylistBar.m_pl.szPlayListSub, delayms , true); 
      }
    }

    if(s.fEnableSubtitles && m_pSubStreams.GetCount() > 0){
      BOOL HavSubs1 = FALSE;

      Sql 操作  搜索历史记录
      if(AfxGetMyApp()->sqlite_local_record ){
        CString szSQL;
        szSQL.Format(L"SELECT subid FROM histories WHERE fpath = \"%s\" ", FPath);
        int subid = AfxGetMyApp()->sqlite_local_record->get_single_int_from_sql(szSQL.GetBuffer(), -1);
        if(subid >= 0){
          //SVP_LogMsg5(L"subid %d %d", subid, m_pSubStreams.GetCount());
          int i = subid;

      字幕流?
          POSITION pos = m_pSubStreams.GetHeadPosition();
          while(pos && i >= 0)
          {
            循环查找
            CComPtr<ISubStream> pSubStream = m_pSubStreams.GetNext(pos);

            if(i < pSubStream->GetStreamCount()) 
            {
              SendStatusMessage(ResStr(IDS_OSD_MSG_RESTORE_TO_LAST_REMEMBER_SUBTITLE_TRACK),3000);
              CAutoLock cAutoLock(&m_csSubLock);
              pSubStream->SetStream(i);
              SetSubtitle(pSubStream);
              HavSubs1 = true;
              break;
            }
            i -= pSubStream->GetStreamCount();
          }
        }
      }

      字幕流?
      if(!HavSubs1 && !s.sSubStreamName1.IsEmpty()){
        POSITION pos = m_pSubStreams.GetHeadPosition();
        while(pos){
          CComPtr<ISubStream> pSubStream = m_pSubStreams.GetNext(pos);
          if(!pSubStream) continue;
          for(int i = 0, j = pSubStream->GetStreamCount(); i < j; i++)
          {
            WCHAR* pName = NULL;
            if(SUCCEEDED(pSubStream->GetStreamInfo(i, &pName, NULL)))
            {
              CString name(pName);
              //SVP_LogMsg5(L"sub2 %s", name);
              if( name == s.sSubStreamName1){
                SetSubtitle( pSubStream);
                HavSubs1 = true;
              }
              CoTaskMemFree(pName);
              if(HavSubs1)
                break;
            }
          }
          if(HavSubs1)
            break;
        }
      }

      设置字幕流
      if(!HavSubs1){
        POSITION pos = m_pSubStreams.GetHeadPosition();
        while(pos){
          CComPtr<ISubStream> pSubStream = m_pSubStreams.GetNext(pos);
          if(!pSubStream) continue;
          for(int i = 0, j = pSubStream->GetStreamCount(); i < j; i++)
          {
            WCHAR* pName = NULL;
            if(SUCCEEDED(pSubStream->GetStreamInfo(i, &pName, NULL)))
            {
              CString name(pName);
              //SVP_LogMsg5(L"sub2 %s", name);
              if( name.Find(L"plain text") > 0){ //Apple Text Media Handler (plain text)
                SetSubtitle( pSubStream);
                HavSubs1 = true;
              }
              CoTaskMemFree(pName);
              if(HavSubs1)
                break;
            }
          }
          if(HavSubs1)
            break;
        }
      }

      字幕流
      if(!HavSubs1)
        SetSubtitle(m_pSubStreams.GetHead());

      if(s.fAutoloadSubtitles2 && m_pSubStreams2.GetCount() > 1 ){
        BOOL HavSubs = false;
        if(AfxGetMyApp()->sqlite_local_record ){
          CString szSQL;
          szSQL.Format(L"SELECT subid2 FROM histories WHERE fpath = \"%s\" ", FPath);
          int subid = AfxGetMyApp()->sqlite_local_record->get_single_int_from_sql(szSQL.GetBuffer(), -1);
          if(subid >= 0){
            //SVP_LogMsg5(L"subid %d %d", subid, m_pSubStreams.GetCount());
            int i = subid;
            POSITION pos = m_pSubStreams2.GetHeadPosition();
            while(pos && i >= 0)
            {
              CComPtr<ISubStream> pSubStream = m_pSubStreams2.GetNext(pos);
              if(i < pSubStream->GetStreamCount()) 
              {
                CAutoLock cAutoLock(&m_csSubLock);
                pSubStream->SetStream(i);
                SetSubtitle2(pSubStream);
                //SendStatusMessage(ResStr(IDS_OSD_MSG_RESTORE_TO_LAST_REMEMBER_SUBTITLE2_TRACK),3000);
                HavSubs = true;
                break;
              }
              i -= pSubStream->GetStreamCount();
            }
          }
        }

        字幕流
        if(!HavSubs && !s.sSubStreamName2.IsEmpty()){
          POSITION pos = m_pSubStreams2.GetHeadPosition();
          while(pos){
            CComPtr<ISubStream> pSubStream = m_pSubStreams2.GetNext(pos);

            if(!pSubStream) continue;

            for(int i = 0, j = pSubStream->GetStreamCount(); i < j; i++)
            {
              WCHAR* pName = NULL;
              if(SUCCEEDED(pSubStream->GetStreamInfo(i, &pName, NULL)))
              {
                CString name(pName);
                //SVP_LogMsg5(L"sub2 %s", name);
                if((!s.sSubStreamName2.IsEmpty() && name == s.sSubStreamName2)  ){
                  SetSubtitle2( pSubStream);
                  HavSubs = true;
                }
                CoTaskMemFree(pName);
                if(HavSubs)
                  break;
              }
            }
            if(HavSubs)
              break;
          }
        }

        字幕流
        if(!HavSubs){
          POSITION pos = m_pSubStreams2.GetHeadPosition();
          while(pos){
            CComPtr<ISubStream> pSubStream = m_pSubStreams2.GetNext(pos);

            if(!pSubStream) continue;

            for(int i = 0, j = pSubStream->GetStreamCount(); i < j; i++)
            {
              WCHAR* pName = NULL;
              if(SUCCEEDED(pSubStream->GetStreamInfo(i, &pName, NULL)))
              {
                CString name(pName);
                //SVP_LogMsg5(L"sub2 %s", name);
                if( ( name.Find(_T("en")) >= 0 ||  name.Find(_T("eng")) >= 0 ||  name.Find(_T("英文")) >= 0) ){
                  SetSubtitle2( pSubStream);
                  HavSubs = true;
                }
                CoTaskMemFree(pName);
                if(HavSubs)
                  break;
              }
            }
            if(HavSubs)
              break;
          }
        }
        if(!HavSubs){
          POSITION pos = m_pSubStreams2.GetHeadPosition();
          m_pSubStreams2.GetNext(pos);
          if(pos)
            SetSubtitle2( m_pSubStreams2.GetNext(pos));
        }
      }
    }
    //make sure the subtitle displayed
    UpdateSubtitle(true);  设置字幕流
    UpdateSubtitle2(true);  设置字幕流
  }

  根据Sql查找历史   发送状态
  if(AfxGetMyApp()->sqlite_local_record ){
    CString szSQL;
    szSQL.Format(L"SELECT audioid FROM histories WHERE fpath = \"%s\" ", FPath);
    //SVP_LogMsg5(szSQL);
    int audid = AfxGetMyApp()->sqlite_local_record->get_single_int_from_sql(szSQL.GetBuffer(), -1);
    if(audid > 0){
      SVP_LogMsg5(L"audid %d subs %d", audid, m_pSubStreams.GetCount());
      CComQIPtr<IAMStreamSelect> pSS = FindFilter(__uuidof(CAudioSwitcherFilter), pGB);
      if(!pSS) pSS = FindFilter(L"{D3CD7858-971A-4838-ACEC-40CA5D529DC8}", pGB);
      if( pSS)
      {
        pSS->Enable(audid, AMSTREAMSELECTENABLE_ENABLE);
        SendStatusMessage(ResStr(IDS_OSD_MSG_RESTORE_TO_LAST_REMEMBER_AUDIO_TRACK),3000);
      }
    }
  }

  根据SQL 设置字幕
  if (AfxGetMyApp()->sqlite_local_record)
  {
    CString szSQL;
    if (s.fEnableSubtitles ){
      szSQL.Format(L"SELECT subid FROM histories_stream WHERE fpath = \"%s\" ", FPath);
      int subid = AfxGetMyApp()->sqlite_local_record->get_single_int_from_sql(szSQL.GetBuffer(), -1);
      if(subid > 0){
        OnPlayLanguage(subid);
      }
    }
    szSQL.Format(L"SELECT audioid FROM histories_stream WHERE fpath = \"%s\" ", FPath);
    int audid = AfxGetMyApp()->sqlite_local_record->get_single_int_from_sql(szSQL.GetBuffer(), -1);
    if(audid > 0){
      OnPlayLanguage(audid);
    }
  }

  if(!m_pCAP && m_fAudioOnly){ / /这是我们第一次检测,这是仅音频文件

    m_wndView.m_strAudioInfo.Empty();
    //This is silly
    if(!m_fLastIsAudioOnly)
      ShowControlBar(&m_wndPlaylistBar, FALSE, TRUE);

    KillTimer(TIMER_TRANSPARENTTOOLBARSTAT);
    SetTimer(TIMER_TRANSPARENTTOOLBARSTAT, 20,NULL);
    rePosOSD();  重新计算位置
  }

  {
    WINDOWPLACEMENT wp;
    wp.length = sizeof(wp);
    GetWindowPlacement(&wp);  记录窗体位置

    // restore magnification   只有音频的情况下
    if(IsWindowVisible() && AfxGetAppSettings().fRememberZoomLevel
      && !(m_fFullScreen || wp.showCmd == SW_SHOWMAXIMIZED || wp.showCmd == SW_SHOWMINIMIZED))
    {
      if(m_fAudioOnly && m_fLastIsAudioOnly){
      }else{
        ZoomVideoWindow();  全屏播放
        // m_fFullScreen意思现在是指当前播放模式是全屏还是非全屏,如果是全屏就会在Toogle中变为非全屏,反之亦然
        if (!m_fFullScreen)
        {
          PlayerPreference* pref = PlayerPreference::GetInstance();
          bool bToBeFullScreen = pref->GetIntVar(INTVAR_TOGGLEFULLSCRENWHENPLAYBACKSTARTED);
          if (bToBeFullScreen)   是否全屏
          {
            ToggleFullscreen(true, true);
            SetCursor(NULL);
          }
        }
      }
      m_fLastIsAudioOnly = m_fAudioOnly;
    }
  }

  if(!m_fAudioOnly && (s.nCLSwitches&CLSW_FULLSCREEN))  全屏时
  {
    SendMessage(WM_COMMAND, ID_VIEW_FULLSCREEN);
    s.nCLSwitches &= ~CLSW_FULLSCREEN;
  }
  m_bDxvaInUse = false;
  m_bMustUseExternalTimer = false;
  m_haveSubVoted = false;
  m_DXVAMode = _T("");
  视频解码接口
  CComQIPtr<IMPCVideoDecFilter> pMDF  = FindFilter(__uuidof(CMPCVideoDecFilter), pGB);
  if(pMDF){
    GUID* DxvaGui = NULL;
    DxvaGui = pMDF->GetDXVADecoderGuid();
    if (DxvaGui != NULL)
    {
      m_DXVAMode = GetDXVAMode (DxvaGui);
      m_bDxvaInUse = (m_DXVAMode != _T("Not using DXVA"));
    }
  }else if(FindFilter(L"{09571A4B-F1FE-4C60-9760-DE6D310C7C31}", pGB)) {
    if(s.bHasCUDAforCoreAVC){
      m_bDxvaInUse = true;
      m_DXVAMode = _T("CoreAVC");
    }
  }
  /*
  CComQIPtr<IWMReaderAdvanced2> pWMR  = FindFilter(__uuidof(IWMReaderAdvanced2), pGB);
  if(pWMR){
  pWMR->SetPlayMode(WMT_PLAY_MODE_STREAMING);
  AfxMessageBox(L"1");
  }*/
  if(FindFilter(L"{FA10746C-9B63-4B6C-BC49-FC300EA5F256}", pGB)){
    m_bEVRInUse = true;
  }
  if( FindFilter(L"{6F513D27-97C3-453C-87FE-B24AE50B1601}", pGB)){//m_bEVRInUse
    SVP_LogMsg5(L"Has Divx H264 Dec and EVR so use External Timer");
    m_bMustUseExternalTimer = true;
  }

  RedrawNonClientArea();  重新绘画客户区

  if(m_iPlaybackMode == PM_FILE){  回放模式
    if(!s.bDontNeedSVPSubFilter && !m_pCAP && s.iSVPRenderType && !m_fAudioOnly ){
      s.iSVPRenderType = 0;
      SendStatusMessage( ResStr(IDS_OSD_MSG_DEVICE_NOT_SUPPORT_VIDEO_QMODE), 2000);
    }

    if(m_fAudioOnly && m_fnCurPlayingFile.Find(L"://") < 0){
       只有音频时  查找歌词
      //find lyric file
      m_LyricFilePaths.RemoveAll();    
      CAtlArray<CString> lrcSearchPaths;
      lrcSearchPaths.Add(_T("."));
      lrcSearchPaths.Add(s.GetSVPSubStorePath());

      CAtlArray<LrcFile> ret;
      int bGotLrc = 0 ; 
      m_Lyric.GetLrcFileNames( m_fnCurPlayingFile , lrcSearchPaths, ret);
      if( ret.GetCount() ){
        LrcFile oLrcFile = ret.GetAt(0);
        if( m_Lyric.LoadLyricFile( oLrcFile.fn) >= 0)  装载歌词
        {
          //maybe we should do something here?
          if(m_Lyric.m_has_lyric)
            bGotLrc = 1;
        }
      }
      if( !bGotLrc && s.autoDownloadSVPSub  ) {   没有歌词 但自动下载
        //debug
        //m_Lyric.LoadLyricFile(L"D:\\-=SVN=-\\test.lrc");

        m_Lyric.Empty();
        //download it by thead
        m_Lyric.title = GetClipInfo(IDS_INFOBAR_TITLE).c_str();
        m_Lyric.artist = GetClipInfo(IDS_INFOBAR_AUTHOR).c_str();
        m_Lyric.album = GetClipInfo(IDS_INFOBAR_DESCRIPTION).c_str();
        m_Lyric.m_sz_current_music_file = m_fnCurPlayingFile;
        //m_Lyric.m_stop_downloading = 1;
        //TerminateThread(m_lyricDownloadThread , 0);
        启动线程下载
        m_lyricDownloadThread = AfxBeginThread(lyric_fetch_Proc, &m_Lyric, THREAD_PRIORITY_LOWEST, 0, CREATE_SUSPENDED);
        m_lyricDownloadThread->m_pMainWnd = AfxGetMainWnd();
        m_lyricDownloadThread->ResumeThread();
      }
    }
  }
  // send sphash to remote  发送sphash到远程
  m_wndToolBar.HideMovieShareBtn(TRUE);
  UserShareController::GetInstance()->HideCommentPlane();
  UserShareController::GetInstance()->CloseShooterMedia();
  if(IsSomethingLoaded() && !m_fAudioOnly && (UINT)((INT64)rtDur/10000000) > 90)
  {
    m_movieShared = false;
    m_wndToolBar.HideMovieShareBtn(FALSE);
    SetTimer(TIMER_MOVIESHARE, 300000, NULL);   
  }
  KillTimer(TIMER_IDLE_TASK);
}

  进入CMainFrame::OpenSetupCaptureBar 分析
void CMainFrame::OpenSetupCaptureBar()  初始化头导航
{
  初始化控件
  if(m_iPlaybackMode == PM_CAPTURE)
  {
    if(pVidCap && pAMVSCCap) 
    {
      CComQIPtr<IAMVfwCaptureDialogs> pVfwCD = pVidCap;

      if(!pAMXBar && pVfwCD)
      {
        m_wndCaptureBar.m_capdlg.SetupVideoControls(m_VidDispName, pAMVSCCap, pVfwCD);
      }
      else
      {
        m_wndCaptureBar.m_capdlg.SetupVideoControls(m_VidDispName, pAMVSCCap, pAMXBar, pAMTuner);
      }
    }

    if(pAudCap && pAMASC)
    {
      CInterfaceArray<IAMAudioInputMixer> pAMAIM;
      BeginEnumPins(pAudCap, pEP, pPin)
      {
        if(CComQIPtr<IAMAudioInputMixer> pAIM = pPin) 
          pAMAIM.Add(pAIM);
      }
      EndEnumPins
        m_wndCaptureBar.m_capdlg.SetupAudioControls(m_AudDispName, pAMASC, pAMAIM);
    }
  }

  BuildGraphVideoAudio(
    m_wndCaptureBar.m_capdlg.m_fVidPreview, false, 
    m_wndCaptureBar.m_capdlg.m_fAudPreview, false);
}

  进入CMainFrame::BuildGraphVideoAudio 分析
bool CMainFrame::BuildGraphVideoAudio(int fVPreview, bool fVCapture, int fAPreview, bool fACapture)
{
  if(!pCGB) return(false);  不存在直接返回  关键是pCGB另一个

  SaveMediaState;

  HRESULT hr;

  pGB->NukeDownstream(pVidCap);
  pGB->NukeDownstream(pAudCap);

  CleanGraph();

  if(pAMVSCCap) hr = pAMVSCCap->SetFormat(&m_wndCaptureBar.m_capdlg.m_mtv);
  if(pAMVSCPrev) hr = pAMVSCPrev->SetFormat(&m_wndCaptureBar.m_capdlg.m_mtv);
  if(pAMASC) hr = pAMASC->SetFormat(&m_wndCaptureBar.m_capdlg.m_mta);

  CComPtr<IBaseFilter> pVidBuffer = m_wndCaptureBar.m_capdlg.m_pVidBuffer;
  CComPtr<IBaseFilter> pAudBuffer = m_wndCaptureBar.m_capdlg.m_pAudBuffer;
  CComPtr<IBaseFilter> pVidEnc = m_wndCaptureBar.m_capdlg.m_pVidEnc;
  CComPtr<IBaseFilter> pAudEnc = m_wndCaptureBar.m_capdlg.m_pAudEnc;
  CComPtr<IBaseFilter> pMux = m_wndCaptureBar.m_capdlg.m_pMux;
  CComPtr<IBaseFilter> pDst = m_wndCaptureBar.m_capdlg.m_pDst;
  CComPtr<IBaseFilter> pAudMux = m_wndCaptureBar.m_capdlg.m_pAudMux;
  CComPtr<IBaseFilter> pAudDst = m_wndCaptureBar.m_capdlg.m_pAudDst;

  bool fFileOutput = (pMux && pDst) || (pAudMux && pAudDst);
  bool fCapture = (fVCapture || fACapture);

  if(pAudCap)
  {
    AM_MEDIA_TYPE* pmt = &m_wndCaptureBar.m_capdlg.m_mta;
    int ms = (fACapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fAudOutput) ? AUDIOBUFFERLEN : 60;
    if(pMux != pAudMux && fACapture) SetLatency(pAudCap, -1);
    else if(pmt->pbFormat) SetLatency(pAudCap, ((WAVEFORMATEX*)pmt->pbFormat)->nAvgBytesPerSec * ms / 1000);
  }

  CComPtr<IPin> pVidCapPin, pVidPrevPin, pAudCapPin, pAudPrevPin;
  BuildToCapturePreviewPin(pVidCap, &pVidCapPin, &pVidPrevPin, pAudCap, &pAudCapPin, &pAudPrevPin);

  // if(pVidCap)
  {
    bool fVidPrev = pVidPrevPin && fVPreview;
    bool fVidCap = pVidCapPin && fVCapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fVidOutput;

    if(fVPreview == 2 && !fVidCap && pVidCapPin)
    {
      pVidPrevPin = pVidCapPin;
      pVidCapPin = NULL;
    }

    if(fVidPrev)
    {
      m_pCAP = NULL;
      m_pCAP2 = NULL;
      m_pCAPR = NULL;
      pGB->Render(pVidPrevPin);
      pGB->FindInterface(__uuidof(ISubPicAllocatorPresenter), (void**)&m_pCAP, FALSE);
      pGB->FindInterface(__uuidof(ISubPicAllocatorPresenterRender), (void**)&m_pCAPR, TRUE);
      pGB->FindInterface(__uuidof(ISubPicAllocatorPresenter2), (void**)&m_pCAP2, TRUE);
    }

    if(fVidCap)
    {
      IBaseFilter* pBF[3] = {pVidBuffer, pVidEnc, pMux};
      HRESULT hr = BuildCapture(pVidCapPin, pBF, MEDIATYPE_Video, &m_wndCaptureBar.m_capdlg.m_mtcv);
    }

    pAMDF = NULL;
    pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pVidCap, IID_IAMDroppedFrames, (void**)&pAMDF);
  }

  // if(pAudCap)
  {
    bool fAudPrev = pAudPrevPin && fAPreview;
    bool fAudCap = pAudCapPin && fACapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fAudOutput;

    if(fAPreview == 2 && !fAudCap && pAudCapPin)
    {
      pAudPrevPin = pAudCapPin;
      pAudCapPin = NULL;
    }

    if(fAudPrev)
    {
      pGB->Render(pAudPrevPin);
    }

    if(fAudCap)
    {
      IBaseFilter* pBF[3] = {pAudBuffer, pAudEnc, pAudMux ? pAudMux : pMux};
      HRESULT hr = BuildCapture(pAudCapPin, pBF, MEDIATYPE_Audio, &m_wndCaptureBar.m_capdlg.m_mtca);
    }
  }

  if((pVidCap || pAudCap) && fCapture && fFileOutput)
  {
    if(pMux != pDst)
    {
      hr = pGB->AddFilter(pDst, L"File Writer V/A");
      hr = pGB->ConnectFilter(GetFirstPin(pMux, PINDIR_OUTPUT), pDst);
    }

    if(CComQIPtr<IConfigAviMux> pCAM = pMux)
    {
      int nIn, nOut, nInC, nOutC;
      CountPins(pMux, nIn, nOut, nInC, nOutC);
      pCAM->SetMasterStream(nInC-1);
      // pCAM->SetMasterStream(-1);
      pCAM->SetOutputCompatibilityIndex(FALSE);
    }

    if(CComQIPtr<IConfigInterleaving> pCI = pMux)
    {
      // if(FAILED(pCI->put_Mode(INTERLEAVE_CAPTURE)))
      if(FAILED(pCI->put_Mode(INTERLEAVE_NONE_BUFFERED)))
        pCI->put_Mode(INTERLEAVE_NONE);

      REFERENCE_TIME rtInterleave = 10000i64*AUDIOBUFFERLEN, rtPreroll = 0;//10000i64*500
      pCI->put_Interleaving(&rtInterleave, &rtPreroll);
    }

    if(pMux != pAudMux && pAudMux != pAudDst)
    {
      hr = pGB->AddFilter(pAudDst, L"File Writer A");
      hr = pGB->ConnectFilter(GetFirstPin(pAudMux, PINDIR_OUTPUT), pAudDst);
    }
  }

  REFERENCE_TIME stop = MAX_TIME;
  hr = pCGB->ControlStream(&PIN_CATEGORY_CAPTURE, NULL, NULL, NULL, &stop, 0, 0); // stop in the infinite

  CleanGraph();

  OpenSetupVideo();
  OpenSetupAudio();

  RestoreMediaState;

  return(true);
}

OnFilePostOpenmedia() 中  SetTimer(TIMER_MOVIESHARE, 300000, NULL);  
  case TIMER_MOVIESHARE:
    {
      KillTimer(TIMER_MOVIESHARE);
      if (IsSomethingLoaded() && !m_fAudioOnly && !m_movieShared)  已经加载  不是音频 文件不共享
      {
        m_movieShared = true;
        std::wstring uuid, moviehash;
        SPlayerGUID::GenerateGUID(uuid);
        UserShareController* usc = UserShareController::GetInstance();
        usc->CreateCommentPlane();
        moviehash = HashController::GetInstance()->GetSPHash(m_fnCurPlayingFile);
        usc->ShareMovie(uuid, moviehash, m_fnCurPlayingFile.GetString());
      }
    }
    break;

   进入CMainFrame::ZoomVideoWindow 分析
void CMainFrame::ZoomVideoWindow(double scale)
{
  if(m_iMediaLoadState != MLS_LOADED)    return;  没有装载 直接退出 ?

  AppSettings& s = AfxGetAppSettings();

  if(s.bUserAeroUI()){   用户区域UI
    m_lTransparentToolbarStat = 0;
    m_wndFloatToolBar->ShowWindow(SW_HIDE);
  }

  BOOL bThisIsAutoZoom = false;  自动大小

  if(scale <= 0)
  {
    bThisIsAutoZoom = true;
    scale = 
      s.iZoomLevel == 0 ? 0.5 : 
      s.iZoomLevel == 1 ? 1.0 : 
      s.iZoomLevel == 2 ? 2.0 : 
      s.iZoomLevel == 3 ? GetZoomAutoFitScale() : 
      1.0;
    m_last_size_of_current_kind_of_video.cx = -1;
    m_last_size_of_current_kind_of_video.cy = -1;
  }

  if(m_fFullScreen)  如果全屏 则全屏
  {
    OnViewFullscreen();
  }

  MINMAXINFO mmi;
  OnGetMinMaxInfo(&mmi);

  CRect r;
  int w = 0, h = 0;

  if(!m_fAudioOnly)  不是音频
  {
    CSize arxy = m_original_size_of_current_video = GetVideoSize();
    long lWidth = int(arxy.cx * scale + 0.5);
    long lHeight = int(arxy.cy * scale + 0.5);
    CString string_remember_windows_size_for_this_video_size_parm;
    string_remember_windows_size_for_this_video_size_parm.Format(L"ORGSIZE%dx%d", m_original_size_of_current_video.cx, m_original_size_of_current_video.cy );
    AppSettings& s = AfxGetAppSettings();
    long lPerfWidth = m_last_size_of_current_kind_of_video.cx = AfxGetMyApp()->GetProfileInt(ResStr(IDS_R_SETTINGS)+L"REMENBERWNDSIZE", string_remember_windows_size_for_this_video_size_parm+L"W", -1);
    long lPerfHeight = m_last_size_of_current_kind_of_video.cy = AfxGetMyApp()->GetProfileInt(ResStr(IDS_R_SETTINGS)+L"REMENBERWNDSIZE", string_remember_windows_size_for_this_video_size_parm+L"H", -1);

    DWORD style = GetStyle();

    CRect r3 ,r4;
    GetWindowRect(r3);
    m_wndView.GetWindowRect(r4);
    //GetClientRect(&r1);
    //m_wndView.GetClientRect(&r2);
    int wDelta = 0;
    int hDelta = 0;

    wDelta = r3.Width() - r4.Width();
    hDelta = r3.Height() - r4.Height();

    if(style&WS_CAPTION)
    {
      //h += GetSystemMetrics(SM_CYCAPTION);
      //w += 2; h += 2; // for the 1 pixel wide sunken frame
      //w += 2; h += 3; // for the inner black border
    }

    GetWindowRect(r);

    if (lHeight + hDelta < 280 || lWidth + wDelta < 480) {
      int w1 = 480 - wDelta;
      int h1 = 280 - hDelta;
      SVP_ASSERT(w1 > 0);
      SVP_ASSERT(h1 > 0);

      // Re-evaluate current 'w' and 'h' to keep aspect ratio
      int h2 = arxy.cy * w1 / arxy.cx, w2 = arxy.cx * h1 / arxy.cy;
      // Choose by the fitting rectangle.
      if (h2 + hDelta >= 280) {
        w = 480;
        h = h2 + hDelta;
      } else {
        w = w2 + wDelta;
        h = 280;
      }


    } else {
      h = lHeight + hDelta;
      w = lWidth + wDelta;
    }


    if(bThisIsAutoZoom && 0){
      double mratio = (double)lHeight/lWidth;
      //SVP_LogMsg5(L"%d %d %f %d %d %f",h , w, w * mratio + (h - lHeight), lHeight, lWidth, mratio);
      h = max(h , w * mratio + (h - lHeight));
    }


    if(bThisIsAutoZoom && lPerfWidth > 240 && lPerfHeight > 120)
    {
      //Only do this if its auto zoom
      w = lPerfWidth;
      h = lPerfHeight;
    }
  }
  else
  {
    GetWindowRect(r);


    //w = r.Width(); //;mmi.ptMinTrackSize.x;
    //h = r.Height();//;mmi.ptMinTrackSize.y;
    w = 320;
    if(s.bUserAeroUI()){
      w /= 0.9;
    }
    h = 110;


    AppSettings& s = AfxGetAppSettings();
    long lPerfWidth = m_last_size_of_current_kind_of_video.cx = AfxGetMyApp()->GetProfileInt(ResStr(IDS_R_SETTINGS)+L"REMENBERWNDSIZE", L"ORGSIZE0x0W", -1);
    long lPerfHeight = m_last_size_of_current_kind_of_video.cy = AfxGetMyApp()->GetProfileInt(ResStr(IDS_R_SETTINGS)+L"REMENBERWNDSIZE", L"ORGSIZE0x0H", -1);


    w = max(w, lPerfWidth);
    h = max(h, lPerfHeight);


  }


  // center window
  //if(!s.fRememberWindowPos)
  {
    CPoint cp = r.CenterPoint();
    r.left = cp.x - w/2;
    r.top = cp.y - h/2;
  }


  r.right = r.left + w;
  r.bottom = r.top + h;


  MONITORINFO mi;
  mi.cbSize = sizeof(MONITORINFO);


  获得窗体信息
  GetMonitorInfo(MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi);
  if(r.right > mi.rcWork.right) r.OffsetRect(mi.rcWork.right-r.right, 0);
  if(r.left < mi.rcWork.left) r.OffsetRect(mi.rcWork.left-r.left, 0);
  if(r.bottom > mi.rcWork.bottom) r.OffsetRect(0, mi.rcWork.bottom-r.bottom);
  if(r.top < mi.rcWork.top) r.OffsetRect(0, mi.rcWork.top-r.top);
  CRect rcWork(mi.rcWork);
  if(r.Width() >  rcWork.Width() ){
    r.left = rcWork.left;
    r.right = rcWork.right;
  }
  if(r.Height() >  rcWork.Height() ){
    r.top = rcWork.top;
    r.bottom = rcWork.bottom;
  }
  if(m_fFullScreen || !s.HasFixedWindowSize())
  {
    MoveWindow(r);
  }


  //AfxMessageBox(_T("1"));
  //Sleep(200);
  // ShowWindow(SW_SHOWNORMAL);


  MoveVideoWindow();
}




   进入CMainFrame::ToggleFullscreen 分析
void CMainFrame::ToggleFullscreen(bool fToNearest, bool fSwitchScreenResWhenHasTo)
{
  CRect r;
  m_lastTimeToggleFullsreen = AfxGetMyApp()->GetPerfCounter();
  // const CWnd* pWndInsertAfter;
  DWORD dwRemove = 0, dwAdd = 0;
  DWORD dwRemoveEx = 0, dwAddEx = 0;
  HMENU hMenu;


  if(!m_fFullScreen)  
  {  不是全屏


    if(m_wndPlaylistBar.IsVisible()){
      m_fPlaylistBeforeToggleFullScreen = true;
      ShowControlBar(&m_wndPlaylistBar, FALSE, TRUE);
    }


    GetWindowRect(&m_lastWindowRect);


    dispmode& dm = AfxGetAppSettings().dmFullscreenRes;
    m_dmBeforeFullscreen.fValid = false;
    if(dm.fValid && fSwitchScreenResWhenHasTo)
    {
      GetCurDispMode(m_dmBeforeFullscreen);
      SetDispMode(dm);
    }


    MONITORINFO mi;
    mi.cbSize = sizeof(MONITORINFO);
    GetMonitorInfo(MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi);


    dwRemove = WS_CAPTION|WS_THICKFRAME;
    if(fToNearest) r = mi.rcMonitor;
    else GetDesktopWindow()->GetWindowRect(&r);
    hMenu = NULL;




  }
  else
  {
    全屏
    if( AfxGetAppSettings().htpcmode){
      return;
    }
    if( m_fPlaylistBeforeToggleFullScreen )  
      ShowControlBar(&m_wndPlaylistBar, TRUE, TRUE);


    if(m_dmBeforeFullscreen.fValid)
      SetDispMode(m_dmBeforeFullscreen);


    dwAdd = (AfxGetAppSettings().fHideCaptionMenu ? 0 : WS_CAPTION) | WS_THICKFRAME;
    r = m_lastWindowRect;
    hMenu = NULL;//AfxGetAppSettings().fHideCaptionMenu ? NULL : m_hMenuDefault;
  }






  //bool fAudioOnly = m_fAudioOnly;
  //m_fAudioOnly = true;


  m_fFullScreen = !m_fFullScreen;


  SetAlwaysOnTop(AfxGetAppSettings().iOnTop);


  修改属性  进行全屏
  ModifyStyle(dwRemove, dwAdd, SWP_NOZORDER);
  ModifyStyleEx(dwRemoveEx, dwAddEx, SWP_NOZORDER);
  ::SetMenu(m_hWnd, hMenu);
  SetWindowPos(NULL, r.left, r.top, r.Width(), r.Height(), SWP_NOZORDER|SWP_NOSENDCHANGING /*SWP_FRAMECHANGED*/);
  RedrawNonClientArea();


  KillTimer(TIMER_FULLSCREENCONTROLBARHIDER);
  KillTimer(TIMER_FULLSCREENMOUSEHIDER);
  if(m_fFullScreen)
  {
    // SVP_LogMsg5(L"Fullscreen");
    m_fHideCursor = true;
    SetTimer(TIMER_FULLSCREENMOUSEHIDER, 800, NULL);
    ShowControls(CS_NONE, false);
  }
  else
  {
    m_lastMouseMove.x = m_lastMouseMove.y = -1;
    m_fHideCursor = false;
    ShowControls(AfxGetAppSettings().nCS);
  }


  m_wndView.SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER);
  //m_fAudioOnly = fAudioOnly;


  rePosOSD();


  MoveVideoWindow();


  // insert after the HWND_TOP if the player is not full screen
  if (m_fFullScreen)  全屏的话  就置顶
    ::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE);
  else
    ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE);
}




TIMER_STREAMPOSPOLLER:  定时事件
  case TIMER_STREAMPOSPOLLER:
    if (m_iMediaLoadState == MLS_LOADED)
      _HandleTimer_StreamPosPoller();
    break;


void CMainFrame::_HandleTimer_StreamPosPoller()   处理位置信息  比如播放进度
{
  REFERENCE_TIME rtNow = 0, rtDur = 0;


  if (m_iPlaybackMode == PM_FILE)
  {
    pMS->GetCurrentPosition(&rtNow);
    pMS->GetDuration(&rtDur);


    if (m_rtDurationOverride >= 0)
      rtDur = m_rtDurationOverride;


    m_wndSeekBar.Enable(rtDur > 0);
    m_wndSeekBar.SetRange(0, rtDur);
    m_wndSeekBar.SetPos(rtNow);
  }
  else if (m_iPlaybackMode == PM_CAPTURE)
  {
    if (m_fCapturing && m_wndCaptureBar.m_capdlg.m_pMux)
    {
      CComQIPtr<IMediaSeeking> pMuxMS = m_wndCaptureBar.m_capdlg.m_pMux;
      if (!pMuxMS || FAILED(pMuxMS->GetCurrentPosition(&rtNow)))
        rtNow = 0;
    }


    if (m_rtDurationOverride >= 0)
      rtDur = m_rtDurationOverride;


    m_wndSeekBar.Enable(false);
    m_wndSeekBar.SetRange(0, rtDur);
    m_wndSeekBar.SetPos(rtNow);
    /*
    if (m_fCapturing)
    {
    if (rtNow > 10000i64*1000*60*60*3)
    m_wndCaptureBar.m_capdlg.OnRecord();
    }
    */
  }


  if (m_pCAP && (m_iPlaybackMode != PM_FILE || m_bMustUseExternalTimer))
  {
    g_bExternalSubtitleTime = true;
    AfxGetAppSettings().bExternalSubtitleTime = true;
    if (pDVDI)
    {
      DVD_PLAYBACK_LOCATION2 Location;
      if (pDVDI->GetCurrentLocation(&Location) == S_OK)
      {
        double fps = Location.TimeCodeFlags == DVD_TC_FLAG_25fps ? 25.0
          : Location.TimeCodeFlags == DVD_TC_FLAG_30fps ? 30.0
          : Location.TimeCodeFlags == DVD_TC_FLAG_DropFrame ? 29.97
          : 25.0;


        LONGLONG rtTimeCode = HMSF2RT(Location.TimeCode, fps);
        m_pCAP->SetTime(rtTimeCode);
      }
      else
        m_pCAP->SetTime(/*rtNow*/m_wndSeekBar.GetPos());
    }
    else
      m_pCAP->SetTime(/*rtNow*/m_wndSeekBar.GetPos());
  }
  else
  {
    g_bExternalSubtitleTime = false;
    AfxGetAppSettings().bExternalSubtitleTime = false;
  }
}




TIMER_STREAMPOSPOLLER2: 定时设置
  case TIMER_STREAMPOSPOLLER2:
    if (m_iMediaLoadState == MLS_LOADED)   设置位置  和  时间
    {
      __int64 start, stop, pos;
      m_wndSeekBar.GetRange(start, stop);
      pos = m_wndSeekBar.GetPosReal();


      if (ABControlOn && m_bRefTime > m_aRefTime && GetMediaState() == State_Running)
      {
        if (pos > m_bRefTime)
          //goto aRefTimer
          SeekTo(m_aRefTime, 0);
      }
      GUID tf;
      pMS->GetTimeFormat(&tf);


      if (m_iPlaybackMode == PM_CAPTURE && !m_fCapturing)
      {
        CString str = _T("Live");
        long lChannel = 0, lVivSub = 0, lAudSub = 0;
        if (pAMTuner 
          && m_wndCaptureBar.m_capdlg.IsTunerActive()
          && SUCCEEDED(pAMTuner->get_Channel(&lChannel, &lVivSub, &lAudSub)))
        {
          CString ch;
          ch.Format(_T(" (ch%d)"), lChannel);
          str += ch;
        }
        //m_wndStatusBar.SetStatusTimer(str);
        m_wndToolBar.SetStatusTimer(str);
      }
      else
      {
        double pRate;
        if (E_NOTIMPL == pMS->GetRate(&pRate))
          pRate = 0;
        m_wndToolBar.SetStatusTimer(pos, stop, 0, &tf, pRate);
        //m_wndToolBar.SetStatusTimer(str);
      }


      if (m_pCAPR && GetMediaState() == State_Paused)
        m_pCAPR->Paint(true);
    }
    break;








  case TIMER_STATS:   定时 事件
    _HandleTimer_Stats();   处理事件状态
    break;
void CMainFrame::_HandleTimer_Stats()
{
  m_l_been_playing_sec++;
  if (AfxGetMyApp()->IsWin7() && pTBL)
  {
    try
    {
      BOOL bHasValue = 0;
      BOOL bSetPaused = 0;
      if (IsSomethingLoaded())   确认已经加载
      {
        //TBPF_PAUSED
        //TBPF_NORMAL
        //TBPF_INDETERMINATE
        switch (GetMediaState())
        {
        case State_Paused:
          //not using TBPF_PAUSED since it hide progress
          pTBL->SetProgressState(m_hWnd,TBPF_NORMAL);
          bSetPaused = true;
          bHasValue = true;
          break;
        case State_Running:
          pTBL->SetProgressState(m_hWnd,TBPF_NORMAL);
          bHasValue = true;
          break;
        case State_Stopped:
          pTBL->SetProgressState(m_hWnd,TBPF_NOPROGRESS);
          break;
        }
      }
      else
        pTBL->SetProgressState(m_hWnd,TBPF_NOPROGRESS);


      if (bHasValue)
      {
        __int64 iSeekStart, iSeekStop;
        m_wndSeekBar.GetRange(iSeekStart, iSeekStop);
        __int64 iSeekPos = m_wndSeekBar.GetPosReal();
        pTBL->SetProgressValue(m_hWnd, iSeekPos ,(iSeekStop - iSeekStart));
      }
      if (bSetPaused)
        pTBL->SetProgressState(m_hWnd,TBPF_PAUSED);
    }
    catch (...)
    {
      pTBL->Release();
      pTBL = NULL;
    }
  }


  if (IsSomethingLoaded() && m_fAudioOnly && (!m_Lyric.m_has_lyric || m_wndView.m_strAudioInfo.IsEmpty()))
  {    已经加载  是音频  没有歌词
    m_wndView.m_AudioInfoCounter++;
    BOOL bHaveInfo = false;


    for (int i = 0; i < 4; i++)
    {
      if ((m_wndView.m_AudioInfoCounter%4) == 0 || m_wndView.m_strAudioInfo.IsEmpty())
      {
        CString szInfo , szMusicTitle, szMusicAuthor;
        szMusicTitle = GetClipInfo(IDS_INFOBAR_TITLE).c_str();
        szMusicAuthor = GetClipInfo(IDS_INFOBAR_AUTHOR).c_str();


        switch (m_wndView.m_AudioInfoCounter/4 %4)
        {
        case 0:
          szInfo = szMusicTitle;
          break;
        case 1:
          szInfo = szMusicAuthor;
          break;
        case 2:
          szInfo = GetClipInfo(IDS_INFOBAR_DESCRIPTION).c_str();
          break;
        case 3:
          szInfo = GetClipInfo(IDS_INFOBAR_COPYRIGHT).c_str();
          break;
        }
        if (szInfo.IsEmpty())
        {
          m_wndView.m_AudioInfoCounter+=4;
          continue;
        }
        else
        {
          m_wndView.m_strAudioInfo = szInfo;
          CString szTitleItShouleBe = szMusicTitle + _T(" - ") + szMusicAuthor;
          if (szTitleItShouleBe != m_szTitle)
          {
            m_szTitle = szTitleItShouleBe;
            RedrawNonClientArea();
          }
          m_wndView.Invalidate();
          bHaveInfo = true;
        }
      }
      break;
    }
  }


  if (m_iPlaybackMode == PM_FILE)
  {
    REFERENCE_TIME rtNow = 0, rtDur = 0;
    pMS->GetCurrentPosition(&rtNow);
    pMS->GetDuration(&rtDur);




    if (m_fAudioOnly && m_Lyric.m_has_lyric)// && m_wndLycShowBox
    {
      int iLastingTime;
      CString szLyricLine = m_Lyric.GetCurrentLyricLineByTime(rtNow, &iLastingTime);
      if (!szLyricLine.IsEmpty())
      {
        wchar_t music_note[] = {0x266A, 0x0020, 0};
        szLyricLine.Insert(0, music_note);
        if (m_wndView.m_strAudioInfo != szLyricLine)
        {
          m_wndView.m_strAudioInfo = szLyricLine;
          if (iLastingTime > 0)
            m_wndView.SetLyricLasting(iLastingTime);
          else
            m_wndView.SetLyricLasting(15);
          m_wndView.Invalidate();
        }
      }
    }


    UINT iTotalLenSec = (UINT)( (INT64) rtDur / 20000000 );
    //如果视频长度大于1分钟, 而且是文件模式,而且正在播放中
    if (!m_fAudioOnly && iTotalLenSec >  180 && m_iPlaybackMode == PM_FILE && GetMediaState() == State_Running)
    {
      time_t time_now = time(NULL);
      UINT totalplayedtime =  time_now - m_tPlayStartTime;
      //SVP_LogMsg5(L"time_now > ( m_tLastLogTick  %f %f" , (double)time_now , (double)m_tLastLogTick);
      if (time_now > ( m_tLastLogTick + 180 ))
      { //如果和上次检查已经超n秒
        CString fnVideoFile , fnSubtitleFile; 
        int subDelayMS = 0;
        fnVideoFile = m_fnCurPlayingFile;
        fnSubtitleFile = getCurPlayingSubfile(&subDelayMS);


        if (!fnSubtitleFile.IsEmpty())
        { //如果有字幕
          CString szLog;
          //szLog.Format(_T(" %s ( with sub %s delay %d ) %d sec of %d sec ( 1/2 length video = %d ) ") , fnVideoFile, fnSubtitleFile,subDelayMS, totalplayedtime , iTotalLenSec, (UINT)(iTotalLenSec/2)  );
          //SVP_LogMsg(szLog);
          //if time > 50%
          if (totalplayedtime > (UINT)(iTotalLenSec/2))
          {
            if (!m_haveSubVoted && m_pCAP && rtNow > (rtDur - 3000000000i64))
            {
              //如果还没提示过vote
              //如果时间接近最末5分钟
              AppSettings& s = AfxGetAppSettings();
              if (s.bIsChineseUIUser())
              {
                //如果是中文
                if ( m_wndPlaylistBar.GetCount() <= 1)
                {
                  //如果是1CD
                  int nSubPics;
                  REFERENCE_TIME rtSubNow,  rtSubStart, rtSubStop;
                  m_pCAP->GetSubStats(nSubPics,rtSubNow,  rtSubStart, rtSubStop);
                  if (rtSubNow > rtSubStop)
                  {
                    //如果没有更多字幕
                    SVP_LogMsg5(L"Sub Voted Event");
                    //vote之
                    m_haveSubVoted = true;
                  }
                }
              }
            }
            //是否已经上传过呢
            if (m_fnsAlreadyUploadedSubfile.Find(fnVideoFile+fnSubtitleFile) < 0)
            {
              //upload subtitle
              Logging(L"Uploading sub %s of %s width delay %d ms since user played %d sec of %d sec ( more than 1/2 length video ) " , fnSubtitleFile, fnVideoFile ,subDelayMS, totalplayedtime , iTotalLenSec  );
              SVP_UploadSubFileByVideoAndSubFilePath(fnVideoFile , fnSubtitleFile, subDelayMS);
              m_fnsAlreadyUploadedSubfile.Append( fnVideoFile+fnSubtitleFile+_T(";") );
            }
            int subDelayMS2 = 0;
            CString fnSubtitleFile2 = getCurPlayingSubfile(&subDelayMS2);
            if (!fnSubtitleFile2.IsEmpty())
            {
              if (m_fnsAlreadyUploadedSubfile.Find( fnVideoFile+fnSubtitleFile2 ) < 0)
              {
                //upload subtitle
                Logging((L"Uploading sub2 %s of %s width delay %d ms since user played %d sec of %d sec ( more than 1/2 length video ) ") , fnSubtitleFile2, fnVideoFile ,subDelayMS2, totalplayedtime , iTotalLenSec);
                SVP_UploadSubFileByVideoAndSubFilePath(fnVideoFile , fnSubtitleFile2, subDelayMS2);
                m_fnsAlreadyUploadedSubfile.Append( fnVideoFile+fnSubtitleFile2+_T(";") );
              }
            }
          }
        }
        m_tLastLogTick = time_now;
        //SVP_LogMsg5(L"m_tLastLogTick = time_now;   %f %f" , (double)time_now , (double)m_tLastLogTick);
      }
    }
  }


  CString msg;
  if (m_fBuffering)
  {
    BeginEnumFilters(pGB, pEF, pBF)
    {
      if (CComQIPtr<IAMNetworkStatus, &IID_IAMNetworkStatus> pAMNS = pBF)
      {
        long BufferingProgress = 0;
        if (SUCCEEDED(pAMNS->get_BufferingProgress(&BufferingProgress)) && BufferingProgress > 0 && BufferingProgress < 99)
        {
          msg.Format(ResStr(IDS_CONTROLS_BUFFERING), BufferingProgress);
          SendStatusMessage(msg,1000);
          SVP_LogMsg5(msg);
        }
        break;
      }
    }
    EndEnumFilters
  }
  else if (pAMOP)
  {
    __int64 t = 0, c = 0;
    if(SUCCEEDED(pAMOP->QueryProgress(&t, &c)) && t > 0 && c < t)
    {
      msg.Format(ResStr(IDS_CONTROLS_BUFFERING), c*100/t);
      SendStatusMessage(msg,1000);
      SVP_LogMsg5(msg);
    }
  }
  m_wndToolBar.m_buffering  = msg;


  if (m_iPlaybackMode == PM_FILE)
    SetupChapters();
  


  if (GetMediaState() == State_Running)
  {
    if (m_fAudioOnly)
    {
      UINT fSaverActive = 0;
      if (SystemParametersInfo(SPI_GETPOWEROFFACTIVE, 0, (PVOID)&fSaverActive, 0))
      {
        SystemParametersInfo(SPI_SETPOWEROFFACTIVE, 0, 0, SPIF_SENDWININICHANGE); // this might not be needed at all...
        SystemParametersInfo(SPI_SETPOWEROFFACTIVE, fSaverActive, 0, SPIF_SENDWININICHANGE);
      }
      SetThreadExecutionState(ES_SYSTEM_REQUIRED); 
    }
    else
    {
      UINT fSaverActive = 0;
      if (SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, (PVOID)&fSaverActive, 0))
      {
        SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, 0, SPIF_SENDWININICHANGE); // this might not be needed at all...
        SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, fSaverActive, 0, SPIF_SENDWININICHANGE);
      }
      fSaverActive = 0;
      if (SystemParametersInfo(SPI_GETPOWEROFFACTIVE, 0, (PVOID)&fSaverActive, 0))
      {
        SystemParametersInfo(SPI_SETPOWEROFFACTIVE, 0, 0, SPIF_SENDWININICHANGE); // this might not be needed at all...
        SystemParametersInfo(SPI_SETPOWEROFFACTIVE, fSaverActive, 0, SPIF_SENDWININICHANGE);
      }
      SetThreadExecutionState(ES_DISPLAY_REQUIRED|ES_SYSTEM_REQUIRED); //this is the right way, only this work under vista . no ES_CONTINUOUS  so it can goes to sleep when not playing
    }




    if (GetExStyle() & WS_EX_LAYERED)
    {
      BYTE dAlpha = 0 ;
      DWORD dwFlag = 0;
      if (AfxGetMyApp()->m_pGetLayeredWindowAttributes)
      {
        AfxGetMyApp()->m_pGetLayeredWindowAttributes(m_hWnd, NULL, &dAlpha , &dwFlag);
        if (dAlpha == 255)
          ModifyStyleEx(WS_EX_LAYERED , 0);
      }
    }
  }

namespace DSObjects  操作DirectShow类库


空间中有
操作DirectShow  D3D7
CDX7AllocatorPresenter继承ISubPicAllocatorPresenterImpl


操作DirectShow  D3D9
CDX9AllocatorPresenter继承ISubPicAllocatorPresenterImpl


CDXRAllocatorPresenter继承ISubPicAllocatorPresenterImpl


VMR7分配器
CVMR7AllocatorPresenter继承CDX7AllocatorPresenter,继承IVMRSurfaceAllocator,继承IVMRImagePresenter,继承IVMRWindowlessControl


VMR9分配器
CVMR9AllocatorPresenter继承CDX9AllocatorPresenter,继承IVMRSurfaceAllocator9,继承IVMRImagePresenter9, 继承IVMRWindowlessControl9


CGenlock   管理视频和显示的同步。


VR分配器
CmadVRAllocatorPresenter继承ISubPicAllocatorPresenterImpl


QT7分配器
CQT7AllocatorPresenter继承CDX7AllocatorPresenter,继承IQTVideoSurface


QT9分配器
CQT9AllocatorPresenter继承CDX9AllocatorPresenter,继承IQTVideoSurface


Quicktime格式绘图
CQuicktimeGraph继承CBaseGraph,继承IVideoFrameStep


Quicktime载体
CQuicktimeWindow继承CPlayerWindow


Real格式绘图
CRealMediaGraph继承CBaseGraph


Real格式播放
CRealMediaPlayer继承CUnknown,继承IRMAErrorSink,继承IRMAClientAdviseSink,继承IRMAAuthenticationManager,继承IRMASiteSupplier,继承IRMAPassiveSiteWatcher,继承IRMAAudioHook


Real格式播放载体
CRealMediaPlayerWindowed继承CRealMediaPlayer


Real格式播放载体
CRealMediaPlayerWindowless继承CRealMediaPlayer


Real格式视频面
CRealMediaVideoSurface继承CUnknown,继承IRMAVideoSurface


Real格式载体站点
CRealMediaWindowlessSite继承CUnknown,继承IRMASite,继承IRMASite2,继承IRMASiteWindowless,继承IRMAVideoSurface


RM7分配器
CRM7AllocatorPresenter继承CDX7AllocatorPresenter,继承IRMAVideoSurface


RM9分配器
CRM9AllocatorPresenter继承CDX9AllocatorPresenter,继承IRMAVideoSurface


Flash绘图
CShockwaveGraph继承CBaseGraph






主程序有的类库:


链接广告的类  实现了动画效果
AdController继承ThreadHelperImpl<AdController>


ButtonManage  按钮管理类 


CAboutDlg继承CDialog  关于对话框


自定义了一个映射模版类
template <class T = CString, class S = CString>
class CAtlStringMap : public CAtlMap<S, T, CStringElementTraits<S> > {};


一个音频格式集合类
class CAudFormatArray : public CFormatArray<AUDIO_STREAM_CONFIG_CAPS>


一个作者登陆框
class CAuthDlg : public CDialog


视频绘画类
class CBaseGraph继承CUnknown, 继承IGraphBuilder2, public IMediaControl, 继承IMediaEventEx, 继承IMediaSeeking, 继承IVideoWindow, 继承IBasicVideo, 继承IBasicAudio, 继承IAMOpenProgress, public IGraphEngine




class CBtnAlign  按钮位置区域对齐类


自绘了Edit类 阙套了Button
class CBtnEditCtrl继承CWindowImpl<CBtnEditCtrl, CEdit>


CChildView继承CWnd  窗体类 实现了视频载体


COM组件属性页站点
CComPropertyPageSite继承CUnknown,继承IPropertyPageSite


CConvertChapDlg继承CResizableDialog 转换章节对话框


CConvertDlg继承CResizableDialog  转换对话框


CConvertPropsDlg继承CResizableDialog 转换属性页对话框


CConvertResDlg继承CResizableDialog 转换资源对话框


分行过滤器
CDeinterlacerFilter继承CTransformFilter


CDisplaySettingDetector 显示设置探测器


CDlgChkUpdater继承CDialog  确认更新对话框


CDropTarget  移动文件类


EVR分配器
CEVRAllocatorPresenter继承CDX9AllocatorPresenter,继承IMFGetService,继承IMFTopologyServiceLookupClient,继承IMFVideoDeviceID,继承IMFVideoPresenter,继承IDirect3DDeviceManager9,继承IMFAsyncCallback,继承IQualProp,继承IMFRateSupport,继承IMFVideoDisplayControl,继承IEVRTrustedVideoPlugin


渐变视频解码
CFakeDirectXVideoDecoder继承CUnknown,继承IDirectXVideoDecoder


CFavoriteAddDlg继承CCmdUIDialog  收藏对话框


CFavoriteOrganizeDlg继承CResizableDialog 收藏组织对话框


CFFindByDir  目录查找类


CFFindMoreFiles 查找更多文件类


CFGAggregator继承CUnknown  FG集合类


CFGFilter   FG过滤类


CFGFilterFile继承CFGFilter FG过滤文件


CFGFilterInternal继承CFGFilter  FG内部过滤


CFGFilterList  FG过滤列表


CFGFilterRegistry继承CFGFilter FG过滤继承类


CFGFilterVideoRenderer继承CFGFilter  FG过滤视频渲染类


FG管理类
CFGManager继承CUnknown, 继承IGraphBuilder2, 继承IGraphBuilderDeadEnd, 继承CCritSec


CFGManagerCapture继承CFGManagerPlayer FG捕捉管理类


CFGManagerCustom继承CFGManager   FG自定义管理类


CFGManagerDVD继承CFGManagerPlayer  FG_DVD管理类


CFGManagerMuxer继承CFGManagerCustom  FG 混合器管理类


CFGManagerPlayer继承CFGManagerCustom  FG视频管理


CFileDropTarget继承COleDropTarget   文件移动类


CFilterMapper2继承CUnknown继承IFilterMapper2   过滤映射类


CFilterTreeCtrl继承CTreeCtrl   过滤器树列表


CFloatEdit继承CEdit  浮动的编辑框


格式模块
template<class T>
class CFormat : public CAutoPtrArray<CFormatElem<T> >


格式数组模块
template<class T>
class CFormatArray : public CAutoPtrArray<CFormat<T> >


格式节点
template<class T>
class CFormatElem


CGoToDlg继承CDialog  转到对话框


CGraphCore / /我们需要打开/播放暂停/寻求/关闭/ VOL控制/子控制/音频和视频切换的类


CGraphThread继承CWinThread  播放线程类


CHexEdit继承CEdit  16进制编辑框


ChkDefPlayerControlBar继承 CSVPDialog  默认播放控制航


CIfo  文件信息类


CInfoReport继承CDialog  信息报告对话框


CInPlaceComboBox继承CComboBox  阙套下拉框


CInPlaceEdit继承CEdit  阙套编辑框


CInPlaceListBox继承CListBox  阙套列表框


CIntEdit继承CEdit   整形编辑框


CKeyProvider继承CUnknown,继承IServiceProvider  键盘提供者


CLineNumberEdit继承CEdit   线数编辑框


CLineNumberStatic继承CStatic  线数静态框




CMacrovisionKicker继承CUnknown,继承IKsPropertySet


主程序
CMainFrame继承CFrameWnd,继承CDropTarget,继承CGraphCore




CMediaFormatCategory   媒体格式分类


CMediaTypesDlg继承CResizableDialog  媒体类型对话框


CMemoryDC继承CDC   内存离屏DC


CMPlayerCApp继承CWinApp 启动类


CNEWOSDWnd继承CWnd  Osd窗体


ContentTypeTemp  内容类型


COpenCapDeviceDlg继承CResizableDialog  打开捕捉设备对话框


COpenDlg继承CResizableDialog  打开对话框


COpenFileDlg继承CFileDialog  打开文件对话框


COpenURLDlg继承CResizableDialog  打开URL 对话框


输出EVR
COuterEVR继承CUnknown,继承IVMRffdshow9,继承IVMRMixerBitmap9,继承IBaseFilter


输出VMR9
COuterVMR9继承CUnknown,继承IVideoWindow,
继承IBasicVideo2,继承IVMRWindowlessControl,继承IVMRffdshow9,继承IVMRMixerBitmap9


CPixelShaderCompiler  像素着色器编译器


CPlayerCaptureBar继承baseCPlayerCaptureBar  视频捕捉条


CPlayerCaptureDialog继承CResizableDialog //CDialog 视频捕捉对话框


CPlayerChannelNormalizer继承CSVPDialog  视频通道正规化对话框


CPlayerColorControlBar继承CSVPDialog  视频颜色控制条


CPlayerEQControlBar继承CSVPDialog   视频EQ控制条


CPlayerFloatToolBar继承CFrameWnd  视频浮动控制条


CPlayerListCtrl继承CListCtrl  播放器列表


CPlayerPlaylistBar继承CSizingControlBarG  播放器列表条


CPlayerSeekBar继承CDialogBar   视频跳转条


CPlayerShaderEditorBar继承baseCPlayerShaderEditorBar 视频着色编辑条


CPlayerToolBar继承CToolBar  视频工具条


CPlayerToolTopBar继承CWnd  视频上面的工具条


CPlayerWindow继承 CWnd  视频窗体


CPlaylist继承CList<CPlaylistItem>  播放列表


CPlaylistItem  播放列表节点


CPngImage继承CImage  处理png图片


CPnSPresetsDlg继承CCmdUIDialog  预设对话框


CPPageBase继承CCmdUIPropertyPage   基本属性页


CPPageFileInfoClip继承CPropertyPage 文件信息属性页


CPPageFileInfoDetails继承CPropertyPage  详细文件信息页


CPPageFileInfoRes继承CPPageBase  文件信息资源属性页


CPPageFileInfoSheet继承CPropertySheet  文件信息页


CPPageFileMediaInfo继承CPropertyPage  媒体文件信息


CPPageFormats  页格式


CResetDVD继承CDVDSession  重设DVD


CSaveDlg继承CCmdUIDialog  保存对话框


CSaveTextFileDialog继承CFileDialog  保存文本文件对话框


CSaveThumbnailsDialog继承CFileDialog  保存缩略图对话框


CSeekBarTip继承CWnd   赚到提示信息


CShaderAutoCompleteDlg继承CResizableDialog  着色自动完成对话框


CShaderCombineDlg继承CResizableDialog 着色连接对话框


CShaderEdit继承CLineNumberEdit  着色编辑框


CShaderEditorDlg继承CResizableDialog  着色编辑对话框


CShaderLabelComboBox继承CComboBox 着色下拉框


CShockwaveFlash继承CWnd   flash控件


CSUIBtnList继承CList<CSUIButton*>  按钮列表


CSUIButton  自绘按钮类


CSVPButton继承CButton   自绘按钮


CSVPDialog继承CWnd    自绘对话框


CSVPSliderCtrl继承CSliderCtrl  自绘Slider


CSVPStatic继承CStatic   自绘Static


CSVPSubUploadDl继承CResizableDialog  字幕上传对话框


CSVPSubVoteControlBar继承CSVPDialog 


CTextFile继承CStdioFile  操作文件类


CTextPassThruFilter继承CBaseFilter,继承CCritSec  文本直通过滤器


CTextPassThruInputPin继承CSubtitleInputPin  文本直通输入流


CTextPassThruOutputPin继承CBaseOutputPin  文本直通输出流


CTransparentControlBar继承CSVPDialog   透明控制条


CustomDrawBtn继承CButton  自定义按钮


CVidFormatArray继承CFormatArray<VIDEO_STREAM_CONFIG_CAPS>  视频格式集合


CVolumeCtrl继承CSliderCtrl  声音控件


CWebTextFile继承CTextFile  网站文本


FileAssoc   文件关联


FilterOverride  过滤器重叠


FrameCfgFileManage  窗体设置文件管理


GUIConfigManage GUI配置管理


哈希值管理
HashController继承LazyInstanceImpl<HashController>


HotkeyCmd继承ACCEL   快捷键


HotkeyController继承LazyInstanceImpl<HotkeyController>  快捷键控制


HotkeySchemeParser  快捷键计划分析器


LayeredWindowUtils  窗体单元


实例模版
template<class T>
class LazyInstanceImpl


template<class T>
class MainFrameSPlayerCmd


MakeMultiplyBmp


媒体中心管理
MediaCenterController继承LazyInstanceImpl<MediaCenterController>


媒体中心视图
MediaCenterView继承ATL::CWindowImpl<MediaCenterView>,继承MediaScrollbar,继承MediaListView


MediaCheckDB继承ThreadHelperImpl<MediaCheckDB>  媒体确认数据库


MediaDB  媒体数据库


MediaListView 媒体列表视图


MediaModel继承SourceModel<MediaData, MediaFindCondition>  媒体模式


MediaScrollbar  媒体滚动条


MediaSpiderAbstract继承ThreadHelperImpl<T> 媒体摘要


MediaSpiderFolderTree继承MediaSpiderAbstract<MediaSpiderFolderTree>  媒体摘要树


MediaSQLite  媒体SQL


MediaTreeModel 媒体树模式


MovieComment继承CDHtmlDialog  电影评论


NetworkControlerImpl 网络任务控制接口


OpenDeviceData继承OpenMediaData  设备打开方式


OpenDVDData继承OpenMediaData  DVD打开方式


OpenFileData继承OpenMediaData   文件打开方式


OpenMediaData  打开方式基类


建议选项属性页
OptionAdvancedPage继承WTL::CPropertyPageImpl<OptionAdvancedPage>,继承WTL::CWinDataExchange<OptionAdvancedPage>


关联文件属性页
OptionAssociationPage继承WTL::CPropertyPageImpl<OptionAssociationPage>,继承WTL::CWinDataExchange<OptionAssociationPage>


基本选项属性页
OptionBasicPage继承WTL::CPropertyPageImpl<OptionBasicPage>,继承WTL::CWinDataExchange<OptionBasicPage>


OptionDlg继承WTL::CPropertySheetImpl<OptionDlg>  选项对话框


第二字幕选项属性页
OptionSubtitlePage继承WTL::CPropertyPageImpl<OptionSubtitlePage>,继承WTL::COwnerDraw<OptionSubtitlePage>,继承WTL::CWinDataExchange<OptionSubtitlePage>


OSDController继承LazyInstanceImpl<OSDController> OSD控制


OSDView继承ATL::CWindowImpl<OSDView>,继承LayeredWindowUtils<OSDView> OSD视图


PlayerPreference继承LazyInstanceImpl<PlayerPreference>  播放器引用


PlaylistController继承LazyInstanceImpl<PlaylistController>  播放列表控制


PlaylistParser  播放列表分析


播放列表视图
PlaylistView继承ATL::CWindowImpl<PlaylistView>,继承WTL::COwnerDraw<PlaylistView>,继承 WTL::CCustomDraw<PlaylistView>


PlaylistViewMfcProxy继承CSizingControlBarG   播放列表代理


SkinDownload继承CDHtmlDialog,继承ThreadHelperImpl<SkinDownload> 皮肤下载


SkinFolderManager  皮肤管理类


SnapUploadController继承ThreadHelperImpl<SnapUploadController> 对齐上传控制器


源模式模块
template<class TDATA, class TCONDITION>
class SourceModel


SPlayerGUID 播放ID


SQLliteapp 操作数据库


ssftest  测试ssf


SubtitleStyle  内部风格指数提供了实际的映射  字幕渲染设置接受外部字幕滤镜。它还提供Windows基于GDI画画的能力
模拟渲染对话框显示的目的。


字幕透明控制
SubTransController继承ThreadHelperImpl<SubTransController>,继承NetworkControlerImpl


SubTransFormat  字幕透明格式


SUIVoteStar


SVPLycShowBox  //歌词显示面板 mouseover时显示半透明玻璃背景、关闭按钮和变色按钮,out后仅显示文字
//默认在屏幕底部区域显示,可以通过拖拽改变位置  关闭后改为在主窗口界面内显示


ThemePkg  主题背景


ThemePkgController 主题背景控制


TimeBmpManage 事件画面控制


 上传控制
UbdUploadController继承ThreadHelperImpl<UbdUploadController>,继承LazyInstanceImpl<UbdUploadController>


UnCompressZip  解压控制


 更新控制
UpdateController继承NetworkControlerImpl,继承ThreadHelperImpl<UpdateController>,继承LazyInstanceImpl<UpdateController>


用户着色控制
UserShareController继承NetworkControlerImpl,继承ThreadHelperImpl<UserShareController>,继承LazyInstanceImpl<UserShareController>


用户行为控制
UsrBehaviorController继承LazyInstanceImpl<UsrBehaviorController>


用户行为数据
UsrBehaviorData


今天主要针对  SPlayer 播放器项目的  CMPlayerc 分析

mplayerc  

   -->Model\appSQLite.h   主要负责操作sql  
      类成员成员中有两个成员
      SQLliteapp* sqlite_setting; 
      SQLliteapp* sqlite_local_record; 

      对sqlite_setting  分析

      在StoreSettingsToIni 产生一个对象  
      sqlite_setting = PlayerPreference::GetInstance()->GetSqliteSettingPtr();


      保存数据前 存在 则开始输出 BEGIN
      if(pApp->sqlite_setting){
pApp->sqlite_setting->begin_transaction();
}
      保存数据后 存在 则开始输出 END
      if(pApp->sqlite_setting){
pApp->sqlite_setting->end_transaction();
}

      读取整形数据
      if(sqlite_setting){
return sqlite_setting->GetProfileInt( lpszSection,  lpszEntry,  nDefault);
}else{
return __super::GetProfileInt( lpszSection,  lpszEntry,  nDefault);
}
}

       写入整形数据
if(sqlite_setting){
return sqlite_setting->WriteProfileInt( lpszSection,  lpszEntry,  nValue);
}else{
SVP_LogMsg6("dwqdwq");
return __super::WriteProfileInt( lpszSection,  lpszEntry,  nValue);
}

        读取字符集数据
if(sqlite_setting){
return sqlite_setting->GetProfileString( lpszSection,  lpszEntry,
lpszDefault );
}else{
return __super::GetProfileString( lpszSection,  lpszEntry,
lpszDefault );
}


        写入字符集数据
if(sqlite_setting){
return sqlite_setting->WriteProfileString( lpszSection,  lpszEntry,
lpszValue);
}else{
return __super::WriteProfileString( lpszSection,  lpszEntry,
lpszValue);
}

        读取二进制数据
if(sqlite_setting){
return sqlite_setting->GetProfileBinary( lpszSection,  lpszEntry,
ppData,  pBytes);
}else{
return __super::GetProfileBinary( lpszSection,  lpszEntry,
ppData,  pBytes);
}


        写入二进制数据
if(sqlite_setting){
return sqlite_setting->WriteProfileBinary( lpszSection,  lpszEntry,
pData,  nBytes);
}else{
return __super::WriteProfileBinary( lpszSection,  lpszEntry,
pData,  nBytes);
}

        对sqlite_setting 分析完
        对sqlite_local_record 分析
        在InitInstanceThreaded(INT64 CLS64) 函数中 产生对象


        sqlite_local_record = new SQLliteapp(tmPath.m_strPath.GetBuffer())
      
      判断是否打开数据库
      if(!sqlite_local_record->db_open)
      {
        delete sqlite_local_record;
        sqlite_local_record = NULL;
      }

      执行数据库  主要是创建表
      if(sqlite_local_record)
      {
        sqlite_local_record->exec_sql(L"CREATE TABLE  IF NOT EXISTS histories_stream (\"fpath\" TEXT, \"subid\" INTEGER, \"subid2\" INTEGER, \"audioid\" INTEGER, \"videoid\" INTEGER )");
        sqlite_local_record->exec_sql(L"CREATE UNIQUE INDEX  IF NOT EXISTS \"hispks\" on histories_stream (fpath ASC)");


        sqlite_local_record->exec_sql(L"CREATE TABLE  IF NOT EXISTS histories (\"fpath\" TEXT, \"subid\" INTEGER, \"subid2\" INTEGER, \"audioid\" INTEGER, \"stoptime\" INTEGER, \"modtime\" INTEGER )");
        sqlite_local_record->exec_sql(L"CREATE UNIQUE INDEX  IF NOT EXISTS \"hispk\" on histories (fpath ASC)");
        sqlite_local_record->exec_sql(L"CREATE INDEX  IF NOT EXISTS \"modtime\" on histories (modtime ASC)");


        sqlite_local_record->exec_sql(L"CREATE TABLE  IF NOT EXISTS settingstring (\"hkey\" TEXT, \"sect\" TEXT, \"vstring\" TEXT )");
        sqlite_local_record->exec_sql(L"PRAGMA synchronous=OFF");
        //sqlite_local_record->end_transaction();
      }

      在退出程序的时候  ExitInstance()
  if(sqlite_local_record){
   CString szSQL;
   szSQL.Format(L"DELETE FROM histories WHERE modtime < '%d' ", time(NULL)-3600*24*30);
   
// SVP_LogMsg5(szSQL);
   
sqlite_local_record->exec_sql(szSQL.GetBuffer());
   
sqlite_local_record->exec_sql(L"PRAGMA synchronous=ON");
  }
  if (sqlite_local_record)    delete sqlite_local_record;
$(ConfigurationName)


以上是针对主程序播放视频的分析。


ChuckTest工程 是针对rar包里的测试项目,测试代码如下:

int _tmain(int argc, _TCHAR* argv[])
{
  HANDLE rar_handle = NULL;
  //std::wstring fn_rar = L"E:\\-=eMule=-\\1140746814_39741.rar";
  //std::wstring fn_rar = L"E:\\-=eMule=-\\Bride.Flight.2008.Bluray.720p.AC3.x264-CHD_新娘航班\\B2_新娘航班.part1.rar";
  //std::wstring fn_rar = L"D:\\xxxx.part1.rar";
  std::wstring fn_rar = L"E:\\-=eMule=-\\Overheard.2009.REPACK.CN.DVDRip.Xvid-XTM\\sample\\xtm-overheard.repack-sample_stored.rar";
  //std::wstring fn_rar = L"E:\\-=eMule=-\\Overheard.2009.REPACK.CN.DVDRip.Xvid-XTM\\sample\\xtm-overheard.repack-sample_s.part1.rar";
  
  std::wstring tmp_dir = L"C:\\Temp\\";
  
  struct RAROpenArchiveDataEx ArchiveDataEx;
  memset(&ArchiveDataEx, 0, sizeof(ArchiveDataEx));
  
  ArchiveDataEx.ArcNameW = (wchar_t*)fn_rar.c_str();
  //ArchiveDataEx.ArcName = "E:\\-=eMule=-\\1140746814_39741.rar";

  ArchiveDataEx.OpenMode = RAR_OM_EXTRACT;
  ArchiveDataEx.CmtBuf = 0;
  rar_handle = RAROpenArchiveEx(&ArchiveDataEx);

  const long buffsize = 1000;
  char testbuff[buffsize];

  if (rar_handle)
  {
    wprintf(L"RAROpenArchiveEx open successed\n");
    struct RARHeaderDataEx HeaderDataEx;
    HeaderDataEx.CmtBuf = NULL;
    while (RARReadHeaderEx(rar_handle, &HeaderDataEx) == 0)
    {
      // 正常解压该文件
      unsigned long long filesize = ((unsigned long long)HeaderDataEx.UnpSizeHigh << 32) + HeaderDataEx.UnpSize;
      int err = 0;
      std::wstring unp_tmpfile = tmp_dir + HeaderDataEx.FileNameW;
      err = RARProcessFileW(rar_handle, RAR_EXTRACT, (wchar_t*)tmp_dir.c_str(), HeaderDataEx.FileNameW);
      wprintf(L"RARProcessFileW to %s return %d size %lld %x %x\n", unp_tmpfile.c_str(), err, filesize, HeaderDataEx.UnpVer, HeaderDataEx.Method);
    }
    RARCloseArchive(rar_handle);
  }

  rar_handle = RAROpenArchiveEx(&ArchiveDataEx);
  if (rar_handle)
  {
    wprintf(L"RAROpenArchiveEx open successed\n");
    struct RARHeaderDataEx HeaderDataEx;
    HeaderDataEx.CmtBuf = NULL;
    while (RARReadHeaderEx(rar_handle, &HeaderDataEx) == 0)
    {
      unsigned long long filesize = ((unsigned long long)HeaderDataEx.UnpSizeHigh << 32) + HeaderDataEx.UnpSize;
      int err = 0;
      std::wstring unp_tmpfile = tmp_dir + HeaderDataEx.FileNameW;
      err = RARExtractChunkInit(rar_handle, HeaderDataEx.FileName);
      if (err != 0)
      {
        wprintf(L"RARExtractChunkInit return error %d\n", err);
        continue;
      }

      FILE* unp_filehandle = NULL;
      err = _wfopen_s(&unp_filehandle, unp_tmpfile.c_str(), L"rb");
      if (err)
      {
        wprintf(L"open extracted file fail %d %d\n", err, unp_filehandle);
        continue;
      }

      
      // 顺序测试
      int iExtractRet = 0;
      unsigned long long fpos = 0;
      do
      {
        iExtractRet = RARExtractChunk(rar_handle, (char*)testbuff, buffsize);
        // Compare 
        if (compare_filebinary(unp_filehandle, fpos, testbuff, iExtractRet, 0))
        {
          wprintf(L"Sequence compare difference found at %lld for %d\n", fpos, buffsize);
          break;
        }
        //else
        //  wprintf(L"Sequence compare is same %lld %d\n", fpos, iExtractRet);

        fpos += iExtractRet;
      } while(iExtractRet > 0);

      // 随机测试
      for (int i = 0; i < 100; i++)
      {
        unsigned long long ll_pos = rand() * filesize/RAND_MAX;
        RARExtractChunkSeek(rar_handle, ll_pos, SEEK_SET);
        RARExtractChunk(rar_handle, (char*)testbuff, buffsize);
        // Compare 
        if (compare_filebinary(unp_filehandle, ll_pos, testbuff, iExtractRet, 0))
        {
          wprintf(L"Random compare difference found at %lld\n", ll_pos);
          break;
        }
        //else
        //  wprintf(L"Random compare is same %lld\n", ll_pos);
      }
      wprintf(L"RARExtractChunk test for %s finished\n", unp_tmpfile.c_str());
    }
    RARCloseArchive(rar_handle);
  }
  wprintf(L"Test finished\n");
  scanf_s("%d");
	return 0;
}
//字符切换
std::string WStringToString(const std::wstring& s)
{
  char* ch;
  UINT bytes = WideCharToMultiByte(CP_ACP, 0, s.c_str(), -1, NULL, 0,
    NULL, NULL); 
  ch = new char[bytes];
  if(ch)
    bytes = WideCharToMultiByte(CP_ACP, 0, s.c_str(), -1, ch, bytes,
    NULL, NULL);
  std::string str = ch;
  delete[] ch;
  return str;
}

//比较文件
int compare_filebinary(FILE* filehandle, unsigned long long filepos, char* buff, unsigned long buffsize, int debug)
{
  char *fbuf = (char *)malloc(buffsize);
  _fseeki64(filehandle, filepos, SEEK_SET);
  fread_s(fbuf, buffsize, sizeof(char), buffsize, filehandle);
  int ret = memcmp(buff, fbuf, buffsize);
  
  if (debug)
  {
    for (int i = 0;i < 100;i++)
      wprintf(L"%02x", (DWORD)buff[i] & 0xff);
    wprintf(L"\n");
    for (int i = 0;i < 100;i++)
      wprintf(L"%02x", (DWORD)fbuf[i] & 0xff);
    wprintf(L"\n");
  }

  free(fbuf);
  return ret;
}


HotkeySchemeParser_UnitTest 是针对热键计划分析器单元测试,测试代码如下:

//热键计划分析器单元测试
int _tmain(int argc, _TCHAR* argv[])
{
  HotkeySchemeParser parser;
  printf("HotkeySchemeParser unit test\n");
  printf("----------------------------------------------------------\n");
  printf("Populating default scheme (HotkeySchemeParser::PopulateDefaultScheme) ...\n");
  parser.PopulateDefaultScheme();
  printf("Attempting to write scheme file (HotkeySchemeParser::WriteToFile) ... ");
  if (!parser.WriteToFile(L"SPlayerHotKey.txt"))
  {
    printf("[FAILED]\n");
    return 0;
  }
  printf("[OK]\n");
  printf("Attempting to read scheme file (HotkeySchemeParser::ReadFromFile) ... ");
  if (!parser.ReadFromFile(L"SPlayerHotKey.txt"))
  {
    printf("[FAILED]\n");
    return 0;
  }
  printf("[OK]\n");

  //目标键
  HotkeySchemeParser target;
  target.PopulateDefaultScheme();
  printf("Comparing results (scheme name)... ");
  if (target.GetSchemeName() != parser.GetSchemeName())
  {
    printf("[ERROR]\n");
    return 0;
  }
  printf("[OK]\n");
  printf("Comparing results (list)... ");
  std::vector<HotkeyCmd> parser_list = parser.GetScheme();
  std::vector<HotkeyCmd> target_list = target.GetScheme();
  if (parser_list.size() != target_list.size())
  {
    printf("[SIZE MISMATCH]\n");
    return 0;
  }
  for (std::vector<HotkeyCmd>::iterator it1 = parser_list.begin(),
    it2 = target_list.begin();
    it1 != parser_list.end(),
    it2 != target_list.end();
    it1++, it2++)
  {
    if (it1->cmd != it2->cmd ||
      it1->key != it2->key ||
      it1->fVirt != it2->fVirt ||
      it1->appcmd != it2->appcmd ||
      it1->mouse != it2->mouse)
    {
      printf("[ERROR @ %d]\n", std::distance(parser_list.begin(), it1));
      return 0;
    }
  }
  printf("[OK]\n");

	return 0;
}
sqliteppTest 是针对第三方库sqlitepp操作数据库的测试,测试代码如下:

/* step0 init - *******************
*first check del file Testsqlite.db*/

const wchar_t *filename=L"./Testsqlite.db";
const wchar_t *sqlc1=L"CREATE TABLE IF NOT EXISTS \"settingint\" (\"hkey\" TEXT,\"sect\" TEXT,\"sval\" INTEGER)";
const wchar_t *sqlc2=L"CREATE TABLE IF NOT EXISTS \"settingstring\" (\"hkey\" TEXT,   \"sect\" TEXT, \"vstring\" TEXT)";
const wchar_t *sqlc3 = L"CREATE TABLE IF NOT EXISTS \"settingbin2\" (\"skey\" TEXT,   \"sect\" TEXT, \"vdata\" BLOB)";
const wchar_t *sqlc4 = L"CREATE UNIQUE INDEX IF NOT EXISTS \"pkey\" on settingint (hkey ASC, sect ASC)";
const wchar_t *sqlc5 = L"CREATE UNIQUE INDEX IF NOT EXISTS \"pkeystring\" on settingstring (hkey ASC, sect ASC)";
const wchar_t *sqlc6 = L"CREATE UNIQUE INDEX IF NOT EXISTS \"pkeybin\" on settingbin2 (skey ASC, sect ASC)";

//定义
TCHAR path[MAX_PATH] = {0};
::GetModuleFileName(NULL,path,MAX_PATH);
CStringW strSQL(path);
strSQL.Replace(_T("TestSqlite.exe"),_T("Testsqlite.db"));

int i=0;
std::wstring sql,sql2,sql3,sql4,sql5;
SQLliteapp p(strSQL.GetBuffer());  //构造会创建数据库文件

/* step1 : Create Table 执行sql语句 创建表 字段 数值*/
p.exec_sql(sqlc1);
p.exec_sql(sqlc2);
p.exec_sql(sqlc3);
p.exec_sql(sqlc4);
p.exec_sql(sqlc5);
p.exec_sql(sqlc6);

std::wstring str1=L"hello";
std::wstring str2=L"world";

/* step2 int-test  *******************
 *
 *   write int - WriteProfileInt
 get int - GetProfileInt compare    写入 读取整形数值 比较
  ************************************/
{
int geti1=1;
int geti2=100;

geti1=p.WriteProfileInt(str2.c_str(),str1.c_str(),-10,false);
int test01=p.GetProfileInt(str2.c_str(),str1.c_str(),10,false);
if(geti1)
printf("pass -- 1 \n");
else
printf("fail -- 1 \n");
p.WriteProfileInt(str1.c_str(),str2.c_str(),geti2,false);
geti1=p.GetProfileInt(str1.c_str(),str2.c_str(),-1,false);
if(geti2==geti1)
printf("pass -- 2 \n");
else
printf("fail -- 2 \n");
}

/* step3 string-test  ***************
 *
 *   write str - WriteProfileString
get str - GetProfileString
compare    写入 读取 字符集比较
 ************************************/
{
std::wstring str3s1, str3s2;
str3s1 = L"ss";
str3s2 = L"hello你好\n";
str3s1 = p.GetProfileString(str2.c_str(), str1.c_str(),L"xx",false);

if(str3s1 == L"xx")
printf("pass--3\n");   // ok
else
printf("fail--3\n");

p.WriteProfileString(str1.c_str(), str2.c_str(), str3s2.c_str());
str3s1 = p.GetProfileString(str1.c_str(), str2.c_str(), L"xx",false);

if(str3s1.compare(str3s2) == 0)
printf("pass--4\n");   // ok
else
printf("fail--4\n");
}

/* step4 binrary-test  **************
 *
 *   write bin
 get bin - donot forget new/delete   写入 读取 二进制文件
 **************************************/
{
char *pp = 0; //donot forget new/delete
char buf[100];
char str3[] = "hello4";
char str4[] = "world4";

for(i=0;i<80;i++)
{
buf[i] = i * 3 % 5 + 2;
}

int bPass=0;    //成功的话 bPass 返回个数
p.GetProfileBinary(str2.c_str(), str1.c_str(),(LPBYTE*)&pp,(UINT*)&bPass,false);

if( bPass == 0 )
printf("pass--5 bin\n");
else
printf("fail--5 bin\n");

if(i>0 && pp)
{
delete[] pp;
pp = NULL;
}

p.WriteProfileBinary(str1.c_str(), str2.c_str(), (LPBYTE)buf, 80); //w 80 BYTE
p.GetProfileBinary(str1.c_str(), str2.c_str(), (LPBYTE*)&pp, (UINT*)&bPass, false); //成功的话 bPass 返回个数

if(memcmp(pp,buf,30) == 0)
printf("pass--6 bin\n");
else
printf("fail--6 bin\n");

if(bPass>0 && pp)
{
delete[] pp;
pp = NULL;
}
}

 分析到此就结束了!~这是我针对这SPlayer项目的简单分析!

 学习的目标是成熟!~~~




  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值