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,  //分配器演示使用这个接口进行通信的VMRpublic 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);//打开DVDvoid 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;}猜测 关闭MediaSendMessage(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里面保存了路径和rtStartCAutoPtr<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 logom_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());elseOpenMediaPrivate(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;设置Sliderm_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" initiallyPostMessage(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);}}elseSendStatusMessage(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; // generalpVW = pGB; pBV = pGB; // videopBA = pGB; // audiopFS = 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 wayhr = 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 wayhr = 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;EndEnumFiltersUINT 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();查找过滤接口  并添加到pBFsCInterfaceList<IBaseFilter> pBFs;BeginEnumFilters(pGB, pEF, pBF) pBFs.AddTail(pBF);EndEnumFiltersPOSITION 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);}}}}}EndEnumFiltersCleanGraph();
}进入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{// TESTMEpVW->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;不能进入暂停状态,从停止使用rmif(fs == State_Stopped && pCmdUI->m_nID == ID_PLAY_PAUSE && m_fRealMediaGraph) fEnable = false; // can't go into paused state from stopped with rmelse 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);// HACKCRect 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 rmelse 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 statepMC->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 Controlm_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 displayedUpdateSubtitle(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 sillyif(!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_bEVRInUseSVP_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 filem_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 theadm_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);}EndEnumPinsm_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*500pCI->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 infiniteCleanGraph();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()){   用户区域UIm_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 ratioint 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 zoomw = 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 screenif (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);}elsem_pCAP->SetTime(/*rtNow*/m_wndSeekBar.GetPos());}elsem_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 aRefTimerSeekTo(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_INDETERMINATEswitch (GetMediaState()){case State_Paused://not using TBPF_PAUSED since it hide progresspTBL->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;}}elsepTBL->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);elsem_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){//如果是1CDint 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 subtitleLogging(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 subtitleLogging((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继承ISubPicAllocatorPresenterImplCDXRAllocatorPresenter继承ISubPicAllocatorPresenterImplVMR7分配器
CVMR7AllocatorPresenter继承CDX7AllocatorPresenter,继承IVMRSurfaceAllocator,继承IVMRImagePresenter,继承IVMRWindowlessControlVMR9分配器
CVMR9AllocatorPresenter继承CDX9AllocatorPresenter,继承IVMRSurfaceAllocator9,继承IVMRImagePresenter9, 继承IVMRWindowlessControl9CGenlock   管理视频和显示的同步。VR分配器
CmadVRAllocatorPresenter继承ISubPicAllocatorPresenterImplQT7分配器
CQT7AllocatorPresenter继承CDX7AllocatorPresenter,继承IQTVideoSurfaceQT9分配器
CQT9AllocatorPresenter继承CDX9AllocatorPresenter,继承IQTVideoSurfaceQuicktime格式绘图
CQuicktimeGraph继承CBaseGraph,继承IVideoFrameStepQuicktime载体
CQuicktimeWindow继承CPlayerWindowReal格式绘图
CRealMediaGraph继承CBaseGraphReal格式播放
CRealMediaPlayer继承CUnknown,继承IRMAErrorSink,继承IRMAClientAdviseSink,继承IRMAAuthenticationManager,继承IRMASiteSupplier,继承IRMAPassiveSiteWatcher,继承IRMAAudioHookReal格式播放载体
CRealMediaPlayerWindowed继承CRealMediaPlayerReal格式播放载体
CRealMediaPlayerWindowless继承CRealMediaPlayerReal格式视频面
CRealMediaVideoSurface继承CUnknown,继承IRMAVideoSurfaceReal格式载体站点
CRealMediaWindowlessSite继承CUnknown,继承IRMASite,继承IRMASite2,继承IRMASiteWindowless,继承IRMAVideoSurfaceRM7分配器
CRM7AllocatorPresenter继承CDX7AllocatorPresenter,继承IRMAVideoSurfaceRM9分配器
CRM9AllocatorPresenter继承CDX9AllocatorPresenter,继承IRMAVideoSurfaceFlash绘图
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 IGraphEngineclass CBtnAlign  按钮位置区域对齐类自绘了Edit类 阙套了Button
class CBtnEditCtrl继承CWindowImpl<CBtnEditCtrl, CEdit>CChildView继承CWnd  窗体类 实现了视频载体COM组件属性页站点
CComPropertyPageSite继承CUnknown,继承IPropertyPageSiteCConvertChapDlg继承CResizableDialog 转换章节对话框CConvertDlg继承CResizableDialog  转换对话框CConvertPropsDlg继承CResizableDialog 转换属性页对话框CConvertResDlg继承CResizableDialog 转换资源对话框分行过滤器
CDeinterlacerFilter继承CTransformFilterCDisplaySettingDetector 显示设置探测器CDlgChkUpdater继承CDialog  确认更新对话框CDropTarget  移动文件类EVR分配器
CEVRAllocatorPresenter继承CDX9AllocatorPresenter,继承IMFGetService,继承IMFTopologyServiceLookupClient,继承IMFVideoDeviceID,继承IMFVideoPresenter,继承IDirect3DDeviceManager9,继承IMFAsyncCallback,继承IQualProp,继承IMFRateSupport,继承IMFVideoDisplayControl,继承IEVRTrustedVideoPlugin渐变视频解码
CFakeDirectXVideoDecoder继承CUnknown,继承IDirectXVideoDecoderCFavoriteAddDlg继承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, 继承CCritSecCFGManagerCapture继承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 CFormatElemCGoToDlg继承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,继承CGraphCoreCMediaFormatCategory   媒体格式分类CMediaTypesDlg继承CResizableDialog  媒体类型对话框CMemoryDC继承CDC   内存离屏DCCMPlayerCApp继承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,继承IVMRMixerBitmap9CPixelShaderCompiler  像素着色器编译器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  重设DVDCSaveDlg继承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  自绘SliderCSVPStatic继承CStatic   自绘StaticCSVPSubUploadDl继承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 LazyInstanceImpltemplate<class T>
class MainFrameSPlayerCmdMakeMultiplyBmp媒体中心管理
MediaCenterController继承LazyInstanceImpl<MediaCenterController>媒体中心视图
MediaCenterView继承ATL::CWindowImpl<MediaCenterView>,继承MediaScrollbar,继承MediaListViewMediaCheckDB继承ThreadHelperImpl<MediaCheckDB>  媒体确认数据库MediaDB  媒体数据库MediaListView 媒体列表视图MediaModel继承SourceModel<MediaData, MediaFindCondition>  媒体模式MediaScrollbar  媒体滚动条MediaSpiderAbstract继承ThreadHelperImpl<T> 媒体摘要MediaSpiderFolderTree继承MediaSpiderAbstract<MediaSpiderFolderTree>  媒体摘要树MediaSQLite  媒体SQLMediaTreeModel 媒体树模式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 SourceModelSPlayerGUID 播放IDSQLliteapp 操作数据库ssftest  测试ssfSubtitleStyle  内部风格指数提供了实际的映射  字幕渲染设置接受外部字幕滤镜。它还提供Windows基于GDI画画的能力
模拟渲染对话框显示的目的。字幕透明控制
SubTransController继承ThreadHelperImpl<SubTransController>,继承NetworkControlerImplSubTransFormat  字幕透明格式SUIVoteStarSVPLycShowBox  //歌词显示面板 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();保存数据前 存在 则开始输出 BEGINif(pApp->sqlite_setting){
pApp->sqlite_setting->begin_transaction();
}保存数据后 存在 则开始输出 ENDif(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 - WriteProfileIntget 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 binget 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项目的简单分析!

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

开源项目之Splayer 射手影音播放器相关推荐

  1. 强大的多媒体播放器:射手影音播放器SPlayer for Mac

    射手影音SPlayer for Mac是一款功能齐全的媒体播放器,射手影音能够播放几乎所有类型的视频文件.splayer具有内置翻译系统,集成了实时语音识别和NLP(自然语言改进)技术,可帮助您添加字 ...

  2. 修改射手影音播放器字幕保存路径的两种方法

    射手影音播放器--高清时代必备的美剧播放利器,除了轻巧的体积和易用的操作,最大的亮点莫过于可以通过射手网智能匹配下载字幕.不知出于何种考虑,在新版的射手影音中取消了很多高级设置,比如修改字幕保存路径的 ...

  3. Android播放器开源项目,github常用视频音频播放器

    需求: 搜集到的github常用的视频和音频播放器,其中前三个是比较常用的播放器. 第四个和第五个是比较直白的用法. 1.ijkplayer 项目地址: https://github.com/Bili ...

  4. 【Android】Android开源项目(一)音乐播放器源码汇总

    作为一个有追求的程序员来说,项目源码必须看,但是网上那么多资源是不让你无从下手啊,博主今天为大家推荐五个经典项目吧. 一.android-UniversalMusicPlayer 这个开源项目展示了如 ...

  5. Android开源项目(一)音乐播放器

    作为一个有追求的程序员来说,项目源码必须看,但是网上那么多资源是不让你无从下手啊,博主今天为大家推荐五个经典项目吧. 一.android-UniversalMusicPlayer 这个开源项目展示了如 ...

  6. Studio项目实战开发手机影音播放器(Android版)

    AndroidStudio项目实战开发安卓播放器(手机影音) 下载地址:百度网盘

  7. 项目源码--Android3D影音播放器源码

      下载源码   技术要点: 1.本地音乐管理 2.音频流的解码 3. UI控件的综合使用 4. 视频流的解码 5. 动态更换皮肤 6. 3D效果的实现 7. 源码带详细的中文注释 ...... 详细 ...

  8. CMP FLASH影音播放器插件

    我搜索视频播放插件很久了,一直没有找到合适的(要么功能不完善.要么有水印.要么界面不美观),今天终于找到了一个不错的视频播放插件--CMP4 Flash 影音播放器插件. CMP是一款免费的在线Fla ...

  9. C++基础入门:实现类似暴风影音的影音播放器!(源码展示)

    VC++影音播放器源代码,基于DX技术实现,常规的WAV/MP3/AVI/WMV等格式都能很好的支持.界面酷似早期的暴风影音播放器,那种经典风格的. 项目如下: 代码如下: 众所周知,RTMP是以fl ...

最新文章

  1. ContentProvider是如何实现数据共享的
  2. Toad Oracle 本地/远程数据库导入/导出 数据库备份
  3. 在 ASP.NET MVC 中使用 Chart 控件
  4. Python回顾与整理10:模块
  5. jquery技巧(持续更新。。)
  6. 成功解决安装cuda的时候,下载的文件自动消失,并且出现An unknown error has occurred
  7. postgresql测试题_PostgreSQL练习
  8. ios 支付宝支付 回调数据_iOS逆向支付宝
  9. PHP 文件夹操作「复制、删除、查看大小」递归实现
  10. 使用Express开发小说API接口服务1.0(二)
  11. Springboot 读取配置文件
  12. iPhone 13 Pro苍岭绿真机首曝!网友:这次iPhone被渲染图坑惨了
  13. 机器学习:用正规方程法求解线性回归
  14. 指数/对数/WIN10计算器
  15. Swarm-BZZ踩坑日记之 如何在Linux下使用docker开30个bzz节点
  16. ffmpeg给视频加水印
  17. Hadoop退出安全模式
  18. Linux搭建MQTT服务器(mosquitto)并使用
  19. i2c-tool调试工具使用方法介绍
  20. 在线教育网站如何更好的实现视频安全视频保护?

热门文章

  1. APT攻击各阶段简介
  2. 第五十四篇 电子负载操作说明
  3. OpenCV实战(二)——答题卡识别判卷
  4. 我想这就是我选择模板自助建站平台的原因
  5. 高中数学学习的方法之学霸学习4大法宝
  6. 博弈论与机制设计(Y.内拉哈里)思路图
  7. 登录时“自动填充”和“验证码”的实现
  8. 2007安全焦点信息安全技术峰会有感
  9. android 停止一段时间,repo sync 工作一段时间后就停止了
  10. prototype详解