视频采集、视频压缩
1.引言
????? 視頻的采集和壓縮是進行視頻傳輸、監(jiān)控等視頻應(yīng)用開發(fā)時必須采取的步驟。?
??????關(guān)于視頻采集,本文探討了一種基于Windows平臺的簡單而實用的方法,利用微軟提供的VFW(Video For Windows)軟件包來實現(xiàn),只需要有一般的USB攝像頭,就可以方便地對視頻進行采集和保存。?
????視頻壓縮方面,本文探討了如何利用現(xiàn)階段壓縮率最大、傳輸可靠性最高的一種編碼標(biāo)準(zhǔn)—H.264標(biāo)準(zhǔn)的開源編碼器(T264)來實現(xiàn)對采集到的視頻文件進行壓縮的方法,利用VFW 所采集到的視頻格式是沒有進行任何壓縮的AVI 格式,首先對AVI 格式進行轉(zhuǎn)換,再利用T264源碼對轉(zhuǎn)換后的視頻流文件進行壓縮編碼,這樣就極大地壓縮了視頻文件,方便視頻的傳輸。
2.視頻信息的采集
??? 由于利用VFW軟件包能夠方便地實現(xiàn)視頻、音頻數(shù)據(jù)流到AVI文件的存儲,在Visual C++中將VFW軟件包的函數(shù)封裝成為AVICAP窗口類函數(shù),利用AVICAP窗口類函數(shù),程序員能夠通過發(fā)送消息或設(shè)置屬性來捕獲、播放和編輯視頻剪輯,能靈活地實現(xiàn)從模擬視頻源采集數(shù)字視頻信號,并將捕捉的視頻流存儲到磁盤或者直接對視頻緩存進行處理。
????本文所述的方法是在Viusal C++ 6.0 軟件平臺上實現(xiàn)的,而軟件實現(xiàn)的具體步驟如下:?
????1)在采集視頻前必須先創(chuàng)建一個視頻采集的窗口,以及添加一些具體的操作按鈕,窗口利用函數(shù)capCreateCaptureWindow 來創(chuàng)建,如果窗口創(chuàng)建成功,返回窗口的句柄(程序中hwndV),如果創(chuàng)建不成功,則返回NULL 值。具體的創(chuàng)建程序及注釋如下:?
???????hwndV=capCreateCaptureWindow(?
??????(LPSTR) "My Capture Window",?? //捕捉窗口名稱
????????????????WS_CHILD | WS_VISIBLE,?????? //窗口風(fēng)格樣式?
????????????????????????150, 150, 300, 280,????????? //窗口位置和大小?
????????????????????????(HWND) hwndMain,???????????? //父窗口句柄?
????????????????(int) 1);??????????????????? //窗口標(biāo)識?
???????2)采集開始前,要將采集窗口與視頻設(shè)備相關(guān)聯(lián),VFW接口采用capDriverConnect?(hWndCap,,nIndex)這個函數(shù),式中:hWndCap所建立的視頻捕捉窗口的句柄;nIndex為查詢得到的視頻卡驅(qū)動程序的索引號。接下來,獲取視頻采集設(shè)備的能力及狀態(tài)信息,VFW中采用函數(shù)capDriverGetCaps(hwnd,psCaps,wsize)來得到采集設(shè)備的能力,而采用capGetStatus (hwnd,s,size)函數(shù)來得到采集設(shè)備的狀態(tài)信息。
???????3)啟動顯示模式并設(shè)置其模式參數(shù),AVICAP? 窗口類采用兩個函數(shù)來實現(xiàn),具體程序和注釋如下:??
?? ?? ?capPreviewRate( hwndVideo, 66); //設(shè)置預(yù)覽播放速率?
???? ?? capreview( hwndVideo, TRUE);?? //啟動預(yù)覽模式?
??????4)采集視頻流并保存,并終止視頻采集并斷開與采集設(shè)備的連接,在程序的開頭定義一個結(jié)構(gòu)體OPENFN,用于初始化一個對話框,而這個對話框是用來保存視頻的對話框。?
??具體程序如下:?
?if (!isRecordFileOpen)?
{?
????? OPENFN ofname;???? //打開文件結(jié)構(gòu)體?
???????ZeroMemory(&ofname, sizeof(OPENFN)); //初始化結(jié)構(gòu)體?
??????ofname.lStructSize = sizeof(OPENFN);??? //結(jié)構(gòu)體的大小?
??????ofname.hwndOwner = hwndMain;??????????? //主窗口句柄?
?????ofname.lpstrFile = recordFile;???????? //保存的文件指針?
?????ofname.nMaxFile = sizeof(recordFile);?? //保存文件的大小?
??????ofname.lpstrFilter = "Video\0*.avi";?? //保存文件的后綴?
??????ofname.nFilterIndex = 1;?????????????? //文件索引號?
??????ofname.lpstrFileTitle = NULL;????????? //文件名指針?
??????ofname.nMaxFileTitle = 0;?
??? ofname.lpstrInitialDir = NULL;?
??? ofname.Flags=OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST;?
?????if(GetSaveFileName(&ofn) == TRUE)??? //顯示保存文件的對話框?
?????{?
?????? strcpy(recordFile, ofn.lpstrFile);?
?????? strcat(recordFile, ".avi");?
?????? isRecordFileOpen = true;?
???? }?
?}?
????????設(shè)置好保存文件以后,需用函數(shù)CreateThread來創(chuàng)建一個錄像的線程在其中采集視頻流,并利用函數(shù)capDriverDisconnect 來終止視頻采集并斷開與采集設(shè)備的連接,錄像線程的具體代碼如下:
?????? DWORD id;????????????????????????? //創(chuàng)建一個錄像線程?
??????????SECURITY_ATTRIBUTES ma;?
?????? ma.nLength = sizeof(SECURITY_ATTRIBUTES);?
?????? ma.lpSecurityDescriptor = NULL;?
?????? ma.bInheritHandle = TRUE;?
?????? hVideoThread = (&ma, (ULONG)0,?
?????? videoThreadProc, (LPVOID)(ULONG)0, (ULONG)0, &id);
3.視頻格式的轉(zhuǎn)換
???? 本文所采用的是基于H.264編碼標(biāo)準(zhǔn)的視頻壓縮方法,所利用的源碼是由中國視頻編碼自由組織聯(lián)合開發(fā)的t264編解碼器,在使用本源碼前,編碼器要求進行壓縮的文件格式應(yīng)為YUV 格式視頻文件,而VFW采集到的視頻文件是最原始的AVI 格式,因而要進行格式的轉(zhuǎn)換 。?
???????從AVI格式到Y(jié)UV 格式的轉(zhuǎn)換,并沒有直接的公式,而AVI視頻文件流的每一幀對應(yīng)一個BMP(RGB)文件,則可以利用公式轉(zhuǎn)換成YUV 文件,轉(zhuǎn)換的公式如下:
??? ?Y = 0.299R + 0.587G + 0.114B?
???? Cb = 0.564(B - Y )?
??? ?Cr = 0.713(R -Y )?
??????其中,Cb 對應(yīng)U,Cr 對應(yīng)V,分別表示構(gòu)成彩色的兩個分量,而在程序中,則通過以下的程序來實現(xiàn)(按4:2:0 采樣格式):?
??????void RGB2YUV ( uint8 R, uint8 G, uint8 B, uint8 *y, uint8 *u, uint8 *v )?
?? {?
???? *y = Clip ( ( ( 66 * int(R) + 129 * int(G) + 25 * int(B) + 128) >> 8) + 16 );?
???? *u = Clip ( ( ( -38 * int(R) - 74 * int(G) + 112 * int(B) + 128) >> 8) + 128 );?
???? *v = Clip ( ( ( 112 * int(R) - 94 * int(G) - 18 * int(B) + 128) >> 8) + 128 );?
?? }
4.利用編碼器進行壓縮編碼
???? 由中國視頻編碼自由組織聯(lián)合開發(fā)的編碼器在基于VisualC++平臺上創(chuàng)建了一個console程序,而前述的視頻采集程序因為有窗口、按鈕等視圖窗口,故是一個windows程序,在Visual C++平臺中,要將console 程序和windows 程序很好地結(jié)合在一起使用,是個很復(fù)雜的過程,因此,可以在前面視頻采集程序里面運用一個C++函數(shù)ShellExecute 來調(diào)用編碼器函數(shù)。?
??? 具體實現(xiàn)的步驟如下:?
????1)首先針對采集后經(jīng)格式轉(zhuǎn)換生成的YUV文件,得到它的幀數(shù)目,在配置文件enconfig.txt修改編碼幀的數(shù)目,例如如果幀數(shù)目為100,將enconfig.txt 文件中的第6、7、8 行:?
?????300 # total frame number?
??? 300 # i intervals?
??? 300 # idr intervals?
?????改為?:
? ? 100 # total frame number?
??? 100 # i intervals?
??? 100 # idr intervals?
?????幀數(shù)目修改以后,文件生成的路徑也應(yīng)該改為最終exe 文件生成的路徑,在enconfig.txt的最后三行進行修改。?
????1)編譯編碼器,是采用的CONSOLE 程序,一般是在命令行中來執(zhí)行exe 程序,而本文中的方法是利用入口函數(shù)main(int argc, char* argv[])的特征,其中,argc 表示參數(shù)的個數(shù),而argv[]數(shù)組用于保存參數(shù)的指針,在程序中就對參數(shù)進行賦值,省去了進入命令行進行執(zhí)行的繁瑣過程,從而生成一個可以直接拿來運用的exe 程序。具體賦值語句如下:?
?????argv[0]="T264.exe";?
?? argv[1]="-e";?
?? argv[2]="enconfig.txt";?
???2)設(shè)置t264.exe 文件路徑,上述的過程中已經(jīng)生成一個可執(zhí)行的t264.exe 文件,如果將YUV文件放在與之相同的目錄下,在調(diào)試運行這個程序的時候就可以生成264碼流文件,達到編碼的目的。但本文是需要將采集、壓縮編碼在同一個程序中完成,因而把生成的t264.exe文件復(fù)制到采集程序的調(diào)試目錄下面。?
3)上述的工作都做好以后,可以在采集程序里面調(diào)用編碼器程序了,這時用一個函數(shù)來實現(xiàn),具體代碼是:??
???????????ShellExecute(NULL,"open","t264.exe",?
?????? "T264.exe –e enconfig.txt",NULL,SW_SHOWNORMAL);?
??????其中,SW_SHOWNORMAL 指的是一種程序運行風(fēng)格,此時代表正常運行,在調(diào)用時可以看到程序運行的全部過程(DOS命令窗口顯示),如果需要程序透明執(zhí)行,不可見,則可以用SW_HIDE 來代替它。?
??????至此,整個視頻采集、格式轉(zhuǎn)換與編碼壓縮的過程就全部完成了,本文中所采集的AVI文件大小為4.075M,經(jīng)格式轉(zhuǎn)換后的YUV 文件大小為5.458M,而最終生成的264 碼流大小只有27k,壓縮率達到了150.9倍。
5.總結(jié)?
???本文所探討的從視頻采集、格式轉(zhuǎn)換到壓縮編碼的整個過程,可以簡單方便地完成,可以直接應(yīng)用在視頻監(jiān)控或者視頻的網(wǎng)絡(luò)傳輸?shù)鹊那捌陂_發(fā)。佰銳科技已為視頻監(jiān)控音視頻即時通訊提供了解決方案。
本文轉(zhuǎn)自 fanxiaojun 51CTO博客,原文鏈接:http://blog.51cto.com/2343338/493899,如需轉(zhuǎn)載請自行聯(lián)系原作者
總結(jié)
- 上一篇: 一主两从的环境,如果主库挂了,如何选举一
- 下一篇: 楚留香200后期强势职业