1. 程式人生 > >DirectShow SDK編譯中易出現的問題

DirectShow SDK編譯中易出現的問題

由於需要進行視訊採集,昨天開始搜尋資料,發現現在流行的是DirectShow來進行開發,昨天下載安裝了個DirectX 9.0 SDK,於是痛苦的配置旅程開始了。現在我們來重溫一下這個痛苦的歷程吧。先介紹下我的配置吧:

Microsoft DirectX 9.0 SDK + Microsoft Visual Stiduo 2005

我的Microsoft DirectX 9.0 SDK 安裝在D盤根目錄,進入這個目錄D:\DXSDK\Samples\C++\DirectShow\Capture裡面有幾個專案檔案,我們拿AMCap這個專案來用,首先我們拷貝一個副本AMCap1(為了保險起見!),要想看看AMCap最終的執行效果,我們可以進入這個目錄:D:\DXSDK\Samples\C++\DirectShow\Bin

第一個應該就是它了,相信你能找到的(就是那個叫AMCap.exe的!)

用Microsoft Visual Stiduo 2005開啟工程,可能需要轉換下,轉換就是了,先什麼也別做,開始編譯工程(預設的配置管理器中的活動解決方案配置Debug Unicode活動解決方案平臺Win32),我得到了下面的錯誤:

amcap.cpp
C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\include\winnt.h(222) : error C2146: syntax error : missing ';' before identifier 'PVOID64'

C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\include\winnt.h(222) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\include\winnt.h(5940) : error C2146: syntax error : missing ';' before identifier 'Buffer'
C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\include\winnt.h(5940) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\include\winnt.h(5940) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\DXSDK\include\uuids.h : warning C4819: The file contains a character that cannot be represented in the current code page (936). Save the file in Unicode format to prevent data loss
.\amcap.cpp(2787) : error C2065: 'i' : undeclared identifier

