| XPYcn's profileMemoryJBlogListsGuestbook | Help |
|
August 22 文本与二进制今天写VOB Demux的时候,demux产生的音视频文件播放不了。经过调试发现解析过程全都能正确鸡西,但是将结果写入之后就出错。最后发现是fwrite在搞鬼,如果文件以文本模式打开,它会将buf中所有“回车”转换为“回车+换行”。顺便学习一下文本模式和二进制模式打开文件的区别。
转一篇“fopen,文本文件與二進制文件 ”
在學習C語言文件操作後,我們都會知道打開文件的函數是fopen,也知道它的第二個參數是標誌字符串。其中,如果字符串中出現'b',則表明是以打開二進制(binary)文件,否則是打開文本文件。
那麼甚麼是文本文件,甚麼是二進制文件呢? 可能大多數人都沒有仔細考慮過。 在Windows和DOS系統中,狹義的文本文件是指擴展名為txt的文件。實際上,那些沒有規定格式的,由可理解的的ASCII以及其他編碼文字組成的文件都是文本文件,如C源程序文件,HTML超文本,XML。除此之外的其他文件都是二進制文件,如Word文件DOC,圖像格式文件JPG。 但是,所謂使用fopen標誌打開文本文件與二進制文件的說法並不準確。正確的說法應該是--以文本方式和二進制方式打開文件。因為我們用兩種方式都可以任意的文件。 即使這樣,為甚麼還要區分這兩種方式呢? 這是因為這兩種方式在讀寫文件時的操作是不一樣的。 二進制方式很簡單,讀文件時,會原封不動的讀出文件的全部內容,寫的時候,也是把內存緩衝區的內容原封不動的寫到文件中。 而文本方式就不一樣了,在讀文件時,會將換行符號CRLF(0x0D 0x0A)全部轉換成單個的0x0A,並且當遇到結束符CTRLZ(0x1A)時,就認為文件已經結束。相應的,寫文件時,會將所有的0x0A換成0x0D0x0A。 所以,若使用文本方式打開二進制文件時,就很容易出現文件讀不完整,或內容不對的錯誤。即使是用文本方式打開文本文件,也要謹慎使用,比如複製文件,就不應該使用文本方式。 要特別注意的是,上面這樣的說法僅適用于DOS和Windows系統。在Unix和其他一些系統中,沒有文本方式和二進制方式的區分,使不使用'b'標誌都是一樣的。這是由于不同操作系統對文本文件換行符的定義,和C語言中換行符的定義有所不同而造成的。 如上文已提到,DOS和Windows系統使用CRLF(0x0D 0x0A)雙字節作為文本文件換行符,而Unix文本文件的換行符只有一個字節LF(0x0A)為。在C語言中,也是以LF即'\n'為換行符。 由於DOS/Windows定義的換行符和C語言的不一致,C語言的標準輸入輸出函數進行讀寫文本文件時,就進行了CRLF->LF的轉換。而Unix的定義和C語言的是一樣的,就不必轉換了。 那麼,為甚麼會有定義不一致的情況呢,這純屬歷史原因。當初C是在Unix上發展的,對換行的定義自然就一樣了。其後C被引入到DOS系統,為了使原有的C程序能不加修改的讀寫DOS的文本文件,所以就在文件讀寫上做了修改。隨著DOS/Windows成為主流平台,這個當初為了兼容而做的修改給眾多的C語言開發者添了這樣一個小小的麻煩。 August 20 [ZZ]Where Are We Heading?
The paradox of our time in history is that we have taller buildings, but shorter tempers; wider freeways, but narrower viewpoints; we s
我们这个时代在历史上的说法就是我们拥有更高的建筑,但是有更暴的脾气;我们拥有更宽阔的高速公路,却有更狭隘的观点;我们花费得更多,拥有得却更少;我们购买得更多却享受得更少。 We have bigger houses and smaller families; more conveniences, but less time; we have more degrees, but less sense; more knowledge, but less judgment; more experts, but more problems; more medicine, but less wellness. 我们的房子越来越大,家庭却越来越小;便利越来越多,时间却越来越少;学位越来越多,感觉却越来越少;知识越来越多,观点却越来越少;专家越来越多,问题也越来越多;药物越来越多,福利却越来越少。 We drink too much, spend too recklessly, laugh too little, drive too fast, get too angry too quickly, stay up too late, get up too tired, read too little, watch TV too much, and pray too seldom. 我们喝得太多,花钱大手大脚,笑得太少,开车太快,易怒,熬夜,赖床,书读得越来越少,电视看得越来越多,却很少向上帝祈祷。 We talk too much, love too seldom, and hate too often. We've learned how to make a living, but not a life; we've added years to life, not life to years. 我们常常夸夸其谈,却很少付出爱心,且常常心中充满了仇恨。我们学会了如何谋生,而不知如何生活。我们延长了生命的期限,而不是生活的期限。 We've been all the way to the moon and back, but have trouble crossing the street to meet the new neighbor. We've conquered outer space, but not inner space; we've done larger things, but not better things. 我们登上了月球,并成功返回,却不能穿过街道去拜访新邻居。我们已经征服了太空,却征服不了自己的内心;我们的事业越做越大,但质量却没有提高。 We've cleaned up the air, but polluted the soul; we've split the atom, but not our prejudice. We write more, but learn less; we plan more, but accomplish less. 我们清洁了空气,却污染了灵魂;我们分离了原子,却无法驱除我们的偏见;我们写得更多,学到的却更少;我们的计划更多,完成的却更少。 We've learned to rush, but not to wait; we have higher incomes, but, lower morals. 我们学会了奔跑,却忘记了如何等待;我们的收入越来越高,道德水平却越来越低。 We build more computers to hold more information to produce more copies than ever, but have less communication; we've become long on quantity, but short on quality. 我们制造了更多的计算机来存储更多的信息,制造了最多的副本,却减少了交流;我们开始渴望数量,但忽视了质量。 These are the days of two incomes, but more divorce; of fancier houses, but more broken homes. 这个时代有双收入,但也有了更高的离婚率;有更华丽的房屋,却有更多破碎的家庭。 These are the days of quick trips, disposable diapers, throw away morality, one night stands, overweight bodies, and pills that do everything from cheer, to quiet, to kill. Where are we heading...? 这个时代有了快速旅游,免洗尿布,却抛弃了道德、一夜情、超重的身体,以及可以从快乐中走向静止和自杀的药物。我们将走向何方……? If we die tomorrow, the company that we are working for could easily replace us in a matter of days. But the family we left behind will feel the loss for the rest of their lives. 如果我们明天就死掉,我们为之工作的公司可能会在一天内很轻易地找人代替我们的位置。但是当我们离开家人后,他们的余生将会在失落中度过。 And come to think of it, we pour ourselves more into work than to our family an unwise investment indeed. 考虑一下吧,我们将自己的时间更多地投入到工作中,而放弃与家人在一起的时光,实在并非明智之举。 So what is the morale of the story??? 那么这则故事的主旨是什么呢??? Don't work too hard... and you know what's the full word of family? 不要工作得太辛苦,你知道家的全称吗? FAMILY = (F)ATHER (A)ND (M)OTHER, (I) (L)OVE (Y)OU. 家=爸爸妈妈,我爱你们。 August 13 新的一周开始了周末总是很快,还没眨眼就完了:)
周六买了个浮力森林的8寸蛋糕,再买了螃蟹、虾若干,跟女朋友和她表妹一起庆祝俺25小寿。偶发现原来浮力森林蛋糕也就那样,不过她两个一边喊着减肥、一边说真好吃。接着他表妹说了句经典的话:“女人的嘴巴有两个用处!一是吃东西,二是说别人的闲话!”,想想还真是非常有道理啊。
先不乱弹了,开始hard working August 10 身体是革命的本钱 记得那是来公司的第二个星期四的早上,那天坐在座位上突然感觉右下腹隐隐的疼了两下。那个疼跟去年在西安诊断出来是阑尾炎时的疼一样,感觉很不好。果然没过一会疼痛加剧,突然之间两眼一黑什么都看不见了。过了一下能看清东西的时候,感觉自己失意了一样,不知道自己在哪里、在干吗。就这种状态持续了将近半分钟,才回复意识,于是马上告诉旁边的同事。之后导师和哪位同事一起送我到最近的医院。
在医院检查的时候我先告诉医生可能是阑尾炎复发,结果医生检查之后告诉我绝对不是阑尾炎。于是很庆兴当时武警医院叫我做阑尾手术时,在自己的坚持下没做。同时也对武警医院的不负责任感到愤慨和无奈。不过不幸的是那天在医院之后腹部就不是那么疼了,以至于花了300检查之后没有任何结果,医生只好告知“你没问题,可以回去了”。后来自己怀疑可能是急性肠胃炎,或是肠抽筋。反正到现在也不知到是什么原因:( 经过这事之后,现在开始非常注意身体。一个好的身体真的是需要自己好好努力保养才行。
说一下我现在的一些行动:睡觉不敢睡太晚,晚饭不敢吃太多,晚上也不敢吃东西,冰的东西基本不吃,不抽烟,少喝酒。准备办个游泳卡,加强身体锻炼。
new life研一时,不知哪天老师喊了个“小朋友”,于是这个小名就伴随了我三年。说起来还真怀念那时候的日子,怀念被亲切的叫成xpy;怀念半夜打完war rpg,楼道里静悄悄的感觉;怀念周末3个人出去找地方腐败;怀念老师和zt在宿舍讨论问题的情景…… 不知不觉开始第一份工作已经1个多月了,公司环境和团队内的氛围总体感觉还很不错,做的东西目前自己也比较感兴趣。就是再也没人亲切的喊我xpy了,555~~~~~~ May 14 [ZZ]可变参数函数原文地址:http://blog.csdn.net/nicholasmaxwell/archive/2006/04/20/670120.aspx c/c++支持可变参数的函数,即函数的参数是不确定的。 一、为什么要使用可变参数的函数? 一般我们编程的时候,函数中形式参数的数目通常是确定的,在调用时要依次给出与形式参数对应的所有实际参数。但在某些情况下希望函数的参数个数可以根据需要确定,因此c语言引入可变参数函数。这也是c功能强大的一个方面,其它某些语言,比如fortran就没有这个功能。 典型的可变参数函数的例子有大家熟悉的printf()、scanf()等。 二、c/c++如何实现可变参数的函数? 为了支持可变参数函数,C语言引入新的调用协议, 即C语言调用约定 __cdecl 。 采用C/C++语言编程的时候,默认使用这个调用约定。如果要采用其它调用约定,必须添加其它关键字声明,例如WIN32 API使用PASCAL调用约定,函数名字之前必须加__stdcall关键字。 采用C调用约定时,函数的参数是从右到左入栈,个数可变。由于函数体不能预先知道传进来的参数个数,因此采用本约定时必须由函数调用者负责堆栈清理。举个例子: //C调用约定函数 函数调用: 如果调用函数的时候使用的调用协议和函数原型中声明的不一致,就会导致栈错误,这是另外一个话题,这里不再细说。 另外c/c++编译器采用宏的形式支持可变参数函数。这些宏包括va_start、va_arg和va_end等。之所以这么做,是为了增加程序的可移植性。屏蔽不同的硬件平台造成的差异。 支持可变参数函数的所有宏都定义在stdarg.h 和 varargs.h中。例如标准ANSI形式下,这些宏的定义是: typedef char * va_list; //字符串指针 #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) 使用宏_INTSIZEOF是为了按照整数字节对齐指针,因为c调用协议下面,参数入栈都是整数字节(指针或者值)。 三、如何定义这类的函数。 可变参数函数在不同的系统下,采用不同的形式定义。 1、用ANSI标准形式时,参数个数可变的函数的原型声明是: type funcname(type para1, type para2, …); 关于这个定义,有三点需要说明: 一般来说,这种形式至少需要一个普通的形式参数,可变参数就是通过三个’.'来定义的。所以”…”不表示省略,而是函数原型的一部分。type是函数返回值和形式参数的类型。 int MyPrintf(char const* fmt, …); 但是,我们也可以这样定义函数: void MyFunc(…); 但是,这样的话,我们就无法使用函数的参数了,因为无法通过上面所讲的宏来提取每个参数。所以除非你的函数代码中的确没有用到参数表中的任何参数,否则必须在参数表中使用至少一个普通参数。 注意,可变参数只能位于函数参数表的最后。不能这样: void MyFunc(…, int i); 2、采用与UNIX 兼容系统下的声明方式时,参数个数可变的函数原型是: type funcname(va_alist); 但是要求函数实现的时候,函数名字后面必须加上va_dcl。例如: #include void main( void ) /* UNIX兼容形式*/ 这种形式不需要提供任何普通的形式参数。type是函数返回值的类型。va_dcl是对函数原型声明中参数va_alist的详细声明,实际是一个宏定义。根据平台的不同,va_dcl的定义稍有不同。 在varargs.h中,va_dcl的定义后面已经包括了一个分号。因此函数实现的时候,va_dcl后不再需要加上分号了。 3、采用头文件stdarg.h编写的程序是符合ANSI标准的,可以在各种操作系统和硬件上运行;而采用头文件varargs.h的方式仅仅是为了与以前的程序兼容,两种方式的基本原理是一致的,只是在语法形式上有一些细微的区别。 所以一般编程的时候使用stdarg.h。下面的所有例子代码都采用ANSI标准格式。 四、可变参数函数的基本使用方法 下面通过若干例子,说明如何实现可变参数函数的定义和调用。 //================================ 例子程序1 =============== /* 函数原型声明,至少需要一个确定的参数,注意括号内的省略号 */ void main( void ) int demo( char *msg, … ) // 使用宏va_start, 使argp指向传入的第一个可选参数, while (1) if ( strcmp( para, “\0″) == 0 ) /* 采用空串指示参数输入结束 */ //输出结果 注意到上面的例子没有使用第一个参数,下面的例子将使用所有参数 //================================ 例子程序2 =============== #include void main( void ) /*调用4个整数*/ /*只有结束符的调用*/ /* 返回若干整数平均值的函数 */ va_start( marker, first ); //初始化 //输出结果 五、关于可变参数的传递问题 有人问到这个问题,假如我定义了一个可变参数函数,在这个函数内部又要调用其它可变参数函数,那么如何传递参数呢?上面的例子都是使用宏va_arg逐个把参数提取出来使用,能否不提取,直接把它们传递给另外的函数呢? 我们先看printf的实现: int __cdecl printf (const char *format, …) va_start(arglist, format); //arglist指向format后面的第一个参数 。。。//不关心其它代码 。。。//不关心其它代码 我们先模仿这个函数写一个: #include int mywrite(char *fmt, …) void main() 运行一下看看,哈,错误百出。仔细分析原因,根据宏的定义我们知道 arglist是一个指针,它指向第一个可变的参数,但是所有的参数都位于栈中,所以arglist指向栈中某个位置,通过arglist的值,我们可以直接查看栈里面的内容: arglist -> 指向栈里面,内容包括 0067FD78 E0 FD 67 00 //指向字符串”This is a test” 如果直接调用 printf(fmt, arglist); 仅仅是把arglist指针的值0067FD78入栈,然后把格式字符串入栈,相当于调用: printf(fmt, 0067FD78); 自然这样的调用肯定会出现错误。 我们能不能逐个把参数提取出来,再传递给其它函数呢?先考虑一次性把所有参数传递进去的问题。 如果调用的是系统库函数,这种情况下是不可能的。因为提取参数是在运行态,而参数入栈是在编译的时候确定的。无法让编译器预知运行态的事情给出正确的参数入栈代码。而我们在运行态虽然可以提取每个参数,但是无法将参数一次性全部压栈,即使使用汇编代码实现起来也是很困难的,因为不单是一个简单的push代码就可以做到。 如果接受参数的函数也是我们自己写的,自然我们可以把arglist指针入栈,然后在函数中自己解析arglist指针里面的参数,逐个提取出来处理。但是这样做似乎没有什么意义,一方面,这个函数没有必要也做成可变参数函数,另一方面直接在第一个函数中解析参数,然后处理不是更简单么? 我们唯一可以做到的是,逐个解析参数,然后循环中调用其它可变参数函数,每次传递一个参数。这里又有一个问题,就是参数表中的不可变参数的传递问题,有些情况下不能简单的传递,以上面的例子为例, 通常我们解析参数的同时,还需要解析格式字符串: #include //测试一下这个,开个玩笑 int mywrite(char *fmt, …) char temp[255]; char *p = strchr(temp,’%'); //格式字符串 i++; return i; } void main() //输出: 当然这里的解析是不完善的。 结构体对其的具体含义关键词: 字节对齐 #pragma pack sizeof padding 关于字节对齐,这可能是我找到的解释最为准确的一篇文章了,尤其对于 #pragma pack 的解释.之前看了好几篇文章,都解释为是设置默认对齐字节数.唯有该篇指出是设置字节对齐时所允许的最大值.经linux 下验证,符合事实. 似乎网上的文章以讹传讹的情况越来越多了.以至于关于集线器在osi体系中所处的层次居然有3中说法. 各种指针的含义方法:以a变量为中心 先右后左 再右再左 读完为止 a) int a; // An integer b) int *a; // A pointer to an integer c) int **a; // A pointer to a pointer to an integer d) int a[10]; // An array of 10 integers e) int *a[10]; // An array of 10 pointers to integers f) int (*a)[10]; // A pointer to an array of 10 integers g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer January 18 DirectX -- DirectShow 介绍1、DirectX是什么
DirectX(简称:DX)是微软推出的一套基于Windows系统的多媒体应用程式接口APIs函式。在开发中,DX分为两个部分,一个是运行库,通过DX编译出来的程式必须要有运行库的支持,另外一个是开发库,也就是常说的SDK,这部分是在编译DX程序中是必需的。
DirectX是一种图形应用程序接口(API),简单的说它是一个辅助软件,一个提高系统性能的加速软件,微软创建开发的。他的意思不难理解,Direct是直接的意思,X是很多东西,加在一起就是一组具有共性的东西,这个共性就是直接。微软定义它为“硬件设备无关性”。
DirectX 是微软开发的图形及媒体加速接口,只有安装了它,系统中软件才能比较直接的利用硬件加速资源(高速访问硬件),目前该软件最高版本为9.0c
在Windows操作系统的体系构架中,在内核与硬件之间有一层抽象层,专门对硬件进行屏蔽抽象,所以用户不再被允许对硬件进行直接访问。这样做以后,大大地提高了操作系统的抗破坏性和抗干扰性,但这样以来,使硬件操作的效率大打折扣,许多新硬件的新特性无法直接使用,这对多媒体和游戏的发展显然是一种障碍。DirectX是微软公司提供的一套优秀的应用程序编程接口(APIs),用于联系应用程序和硬件自身,它对发展Windows平台下的多媒体应用程序和电脑游戏起到了关键的作用。
DirectX组件包括:DirectDraw、DirectSound、DirectPlay、Direct3D、DirectInput、DirectSetup、AutoPlay等。
总之,DirectX的主要好处有两个:为软件开发者提供与硬件的无关性;为硬件开发提供策略。 为得到最新的版本,应该从最新的Microsoft Platform SDK中将DirectX安装到系统中。 可以在http://www.microsoft.com/msdn站点或者MSDN光盘中找到platform SDK。缺省情况下,Microsoft Platform SDK被安装到缺省驱动器根目录下的\MSSDK目录中。DirectX 的头文件安装在\MSSDK\INCLUDE目录中,Lib文件安装在\MSSDK\LIB目录中。
Platform SDK包含了一些非常好的DirectX例子和文档。早期发布的DirectX 文档非常粗略而且有些是错误的,现在的版本已经极大地改正了这一问题。最好要熟悉这些文档。
所幸的是,不必一次就处理DirectX的全部功能。DirectX是一套可以分别使用的组件。实际上,在编程概念中,DirectX的不同部分互相没有联系。它们仅仅是具有相同的设计风格和目标:使Windows的游戏编程变得容易。
使用DirectX组件的程序有什么特殊的地方吗?根本没有。使用DirectX组件的程序是基于Win32的程序,它们使用普通Win32 API集,并且可以访问所有可以获得的操作系统工具。实际上,DirectX既可以用于GUI程序,也可以用于控制台程序。可以直接用Petzold-style SDK编程开发程序,也可以用基本类库,如MFC。总的说,唯一的要求是大多数DirectX组件在程序中需要HWND,所以至少要有一个窗口。
2、DirectX 9.0 家族的所有成员
DirectX Graphics:集成了以前的DirectDraw 和Direct3D技术。DirectDraw主要负责2D加速,以实现对显卡内存和系统内存的直接操作;Direct3D主要提供三维绘图硬件接口,它是开发三维DirectX游戏的基础。
DirectInput:主要支持输入服务(包括鼠标、键盘、游戏杆等),同时支持输出设备。
DirectPlay:主要提供多人网络游戏的通信、组织功能。
DirectSetup:主要提供自动安装DirectX组件的API功能。
DirectMusic:主要支持MIDI音乐合成和播放功能。
DirectSound:主要提供音频捕捉、回放、音效处理、硬件加速、直接设备访问等功能。
DirectShow:为Windows平台上处理各种格式的媒体文件的回放、音视频采集等高性能要求的多媒体应用,提供了完整的解决方案。
DirectX Media Objects:DirectShow Filter 的简化模型,提供更方便的流数据处理方案。
3、DirectX的作用
DirectX软件开发包是微软公司提供的一套Windows操作平台上的开发高性能图形、声音、输入、输出和网络游戏的编程接口。它提供了硬件设备无关性。
4、DirectShow的由来及介绍
DirectShow是从DirectX6.0中的DirectX Media 发展而来的,它集成了DirectX家族中其他成员(DirectDraw、DirectSound等)的技术。DirectX Media Objects是从DirectX8.1的DirectShow中分离出来的,成为了另一种高效率的流数据处理解决方案。
Microsoft DirectShow是一个基于Microsoft Windows平台的媒体流结构。它支持各种格式,包括高级流模式(ASF)、运动图像专家组(MPEG)、音频视频交错(AVI)、音频动态压缩第三层(MP3)和WAV声音文件。它支持Windows驱动模式(WDM)设备的捕捉,以及早期Widows设备的视频。DirectShow结合了其它的DirectX技术。当视频和音频的硬件加速可用时,它能够自动检测并进行使用,同时也支持没有硬件加速的系统。
DirectShow媒体重放、格式转换和捕捉的任务变得简单。同时,它为需要自定义的解决方案的应用程序提供了对底层流控制结构的访问。您也可以创建自己的DirectShow组件,来支持新的格式或自定义效果。
使用DirectShow的应用程序类型包括DVD播放器、视频编辑应用程序、AVI到ASF的转换器、MP3播放器和数字视频捕捉应用程序。
DirectShow是基于组件对象模型(COM)的。要做一个DirectShow的应用程序,您必须了解COM客户端编程。对于大多数应用程序,您不需要实现您自己的COM对象。DirectShow提供了您所需要的组件。(如果您想写自己的组件扩展DirectShow,则必须以COM对象的方式来实现。)
5、程序开发包的选择
请问在Mirosoft DirectX主页上的下载连接有如下:
它们有什么区别:
l DirectX 9.0 SDK Update - (April 2005)
l DirectX 9.0 SDK Update - (April 2005) Symbol Files
l DirectX 9.0c Redistributable for Software Developers - (April 2005)
l DirectX 9.0c End-User Runtime
--------------------------------------------------------------------------------
l DirectX 9.0 SDK Update - (April 2005) - 就是通常说的DXSDK
l DirectX 9.0 SDK Update - (April 2005) Symbol Files - 调试时用的符号文件
l DirectX 9.0c Redistributable for Software Developers - (April 2005) - 能够随你的程序一起发行的部分
l DirectX 9.0c End-User Runtime - 普通用户安装的DX
我们要进行DirectX程序的编译就必须要有DirectX SDK库文件,此文件可以到微软或者本站获取,然后通过VC设置将其关联。下面说明了在VC6和VS.Net下的安装方法。
VC6(英文版):选择菜单Tools->Options,打开Options对话框,选择Directions标签页,选择Include files项,在里面添加DirectX头文件的文件夹路径目录,同样,在Library files项中添加DirectX头文件的文件夹路径目录。
VS.Net(中文版):选择菜单"工具->选项",打开选项对话框,打开Projects标签页,分别选择"包含文件"和"库文件"进行相应的路径添加即可。
注:VC在进行编译时,会根据排列顺序来进行库文件选取,假设有两个相同名字的库,VC会优先使用排列在前面的库文件。
DirectShow应用程序至少连接库文件Strmiids.lib和Quartz.lib。前者定义了SirectShow标准的CLSID和IID,后者定义了导出函数AMGetErrorText(如果应用程序中没有使用到这个函数,也可以不连接这个库)。
DirectShow应用程序都应该包含Dshow.h文件,但常常用Streams.h文件来代替它。如果包含了Streams.h,则一般库文件还要连接strmbasd.lib、uuid.lib和winmm.lib。
7、DirectShow开发环境的配置
(1)使用VC向导生成一个具体项目,如Win32 Dynamic-Link;
(2)包含头文件streams.h;
(3)在VC的菜单中选择Project|Settings|C/C++,在弹出的对话框中的Category中选择Code generation,然后在Calling convention中选择_stdcall;
(4)使用多线程语言运行时库,即在VC的菜单中选择Project|Settings|C/C++,在弹出的对话框中的Category中选择Code generation,然后在Use run-time library中,Debug版选择Debug Multithreaded,Release版选择Multithreaded。
(5)配置必要的链接库文件,即在VC的菜单中选择Project|Settings|Link,在弹出的对话框中的Category中选择General,然后在Object/library modules中输入如下代码:
Debug版本 strmbasd.lib, msvcrtd.lib, winmm.lib
Release版本 strmbase.lib, msvcrt.lib, winmm.lib
并且选中Ignore all default libraries。
DirectShow SDK建议,DirectShow应用程序应该至少连接库文件strmiids.lib和quartz.lib。前者定义了DirectShow标准的CLSID和IID,后者定义了导出函数AMGetErrorText(如果应用程序中没有使用到这个函数,也可以不连接这个库)。如果程序里包含了头文件streams.h,则一般库文件还要连接strmbasd.lib、uuid.lib、winmm.lib。
(6)将DirectX SDK的Include和Lib目录配置到VC的系统目录中去,并且放在标准的VC目录之前,以保证编译器能够拿到最新版本的源文件。选择Tools|Options|Directories,在弹出的对话框中的Show directories for中选择Include files,配置如下(假设DirectX SDK安装在D:\DXSDK目录下,VC安装在C:\Program Files下):
D:\DXSDK\Include
D:\DXSDK\SAMPLES\C++\DIRECTSHOW\BASECLASSES
D:\DXSDK\SAMPLES\C++\COMMON\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\MFC\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\ATL\INCLUDE
再在Show directories for中选择Library files,配置如下:
D:\DXSDK\Lib
D:\DXSDK\SAMPLES\C++\DIRECTSHOW\BASECLASSES\DEBUG
D:\DXSDK\SAMPLES\C++\DIRECTSHOW\BASECLASSES\RELEASE
C:\PROGRAM FILES\MICROSOFT SDK\LIB
C:\Program Files\Microsoft Visual Studio\VC98\LIB
C:\Program Files\Microsoft Visual Studio\VC98\MFC\LIB
(7)因为DirectShow应用程序是一种COM客户程序,因此在调用任何COM函数之前调用CoInitialize()(或CoInitializeEx)函数进行COM库的初始化(一般是在应用程序启动的时候调用一次),在结束COM库使用时调用CoUninitialize()函数进行反初始化(一般是在应用程序退出前调用一次)。
这个错误经常出现在初学者要进行编译DirectX程序的时候,主要是因为没有将DX的库文件引用到工程中,这里需要注意,我们将DX SDK的路径设置到VC后,并不代表我们已设置好了DX SDK,在我们的DX工程中,我们还需要进行相应的设置操作,把我们所需要的库文件(DirectX SDK Library)加入到我们的工程中,要设置这个库文件有两个方法,一个是在你工程的编译选项中进行添加,另外一种可以通过代码的方法来添加(推荐)。
命令行:#pragma comment( lib,"xxx.lib" )
这个是VC的编译预处理指令,将其加在代码中即可。
例如:#pragma comment( lib,"ddraw.lib" ) 这句的意思是将ddraw.lib库加入到工程中进行编译。
注:此命令行不需要加分号(“;”)。
9、DirectShow SDK基类库
在DirectShow SDK基类库中,除了Filter和Pin类外,还有很多工具类。有了这些类的支持,我们开发Filter组件或者DirectShow应用程序会更加轻松。这些类主要包括:CPullPin、COutputQueue、CSourceSeeking、CEnumPins、CEnumMedieTypes、CMemAllocator、CMediaSample、CBaseReferenceClock、CMediaType、CBaseProperyPage等。
DirectX采用了COM标准,而DirectShow是一套完全基于COM的应用系统。
DirectShow应用程序实际上是一种COM组件的客户程序,只是COM组件的“使用”问题。这些问题包括如何创建COM组件、如何得到组件对象上的解风口以及调用接口方法、如何管理组件对象(即需要熟悉COM的引用计数机制)等。
而对于Filter开发人员来说,需要掌握的COM知识就要多一点。因为Filter本身是一种COM组件,开发Filter牵涉到了COM组件的“实现”问题。
COM本身只是一种规范,而不是实现。但是当使用C++来实现时,COM组件就是一个C++类,而接口都是纯虚类。COM规范规定,任何组件或接口都必须从IUnknown接口中继承而来,每个组件都必须实现一个与支相对应的类工厂(Class Factory),类工厂也是一个COM组件,他实现了IClassFactory接口。在IClassFactory的接口函数CreateInstance中,才能使用new操作生成一个与之对应的COM组件类对象实例。
COM组件有3种类型:进程内组件、本地进程组件和远程组件。Filter一般是一种进程内组件,以DLL的形式提供服务。
每个COM组件都使用一个GUID来唯一标识。当创建一个COM组件时,总是首先通过这个GUID调用CoGetClassObject来获得创建这个组件对象的类工厂。然后调用类工厂的接口方法IClassFactory::CreateInstance,就能真正地创建GUID标示的组件对象了。
一个典型的自注册COM组件DLL所必需的5个函数如下:
l DllMain:DLL的入口函数(DirectShow实现的是DllEntryPoint);
l DllGetClassObject:用于获得类工厂指针;
l DllCanUnloadNow:系统空闲时会调用这个函数,以确定是否可以卸载DLL;
l DllRegisterServer:将COM组件注册到注册表中;
l DllUnregisterServer:删除注册表中COM组件的注册信息。 |
MemoryJ |
||||||||||
|
|