DirectShow系統初級指南

流媒體的處理,以其復雜性和技術性,一向廣受工業界的關注。特別伴隨著因特網的普及,流媒體在網絡上的廣泛應用,怎樣使流媒體的處理變得簡單而富有成效逐漸成為了焦點問題。選擇一種合適的應用方案,事半功倍。此時,微軟的DirectShow,給了我們一個不錯的選擇。

  DirectShow是微軟公司提供的一套在Windows平臺上進行流媒體處理的開發包,與DirectX開發包一起發布。目前,DirectX最新版本為8.1。

  那么,DirectShow能夠做些什么呢?且看,DirectShow為多媒體流的捕捉和回放提供了強有力的支持。運用DirectShow,我們可以很方便地從支持WDM驅動模型的采集卡上捕獲數據,并且進行相應的后期處理乃至存儲到文件中。它廣泛地支持各種媒體格式,包括Asf、Mpeg、Avi、Dv、Mp3、Wave等等,使得多媒體數據的回放變得輕而易舉。另外,DirectShow還集成了DirectX其它部分(比如DirectDraw、DirectSound)的技術,直接支持DVD的播放,視頻的非線性編輯,以及與數字攝像機的數據交換。更值得一提的是,DirectShow提供的是一種開放式的開發環境,我們可以根據自己的需要定制自己的組件。

?

  DirectShow使用一種叫Filter Graph的模型來管理整個數據流的處理過程;參與數據處理的各個功能模塊叫做Filter;各個Filter在Filter Graph中按一定的順序連接成一條“流水線”協同工作。大家可以看到,按照功能來分,Filter大致分為三類:Source Filters、Transform Filters和Rendering Filters。Source Filters主要負責取得數據,數據源可以是文件、因特網、或者計算機里的采集卡、數字攝像機等,然后將數據往下傳輸;Transform Fitlers主要負責數據的格式轉換、傳輸;Rendering Filtes主要負責數據的最終去向,我們可以將數據送給聲卡、顯卡進行多媒體的演示,也可以輸出到文件進行存儲。值得注意的是,三個部分并不是都只有一個Filter去完成功能。恰恰相反,每個部分往往是有幾個Fitler協同工作的。比如,Transform Filters可能包含了一個Mpeg的解碼Filter、以及視頻色彩空間的轉換Filter、音頻采樣頻率轉換Filter等等。除了系統提供的大量Filter外,我們可以定制自己的Filter,以完成我們需要的功能。下圖是一條典型的Avi文件回放Filter Graph鏈路:

  在DirectShow系統之上,我們看到的,即是我們的應用程序(Application)。應用程序要按照一定的意圖建立起相應的Filter Graph,然后通過Filter Graph Manager來控制整個的數據處理過程。DirectShow能在Filter Graph運行的時候接收到各種事件,并通過消息的方式發送到我們的應用程序。這樣,就實現了應用程序與DirectShow系統之間的交互。下圖給出了DirectShow應用程序開發的一般過程:

  以上簡單介紹了DirectShow的系統結構,希望大家對這個強勁的應用框架已經有了大概的認識。如果你有興趣,可以詳細研究DirectX的幫助文檔。DirectShow是一個強大的開發包;另外,它是基于COM的,因此要求程序員具有COM編程的一些基本知識。關于如何深入學習DirectShow應用結構以及開發自己的Filter,請參閱筆者的后續文章。筆者將從編程的角度,詳細講述來源于實際工作中的經驗之談。

  從下面開始,我們要從程序員的角度,進一步深入探討一下DirectShow的應用以及Filter的開發。

  在這之前,筆者首先要特別提一下微軟提供的一個Filter測試工具——GraphEdit,它的路徑在DXSDK/bin/DXUtils/GraphEdit.exe。(如果您還沒有安裝DirectX SDK,請到微軟的網站上去下載。)通過這個工具,我們可以很直觀地看到Filter Graph的運行及處理流程,方便我們進行程序調試。(如果您手邊就有電腦,還等什么,馬上體驗一下吧:運行GraphEdit,執行File->Render Media File…選擇一個媒體文件;當Filter Graph構建成功后,按下工具欄的運行按鈕;您就能看到剛才選擇的媒體文件被回放出來了!看到了吧,寫一個媒體播放器也就這么回事!)

  接下去,我們開講Filter的開發。

  學習DirectShow Filter的開發,不外乎以下幾種方法:看幫助文檔、看示例代碼和看SDK基類源代碼。看幫助文檔,應著重于總體概念上的理解;看示例代碼應與基類源代碼的研究同步進行,因為自己寫Filter,關鍵的第一步是選擇一個合適的Filter基類和Pin的基類。對于Filter的把握,一般認為要掌握以下三方面的內容:Filter之間Pin的連接、Filter之間的數據傳輸以及流媒體的隨機訪問(或者說流的定位)。下面就開始分別進行闡述。

  所謂的Filter Pin之間的連接,實際上是Pin之間Media Type(媒體類型)的一個協商過程。連接總是從輸出Pin指向輸入Pin的。要想深入了解具體的連接過程,就必須認真研讀SDK的基類源代碼(位于DXSDK/samples/Multimedia/DirectShow/BaseClasses/amfilter.cpp,類CBasePin的Connect方法)。連接的大致過程為,枚舉欲連接的輸入Pin上所有的媒體類型,逐一用這些媒體類型與輸出Pin進行連接,如果輸出Pin也接受這種媒體類型,則Pin之間的連接宣告成功;如果所有輸入Pin上枚舉的媒體類型輸出Pin都不支持,則枚舉輸出Pin上的所有媒體類型,并逐一用這些媒體類型與輸入Pin進行連接。如果輸入Pin接受其中的一種媒體類型,則Pin之間的連接到此也宣告成功;如果輸出Pin上的所有媒體類型,輸入Pin都不支持,則這兩個Pin之間的連接過程宣告失敗。

  有一點需要注意的是,上述的輸入Pin與輸出Pin一般不屬于同一個Filter,典型的是上一級Filter(也叫Upstream Filter)的輸出Pin連向下一級Filter(也叫Downstream Filter)的輸入Pin。

  當Filter的Pin之間連接完成,也就是說,連接雙方通過協商取得了一種大家都支持的媒體類型之后,即開始為數據傳輸做準備。這些準備工作中,最重要的是Pin上的內存分配器的協商,一般也是由輸出Pin發起。在DirectShow Filter之間,數據是通過一個一個數據包傳送的,這個數據包叫做Sample。Sample本身是一個COM對象,擁有一段內存用以裝載數據,Sample就由內存分配器(Allocator)來統一管理。已成功連接的一對輸出、輸入Pin使用同一個內存分配器,所以數據從輸出Pin傳送到輸入Pin上是無需內存拷貝的。而典型的數據拷貝,一般發生在Filter內部,從Filter的輸入Pin上讀取數據后,進行一定意圖的處理,然后在Filter的輸出Pin上填充數據,然后繼續往下傳輸。下面,我們就具體闡述一下Filter之間的數據傳送。
首先,大家要區分一下Filter的兩種主要的數據傳輸模式:推模式(Push Model)和拉模式(Pull Model)。

  所謂推模式,即源Filter(Source Filter)自己能夠產生數據,并且一般在它的輸出Pin上有獨立的子線程負責將數據發送出去,常見的情況如代表WDM模型的采集卡的Live Source Filter;而所謂拉模式,即源Filter不具有把自己的數據送出去的能力,這種情況下,一般源Filter后緊跟著接一個Parser Filter或Splitter Filter,這種Filter一般在輸入Pin上有個獨立的子線程,負責不斷地從源Filter索取數據,然后經過處理后將數據傳送下去,常見的情況如文件源。推模式下,源Filter是主動的;拉模式下,源Filter是被動的。而事實上,如果將上圖拉模式中的源Filter和Splitter Filter看成另一個虛擬的源Filter,則后面的Filter之間的數據傳輸也與推模式完全相同。

  那么,數據到底是怎么通過連接著的Pin傳輸的呢?首先來看推模式。在源Filter后面的Filter輸入Pin上,一定實現了一個IMemInputPin接口,數據正是通過上一級Filter調用這個接口的Receive方法進行傳輸的。值得注意的是(上面已經提到過),數據從輸出Pin通過Receive方法調用傳輸到輸入Pin上,并沒有進行內存拷貝,它只是一個相當于數據到達的“通知”。再看一下拉模式。拉模式下的源Filter的輸出Pin上,一定實現了一個IAsyncReader接口;其后面的Splitter Filter,就是通過調用這個接口的Request方法或者SyncRead方法來獲得數據。Splitter Filter然后像推模式一樣,調用下一級Filter輸入Pin上的IMemInputPin接口Receive方法實現數據的往下傳送。深入了解這部分內容,請認真研讀SDK的基類源代碼(位于DXSDK/samples/Multimedia/DirectShow/BaseClasses/source.cpp和pullpin.cpp)。

  下面,我們來講一下流的定位(Media Seeking)。在GraphEdit中,當我們成功構建了一個Filter Graph之后,我們就可以播放它。在播放中,我們可以看到進度條也在相應地前進。當然,我們也可以通過拖動進度條,實現隨機訪問。要做到這一點,在應用程序級別應該可以知道Filter Graph總共要播放多長時間,當前播放到什么位置等等。那么,在Filter級別,這一點是怎么實現的呢?

  我們知道,若干個Filter通過Pin的相互連接組成了Filter Graph。而這個Filter Graph是由另一個COM對象Filter Graph Manager來管理的。通過Filter Graph Manager,我們就可以得到一個IMediaSeeking的接口來實現對流媒體的定位。在Filter級別,我們可以看到,Filter Graph Manager首先從最后一個Filter(Renderer Filter)開始,詢問上一級Filter的輸出Pin是否支持IMediaSeeking接口。如果支持,則返回這個接口;如果不支持,則繼續往上一級Filter詢問,直到源Filter。一般在源Filter的輸出Pin上實現IMediaSeeking接口,它告訴調用者總共有多長時間的媒體內容,當前播放位置等信息。(如果是文件源,一般在Parser Filter或Splitter Filter實現這個接口。)對于Filter開發者來說,如果我們寫的是源Filter,我們就要在Filter的輸出Pin上實現IMediaSeeking這個接口;如果寫的是中間的傳輸Filter,只需要在輸出Pin上將用戶的獲得接口請求往上傳遞給上一級Filter的輸出Pin;如果寫的是Renderer Filter,需要在Filter上將用戶的獲得接口請求往上傳遞給上一級Filter的輸出Pin。進一步的了解,請認真研讀SDK的基類源代碼(位于DXSDK/samples/Multimedia/DirectShow/BaseClasses/transfrm.cpp的類方法CTransformOutputPin::NonDelegatingQueryInterface實現和ctlutil.cpp中類CPosPassThru的實現)。
以上我們介紹了一下如何學習DirectShow Filter開發,以及一些開始寫自己的Filter之前的預備知識。下一講,筆者將根據自己開發Filter的經驗,手把手教你如何寫自己的Filter。
如何寫自己的Filter

  首先,從VC++的項目開始(請確認你已經給VC++配置好了DirectX的開發環境)。寫自己的Filter,第一步是使用VC++建立一個Filter的項目。由于DirectX SDK提供了很多Filter的例子項目(位于DXSDK/samples/Multimedia/DirectShow/ Filters目錄下),最簡單的方法就是拷貝一個,然后再在此基礎上修改。但如果你是Filter開發的初學者,筆者并不贊成這么做。

  自己新建一個Filter項目也很簡單。使用VC++的向導,建立一個空的”Win32 Dynamic-link Library”項目。注意,幾個文件是必須有的:.def文件,定義四個導出函數;定義Filter類的.cpp文件和.h文件,并在.cpp文件中定義Filter的注冊信息以及兩個Filter的注冊函數:DllRegisterServer和DllUnregisterServer。(注:Filter的注冊信息是Filter在注冊時寫到注冊表里的內容,格式可以參考SDK的示例代碼,Filter相關的GUID務必使用GuidGen.exe產生。)接下去進行項目的設置(Project->Settings…)。此時,你可以打開一個SDK的例子項目進行對比,有些宏定義完全可以照抄,最后注意將輸出文件的擴展名改為.ax。

  上一講曾經提到過,在寫Filter之前,選擇一個合適的Filter基類是至關重要的。為此,你必須對幾個Filter的基類有相當的了解。在實際應用中,Filter的基類并不總是選擇CBaseFilter的。相反,因為我們絕大部分寫的都是中間的傳輸Filter(Transform Filter),所以基類選擇CTransformFilter和CTransInPlaceFilter的居多。如果我們寫的是源Filter,我們可以選擇CSource作為基類;如果是Renderer Filter,可以選擇CBaseRenderer或CBaseVideoRenderer等。

  總之,選擇好Filter的基類是很重要的。當然,選擇Filter的基類也是很靈活的,沒有絕對的標準。能夠通過CTransformFilter實現的Filter當然也能從CBaseFilter一步一步實現。下面,筆者就從本人的實際經驗出發,對Filter基類的選擇提出幾點建議供大家參考。

  首先,你必須明確這個Filter要完成什么樣的功能,即要對Filter項目進行需求分析。請盡量保持Filter實現的功能的單一性。如果必要的話,你可以將需求分解,由兩個(或者更多的)功能單一的Filter去實現總的功能需求。

  其次,你應該明確這個Filter大致在整個Filter Graph的位置,這個Filter的輸入是什么數據,輸出是什么數據,有幾個輸入Pin、幾個輸出Pin等等。你可以畫出這個Filter的草圖。弄清這一點十分重要,這將直接決定你使用哪種“模型”的Filter。比如,如果Filter僅有一個輸入Pin和一個輸出Pin,而且一進一處的媒體類型相同,則一般采用CTransInPlaceFilter作為Filter的基類;如果媒體類型不一樣,則一般選擇CTransformFilter作為基類。

  再者,考慮一些數據傳輸、處理的特殊性要求。比如Filter的輸入和輸出的Sample并不是一一對應的,這就一般要在輸入Pin上進行數據的緩存,而在輸出Pin上使用專門的線程進行數據處理。這種情況下,Filter的基類選擇CSource為宜(雖然這個Filter并不是源Filter)。

  當Filter的基類選定了之后,Pin的基類也就相應選定了。接下去,就是Filter和Pin上的代碼實現了。有一點需要注意的是,從軟件設計的角度上來說,應該將你的邏輯類代碼同Filter的代碼分開。下面,我們一起來看一下輸入Pin的實現。你需要實現基類所有的純虛函數,比如CheckMediaType等。在CheckMediaType內,你可以對媒體類型進行檢驗,看是否是你期望的那種。因為大部分Filter采用的是推模式傳輸數據,所以在輸入Pin上一般都實現了Receive方法。有的基類里面已經實現了Receive,而在Filter類上留一個純虛函數供用戶重載進行數據處理。這種情況下一般是無需重載Receive方法的,除非基類的實現不符合你的實際要求。而如果你重載了Receive方法,一般會同時重載以下三個函數EndOfStream、BeginFlush和EndFlush。我們再來看一下輸出Pin的實現。一般情況下,你要實現基類所有的純虛函數,除了CheckMediaType進行媒體類型檢查外,一般還有DecideBufferSize以決定Sample使用內存的大小,GetMediaType提供支持的媒體類型。最后,我們看一下Filter類的實現。首先當然也要實現基類的所有純虛函數。除此之外,Filter還要實現CreateInstance以提供COM的入口,實現NonDelegatingQueryInterface以暴露支持的接口。如果我們創建了自定義的輸入、輸出Pin,一般我們還要重載GetPinCount和GetPin兩個函數。

  Filter框架的實現大致就是這樣。你或許還想知道怎樣在Filter上實現一個自定義的接口,以及怎么實現Filter的屬性頁等等。限于篇幅,筆者就不展開闡述了。其實,這些問題都能在SDK的示例項目中找到答案。其他的,關于在實際編程中應該注意的一些問題,筆者整理了一下,供大家參考。

  1. 鎖(Lock)問題

  DirectShow應用程序至少包含有兩條線程:一條主線程和一條數據傳輸線程。既然是多線程,肯定會碰到線程同步的問題。Filter有兩種鎖:Filter對象鎖和數據流鎖。Filter對象鎖用于Filter級別的如Filter狀態轉換、BeginFlush、EndFlush等;數據流鎖用于數據處理線程內,比如Receive、EndOfStream等。如果這兩種鎖沒有搞清楚,很容易產生程序的死鎖,這一點特別需要提醒。

  2. EndOfStream問題

  當Filter接收到這個“消息”,意味著上一級Filter的數據都已經發送完畢。在這之后,如果Receive再有數據接收,也不應該去理睬它。如果Filter對輸入Pin上的數據進行了緩存,在接收到EndOfStream后應確保所有緩存的數據都已經處理過了才能返回。

  3. Media Seeking問題

  一般情況下,你只需要在Filter的輸出Pin上實現NonDelegatingQueryInterface方法,當用戶申請得到IID_ImediaPosition接口或IID_IMediaSeeking接口時將請求往上一級Filter的輸出Pin上傳遞。當Filter Graph進行Mediaseeking的時候,一般會調用Filter上的BeginFlush、EndFlush和NewSegment。如果你的Filter對數據進行了緩存,你就要重載它們,并做出相應的處理。如果你的Filter負責給發送出去的Sample打時間戳,那么,在Mediaseeking之后應該重新從零開始打起。

  4. 關于使用專門的線程

  如果你使用了專門的線程進行數據的處理和發送,你需要特別小心,不要讓線程進行死循環,并且要讓線程處理函數能夠去時時檢查線程命令。應該確保在Filter結束工作的時候,線程也能正常地結束。有時候,你把GraphEdit程序關掉,但GraphEdit進程仍在內存中,往往就是因為數據線程沒有安全關閉這個原因。

  5. 如何從媒體類型中獲取信息

  比如,你想在輸入Pin連接的媒體類型中,獲取視頻圖像的寬、高等信息,你應該在輸入Pin的CompleteConnect方法中實現,而不要在SetMediaType中。

  DirectX媒體對象(DirectX Media Objects,簡稱DMOs),是微軟提供的另一種流數據處理COM組件。與DirectShow filter相比,DMO有很多相似之處。對filter原理的熟悉,將會大大幫助你對DMO的學習。另外,DMO也因其結構簡單、易于創建和使用而倍受微軟推崇。


DMO與filter的對比

  1. DMO比filter實現的功能要少很多,這使得DMO“體積”很小;

  2. DMO使用起來比filter更有靈活性。DMO的使用不需要filter graph,應用程序可以直接與DMO交互。而DMO也可以通過一個DMO wrapper filter工作于DirectShow環境;

  3. DMO總是同步處理數據,不像filter有獨立的數據傳送線程,需要考慮多線程編程問題;

  4. 與傳統的編解碼管理器ACM、VCM相比,用DMO開發的編解碼器是基于COM的,更易于擴展。并且DMO支持多個輸入和多個輸出;

  5. DMO不需要像filter一樣分配數據傳送的內存,而有DMO的使用者負責;

  6. DMO是一個獨立功能模塊,不需要像filter一樣連接成一條鏈路;

  7. DMO不需要像filter一樣將數據“推”下去,數據的輸入輸出都是由DMO的使用者完成的;

  所有這些優點,使得DMO成為微軟對于Encoder和Decoder開發的重點推薦模式。DirectX 9.0 SDK中,微軟更是把DMO從DirectShow中分離出來,而對于一些transform filter,微軟也推薦用DMO的方式來替換。

  關于DMO的使用方式,目前大概有兩種:一種是應用程序直接使用DMO,另一種就是在DirectShow filter中的應用。后者比較簡單,只是使用了一個DMO wrapper filter。在DirectShow應用程序中,DMO是對用戶透明的,所有使用DMO的工作均由DMO wrapper filter來完成。參見下面的代碼。

?

// Create the DMO Wrapper filter.
IBaseFilter *pFilter;
HRESULT hr = CoCreateInstance(CLSID_DMOWrapperFilter, NULL,
CLSCTX_INPROC_SERVER, IID_IBaseFilter,
reinterpret_cast<void**>(&pFilter));

if (SUCCEEDED(hr))
{
// Query for IDMOWrapperFilter.
IDMOWrapperFilter *pDmoWrapper;
hr = pFilter->QueryInterface(IID_IDMOWrapperFilter,
reinterpret_cast<void**>(&pDmoWrapper));

if (SUCCEEDED(hr))
{
// Initialize the filter.
hr = pDmoWrapper->Init(CLSID_MyDMO, DMOCATEGORY_VIDEO_EFFECT);
pDmoWrapper->Release();

if (SUCCEEDED(hr))
{
// Add the filter to the graph.
hr = pGraph->AddFilter(pFilter, L"My DMO");
}
}
pFilter->Release();
}

  而對于DMO的直接使用,以下幾點是要特別注意的。

  1. 在處理數據之前,必須為每條輸入輸出stream設置media type(Optional stream除外);

  2. 從DMO從獲取的media type未必包含format塊,但是在給DMO設置media type時,務必帶上這部分信息(MIDI除外);

  3. 應用程序必須自己負責分配數據緩存。緩存的大小可以通過調用DMO的IMediaObject::GetInputSizeInfo或IMediaObject::GetOutputSizeInfo得到。DMO使用的數據緩存也是一個COM對象,支持ImediaBuffer接口,與DirectShow filter的Media Sample類似。

  4. 一般的DMO依次調用IMediaObject::ProcessInput和IMediaObject::ProcessOutput處理數據,In-Place的DMO調用IMediaObjectInPlace::Process處理數據。兩套方法不能混用。

  5. 在調用ProcessOutput時,如果返回的標記是DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE,說明數據的數據還沒有完全取出,需要再次調用ProcessOutput。

  6. 所有輸入數據都已輸入完成,應該調用DMO的IMediaObject::Discontinuity方法。

  7. 如果你想中斷數據處理流程,調用DMO的IMediaObject::Flush。

  8. 區別兩種不同的可丟棄stream,標記分別為DMO_OUTPUT_STREAMF_OPTIONAL和DMO_OUTPUT_STREAMF_DISCARDABLE。注意,后者是要設置media type的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/455275.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/455275.shtml
英文地址,請注明出處:http://en.pswp.cn/news/455275.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

正則正整數含0

^0?$|^([1-9][0-9]*)?$

MySQL 數據庫導出導入操作

有時需要將 MySQL 數據庫中的數據導入到其它的數據庫中,這里以從 Ubuntu 系統的 MySQL 數據庫導出 zabbix 這個數據庫到 Windows 系統中的MySQL 為例。 導出數據庫 導出數據其實非常方便,比如將 MySQL 中的 zabbix 這個數據庫導出到當前文件夾&#xff…

您的apple id 暫時不符合使用此應用程序_Mac相機不工作時該怎么辦

蘋果公司的許多臺式機和筆記本電腦都包含一個內置網絡攝像頭,該公司愉快地將其稱為FaceTime相機。但是,如果您的Mac網絡攝像頭無法正常工作,并且在嘗試訪問它時顯示為斷開連接或不可用,則您可能不會感到高興。您可以嘗試以下操作來…

基于DirectShow的流媒體解碼和回放

一、 前言  流媒體的定義很廣泛,大多數時候指的是把連續的影像和聲音信息經過壓縮處理后放上網站服務器,讓用戶一邊下載一邊觀看、收聽,而不需要等整個壓縮文件下載到自己機器就可以觀看的視頻/音頻傳輸、壓縮技術。流媒體也指代由這種技術…

《知易行難》擴展練習

在學習了《知易行難》后,這個是一個選做的擴展練習,但是里面的問題真的的很好,所以我也將在這里真實的分享,但是有些敏感的人名我就隱去了。 1. 這一年你做了些什么事情? 1)團隊的整合,將團隊…

python 裁判文書網_python - 用selenium模擬登陸裁判文書網,系統報錯找不到元素。...

問 題from selenium import webdriverfrom selenium.webdriver.common.desired_capabilities import DesiredCapabilitiesdcap dict(DesiredCapabilities.PHANTOMJS)dcap["phantomjs.page.settings.userAgent"]("Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWeb…

Python 四大主流 Web 編程框架

目前Python的網絡編程框架已經多達幾十個,逐個學習它們顯然不現實。但這些框架在系統架構和運行環境中有很多共通之處,本文帶領讀者學習基于Python網絡框架開發的常用知識,及目前的4種主流Python網絡框架:Django、Tornado、Flask、Twisted。 …

汕頭市隊賽 SRM16 T2

描述 貓和老鼠,看過吧?貓來了,老鼠要躲進洞里。在一條數軸上,一共有n個洞,位置分別在xi,能容納vi只老鼠。一共有m只老鼠位置分別在Xi,要躲進洞里,問所有老鼠跑進洞里的距離總和最小是…

基于django和vue的xdh官網設計

前言 本項目是使用三段分離的設計 前臺 使用materialize框架搭建的前臺頁面,后端使用的django寫的接口 后臺 使用Amazon UI 模板搭建的界面,管理各個部分的內容 項目環境 python3.7.2 django2.2.9 vue axios jQuery materialize mysql摘 要 本設計采用前后端分離的設計…

C#調用WebService實例和開發(轉)

http://www.cnblogs.com/peterpc/p/4628441.html 一、基本概念 Web Service也叫XML Web Service WebService是一種可以接收從Internet或者Intranet上的其它系統中傳遞過來的請求,輕量級的獨立的通訊技術。是:通過SOAP在Web上提供的軟件服務,使用WSDL文件…

智能情緒分析技術_簡單分析人工智能的表現在計算機網絡應用技術中的優勢

簡單分析人工智能的表現在計算機網絡應用技術中的優勢大數據時代背景下, 計算機網絡技術迅猛發展, 而人工智能技術的發展也進一步推動了計算機網絡技術的發展, 兩者相互融合, 相互促進, 實現了雙贏發展。從人工智能技術…

隨筆:關于關于

突然感覺挺累的。 我愛你。 北京,加油。轉載于:https://www.cnblogs.com/zhengzeze/p/7448878.html

MV預測過程詳解

第一步:確定相鄰塊 MV 預測以宏塊分割(或亞宏塊分割,如果宏塊存在亞分割)為單位,同一個宏塊分割(或亞宏塊分割)內所有 4*4 塊 MV 預測值相同。以每個宏塊分割(或亞宏塊分割&…

Django models中關于blank與null的補充說明

建立一個簡易Model class Person(models.Model):GENDER_CHOICES((1,Male),(2,Female),)namemodels.CharField(max_length30,uniqueTrue,verbose_name姓 名) birthdaymodels.DateField(blankTrue,nullTrue)gendermodels.IntegerField(choicesGENDER_CHOICES)accountmodels.In…

python 人臉關鍵點檢測_opencv+python+dlib人臉關鍵點檢測、實時檢測

安裝的是anaconde3、python3.7.3,3.7環境安裝dlib太麻煩,在anaconde3中新建環境python3.6.8,在3.6環境下安裝dlib-19.6.1-cp36-cp36m-win_amd64.whl,下載地址:https://pypi.org/project/dlib/19.6.1/#filesvscode更改配…

Zabbix2.2.6郵件報警設置方法

http://www.jb51.net/article/56973.htm 這篇文章主要介紹了Zabbix郵件報警設置方法,在Zabbix服務端設置郵件報警,當被監控主機宕機或者達到觸發器預設值時,會自動發送報警郵件到指定郵箱說明:Zabbix監控服務端、客戶端都已經部署完…

Skip宏塊與Direct預測模式淺析

對于我來說,這個是一個老問題了。以前藍風車專門給我講解,我都沒搞懂(真有點對不起藍風車的細心教誨哈。呵呵~~~)。今天終于弄清楚了,特此總結出來,請大家指正。 B_Skip類型宏…

自律

生活上的自律 寫出自律的代碼 身體上的自律 日常生活中,存在這么兩條路。一條路誘惑我們只根據自己的沖動和直覺來生活。這條路可以稱為「寵物之路」,因為所有的動物,包括家里養的寵物狗走的都是這條路。餓了就吃,吃完就算。…

解決兼容性的庫

HTML5標簽兼容方案&#xff1a;html5shiv.js [GitHub地址&#xff1a;https://github.com/aFarkas/html5shiv/] IE8不支持HTML5的新標簽&#xff0c;如<header>、<nav>等標簽在IE8無法渲染。html5shiv.js可幫助IE6-8瀏覽器兼容HTML5語義化標簽。 使用方法&#xff…

H.264 中的相關問題

幀內解碼時&#xff0c;在解碼端&#xff0c;首先通過當前宏塊左邊、上邊已經解碼完成的宏塊使用當前宏塊的預測模式&#xff08;預測模式計算過程請參見我的論文《H.264數字視頻差錯控制技術的研究》&#xff0c;在群FTP“本群原創資料”目錄中&#xff09;得到當前宏塊的像素…