雙擊輸出視窗中的錯誤到錯誤發生處,上圖中藍色部分第一個錯誤的解決辦法是在winnt.h檔案中將(附1typedef void *PVOID;
typedef void * POINTER_64 PVOID64;
修改為

#define POINTER_64 __ptr64 //加上這一行
typedef 
void*PVOID;
typedef 
void* POINTER_64 PVOID64;

對於第二個錯誤改成:int i 就可以了。

修改完錯誤繼續編譯,發現編譯已經沒有錯誤了,只有一些警告,可以不去管它,但是有這樣的一個錯誤:

LINK : fatal error LNK1104: 無法開啟檔案“..\..\baseclasses\debug_unicode\strmbasd.lib

看錯誤的意思是缺少了一個庫檔案,於是在網上找了一下,原來需要先編譯baseclasses,開啟你的dx的sdk安裝目錄,本例為:
D:\DX90SDK\Samples\C++\DirectShow\
這裡就有一個叫baseclasses的工程,為安全起見,請先備份此工程,然後開啟該工程。轉換後開始編譯,我們收到了下面的錯誤:

.\wxdebug.cpp(567) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
.\winutil.cpp(2104) : error C2065: 'Count' : undeclared identifier
.\winutil.cpp(2106) : error C2228: left of '.peRed' must have class/struct/union
.\winutil.cpp(2106) : error C2228: left of '.peRed' must have class/struct/union
.\winutil.cpp(2107) : error C2228: left of '.peGreen' must have class/struct/union
.\winutil.cpp(2107) : error C2228: left of '.peGreen' must have class/struct/union
.\winutil.cpp(2108) : error C2228: left of '.peBlue' must have class/struct/union
.\winutil.cpp(2108) : error C2228: left of '.peBlue' must have class/struct/union
.\winutil.cpp(2124) : error C2228: left of '.peFlags' must have class/struct/union
.\outputq.cpp(664) : error C2065: 'iDone' : undeclared identifier

真正需要解決的是上面藍色部分的三個錯誤,我們現在來開始解決(這裡我們還是直接修改程式碼吧,通過修改配置也可以完成【附2】不過我們一會還需要編譯其他三個版本,為了免去後面還要繼續設定,這裡直接通過修改程式碼解決)。
對於前一個錯誤

//static g_dwLastRefresh =0;
//修改為intstatic g_dwLastRefresh =0;

第二個錯誤【附3】,在Count前面加上int就可以了(修改後編譯後面還會出現類似的錯誤,照這樣修改就是了!)
第三個錯誤,在出錯的檔案中會看到下面的程式碼,修改辦法一併在下面列出,註釋裡有說明。

        LONG iLost = 0;
        LONG iDone = 0;      //這是我們修改的地方,加入這一行程式碼
        for (long iDone = 0;
             iDone < nSamples || (m_nBatched != 0 && m_bSendAnyway);
            ) {

//pragma message (REMIND("Implement threshold scheme"))            ASSERT(m_nBatched < m_lBatchSize);
            if (iDone < nSamples) {
                m_ppSamples[m_nBatched++] = ppSamples[iDone++];
            }
            if (m_nBatched == m_lBatchSize ||
                nSamples == 0 && (m_bSendAnyway || !m_bBatchExact)) {
                LONG nDone;
                DbgLog((LOG_TRACE, 4, TEXT("Batching %d samples"),
                       m_nBatched));

                if (m_hr == S_OK) {
                    m_hr = m_pInputPin->ReceiveMultiple(m_ppSamples,
                                                        m_nBatched,
                                                        &nDone);
                } else {
                    nDone = 0;
                }
                iLost += m_nBatched - nDone;
                for (LONG i = 0; i < m_nBatched; i++) {
                    m_ppSamples[i]->Release();
                }
                m_nBatched = 0;
            }
        }
        *nSamplesProcessed = iDone - iLost; //這是編譯報錯誤的地方

OK,修改完了,我們進行編譯,這下成功了。你會發現在目錄D:\DXSDK\Samples\C++\DirectShow\BaseClasses\Debug_Unicode下有了一個庫檔案strmbasd.lib
現在我們來得到其他三個庫檔案,開啟配置管理器,我們上面的配置是這樣的:
活動解決方案配置Debug Unicode活動解決方案平臺Win32
分別修改如下的三種模式分別編譯:
活動解決方案配置Debug活動解決方案平臺Win32                                            
活動解決方案配置
Release Unicode活動解決方案平臺Win32                          
活動解決方案配置
Release活動解決方案平臺Win32                                          
這樣我們就得到了4個庫檔案。
D:\DXSDK\Samples\C++\DirectShow\BaseClasses\Debug下有了一個庫檔案strmbasd.lib
D:\DXSDK\Samples\C++\DirectShow\BaseClasses\Debug_Unicode
下有了一個庫檔案strmbasd.lib
D:\DXSDK\Samples\C++\DirectShow\BaseClasses\Release
下有了一個庫檔案STRMBASE.lib
D:\DXSDK\Samples\C++\DirectShow\BaseClasses\Release_Unicode
下有了一個庫檔案STRMBASE.lib
現在大家再看看上面的那個紅色的連結錯誤,知道怎麼回事了吧。

好了,我們現在回去編譯AMCap這個工程吧,怎麼樣,搞定了吧!

附1:
POINTER_64是一個巨集,在64位編譯下起作用,它包含在SDK目錄下的BASETSD.H中(Microsoft Visual Studio 8\VC\PlatformSDK\Include\basetsd.h(23):#define POINTER_64 __ptr64),但DXSDK自己也帶了一個basetsd.h,裡面沒有定義POINTER_64,從而導致出錯。

方法1:
在Tools -> Options -> Projects and Solutions -> VC++ Directories -> Include Files裡確保系統包含目錄(以$打頭的)在最前面,同時在 project properties下面的“C/C++ -> General”中確保“Additional Include Directories”為空(因為它會被優先編譯,這樣就輪不到VC\PlatformSDK\Include\basetsd.h),所有的包含目錄都應該在上面的include裡面。這種方法不用改程式碼。

方法2:
在DXSDK自己的basetsd.h裡自己定義#define POINTER_64 __ptr64

附2:
開啟project->BaseClasses properties->configuration->C/C++ ->Command Line,增加/wd4430選項

附3:
C++標準語法的問題,因為在之前在for迴圈內定義的變數可以在for之外的地方使用,即在第一個for裡for(int i,...),以後的for再使用i不必再宣告,解決方法也很簡單,開啟project->BaseClasses properties->configuration->C/C++->Language->Force Comformance in For Loop Scrope設定為No即可。


相關資料: