基于linux下的音視頻采集與傳輸_第1頁(yè)
基于linux下的音視頻采集與傳輸_第2頁(yè)
基于linux下的音視頻采集與傳輸_第3頁(yè)
基于linux下的音視頻采集與傳輸_第4頁(yè)
基于linux下的音視頻采集與傳輸_第5頁(yè)
已閱讀5頁(yè),還剩54頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

基于linux下的音視頻采集與傳輸.基于linux下的音視頻采集與傳輸.59/59基于linux下的音視頻采集與傳輸.基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux大綱:在LINUX下實(shí)現(xiàn)對(duì)音頻和視頻的采集,并編寫(xiě)Socket程序?qū)⒉杉降囊纛l文件在兩臺(tái)主機(jī)的進(jìn)度之間進(jìn)行傳輸。重點(diǎn)字:LINUX音頻、視頻采集Socket傳輸1基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux項(xiàng)目簡(jiǎn)介本項(xiàng)目將分成三部分來(lái)分別實(shí)現(xiàn),分別為L(zhǎng)inux下視頻的采集、Linux下音頻的采集、Linux下Socket傳輸?shù)膶?shí)現(xiàn)。下面將分別介紹各部分詳盡的實(shí)現(xiàn)過(guò)程。Linux下視頻采集1、背景介紹V4L,其全稱(chēng)是Video4Linux(VideoforLinux),是在linux內(nèi)核中關(guān)于視頻設(shè)備的API接口,涉及開(kāi)關(guān)視頻設(shè)備、采集并辦理視頻圖像信息。V4L從2.1.x版本的內(nèi)核中開(kāi)始出現(xiàn)?,F(xiàn)在出現(xiàn)Video4Linux2(VideoforLinuxTwo),簡(jiǎn)稱(chēng)V4L2。很顯然,他是V4L的改進(jìn)版,修復(fù)了第一代的部分設(shè)計(jì)bug。從開(kāi)始,V4L2就被集成到內(nèi)核里面去了。盡管這樣,還是有一部分設(shè)備的驅(qū)動(dòng)不支持新版本的V4L2,因此,有時(shí)我們會(huì)看到V4L跟V4L2同時(shí)出現(xiàn)在代碼里面。Linux系統(tǒng)中,視頻設(shè)備被看作一個(gè)設(shè)備文件來(lái)對(duì)待,設(shè)備文件存放在/dev目錄下,完滿(mǎn)路徑的設(shè)備文件名為:/dev/video0.2、視頻采集基本步驟視頻采集基本步驟流程:打開(kāi)設(shè)備->檢查和設(shè)置設(shè)備屬性->設(shè)置幀格式->設(shè)置一種輸入輸出方法(緩沖區(qū)管理)->循環(huán)獲取數(shù)據(jù)->關(guān)閉設(shè)備。其中打開(kāi)視頻設(shè)備特別簡(jiǎn)單,在V4L2中,視頻設(shè)備被看做一個(gè)文件。使用open函數(shù)打開(kāi)這個(gè)設(shè)備,打開(kāi)這個(gè)設(shè)備有兩種模式即擁塞模式和非擁塞模式。主要實(shí)現(xiàn)代碼為:○1用非擁塞模式打開(kāi)攝像頭設(shè)備代碼為intcameraFd;cameraFd=open("/dev/video0",O_RDWR|O_NONBLOCK);○2用擁塞模式打開(kāi)攝像頭設(shè)備,上述代碼變?yōu)椋篶ameraFd=open("/dev/video0",O_RDWR);應(yīng)用程序能夠使用擁塞模式或非擁塞模式打開(kāi)視頻設(shè)備,若是使用非擁塞模式調(diào)用視頻設(shè)備,即使還沒(méi)有捕獲到信息,驅(qū)動(dòng)依舊會(huì)把緩存(DQBUFF)里的東西返回給應(yīng)用程序。3、Linux視頻設(shè)備驅(qū)動(dòng)常用控制命令使用說(shuō)明設(shè)置視頻設(shè)備屬性經(jīng)過(guò)ioctl來(lái)進(jìn)行設(shè)置,ioctl有三個(gè)參數(shù),分別是fd,cmd,和parameter,表示設(shè)備描述符,控制命令和控制命令參數(shù)。Linux視頻設(shè)備驅(qū)動(dòng)接口V4L2支持的常用控制命令以下:○1控制命令VIDIOC_ENUM_FMT2基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux功能:獲取當(dāng)前視頻設(shè)備支持的視頻格式。參數(shù)說(shuō)明:參數(shù)種類(lèi)為V4L2的視頻格式描述符種類(lèi)structv4l2_fmtdesc返回值說(shuō)明:執(zhí)行成功時(shí),函數(shù)返回值為0;structv4l2_fmtdesc結(jié)構(gòu)體中的.pixelformat和.description成員返回當(dāng)前視頻設(shè)備所支持的視頻格式;使用舉例:structv4l2_fmtdescfmt;memset(&fmt,0,sizeof(fmt));fmt.index=0;fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;while((ret=ioctl(dev,VIDIOC_ENUM_FMT,&fmt))==0){fmt.index++;printf("{pixelformat=''%c%c%c%c'',description=''%s''}\n",fmt.pixelformat&0xFF,(fmt.pixelformat>>8)&0xFF,(fmt.pixelformat>>16)&0xFF,(fmt.pixelformat>>24)&0xFF,fmt.description);}○2控制命令VIDIOC_QUERYCAP功能:盤(pán)問(wèn)視頻設(shè)備的功能;參數(shù)說(shuō)明:參數(shù)種類(lèi)為V4L2的能力描述種類(lèi)structv4l2_capability;返回值說(shuō)明:執(zhí)行成功時(shí),函數(shù)返回值為0;函數(shù)執(zhí)行成功后,structv4l2_capability結(jié)構(gòu)體變量中的返回當(dāng)前視頻設(shè)備所支持的功能;比方支持視頻捕獲功能V4L2_CAP_VIDEO_CAPTURE、V4L2_CAP_STREAMING等。使用舉例:structv4l2_capabilitycap;iret=ioctl(fd_usbcam,VIDIOC_QUERYCAP,&cap);if(iret<0){printf("getvidieocapabilityerror,errorcode:%d\n",errno);return;}執(zhí)行完VIDIOC_QUERYCAP命令后,cap變量中包括了該視頻設(shè)備的能力信息,程序中經(jīng)過(guò)檢查cap中的設(shè)備能力信息來(lái)判斷設(shè)備可否支持某項(xiàng)功能?!?控制命令VIDIOC_S_FMT功能:設(shè)置視頻設(shè)備的視頻數(shù)據(jù)格式,比方設(shè)置視頻圖像數(shù)據(jù)的長(zhǎng)、寬,圖像格式(JPEG、YUYV格式);參數(shù)說(shuō)明:參數(shù)種類(lèi)為V4L2的視頻數(shù)據(jù)格式種類(lèi)structv4l2_format;返回值說(shuō)明:執(zhí)行成功時(shí),函數(shù)返回值為0;使用舉例:structv4l2_formattv4l2_format;tv4l2_format.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;tv4l2_format.fmt.pix.width=img_width;3基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinuxtv4l2_format.fmt.pix.height=img_height;tv4l2_format.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV;tv4l2_format.fmt.pix.field=V4L2_FIELD_INTERLACED;iret=ioctl(fd_usbcam,VIDIOC_S_FMT,&tv4l2_format);○4控制命令VIDIOC_REQBUFS功能:央求V4L2驅(qū)動(dòng)分配視頻緩沖區(qū)(申請(qǐng)V4L2視頻驅(qū)動(dòng)分配內(nèi)存),V4L2是視頻設(shè)備的驅(qū)動(dòng)層,位于內(nèi)核空間,因此經(jīng)過(guò)VIDIOC_REQBUFS控制命令字申請(qǐng)的內(nèi)存位于內(nèi)核空間,應(yīng)用程序不能夠直接接見(jiàn),需要經(jīng)過(guò)調(diào)用mmap內(nèi)存照射函數(shù)把內(nèi)核空間內(nèi)存照射到用戶(hù)空間后,應(yīng)用程序經(jīng)過(guò)接見(jiàn)用戶(hù)空間地址來(lái)接見(jiàn)內(nèi)核空間。參數(shù)說(shuō)明:參數(shù)種類(lèi)為V4L2的申請(qǐng)緩沖區(qū)數(shù)據(jù)結(jié)構(gòu)體種類(lèi)structv4l2_requestbuffers;0;V4L2驅(qū)動(dòng)層分配好了視頻緩沖區(qū);返回值說(shuō)明:執(zhí)行成功時(shí),函數(shù)返回值為使用舉例:structv4l2_requestbufferstV4L2_reqbuf;memset(&tV4L2_reqbuf,0,sizeof(structv4l2_requestbuffers));tV4L2_reqbuf.count=1;tV4L2_reqbuf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;tV4L2_reqbuf.memory=V4L2_MEMORY_MMAP;iret=ioctl(fd_usbcam,VIDIOC_REQBUFS,&tV4L2_reqbuf);注意:VIDIOC_REQBUFS會(huì)更正tV4L2_reqbuf的count值,tV4L2_reqbuf的count值返回實(shí)質(zhì)申請(qǐng)成功的視頻緩沖區(qū)數(shù)目;○5控制命令VIDIOC_QUERYBUF功能:盤(pán)問(wèn)已經(jīng)分配的V4L2的視頻緩沖區(qū)的相關(guān)信息,包括視頻緩沖區(qū)的使用狀態(tài)、在內(nèi)核空間的偏移地址、緩沖區(qū)長(zhǎng)度等。在應(yīng)用程序設(shè)計(jì)中經(jīng)過(guò)調(diào)VIDIOC_QUERYBUF來(lái)獲取內(nèi)核空間的視頻緩沖區(qū)信息,爾后調(diào)用函數(shù)mmap把內(nèi)核空間地址照射到用戶(hù)空間,這樣應(yīng)用程序才能夠接見(jiàn)位于內(nèi)核空間的視頻緩沖區(qū)。參數(shù)說(shuō)明:參數(shù)種類(lèi)為V4L2緩沖區(qū)數(shù)據(jù)結(jié)構(gòu)種類(lèi)structv4l2_buffer;返回值說(shuō)明:執(zhí)行成功時(shí),函數(shù)返回值為0;structv4l2_buffer結(jié)構(gòu)體變量中保存了指令的緩沖區(qū)的相關(guān)信息;一般狀況下,應(yīng)用程序中調(diào)用VIDIOC_QUERYBUF獲取了內(nèi)核緩沖區(qū)信息后,緊接著調(diào)用mmap函數(shù)把內(nèi)核空間地址照射到用戶(hù)空間,方便用戶(hù)空間應(yīng)用程序的接見(jiàn)。使用舉例:structv4l2_buffertV4L2buf;memset(&tV4L2buf,0,sizeof(structv4l2_buffer));tV4L2buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;tV4L2buf.memory=V4L2_MEMORY_MMAP;tV4L2buf.index=i;iret=ioctl(fd_usbcam,VIDIOC_QUERYBUF,&tV4L2buf);AppBufLength=tV4L2buf.length;4基于linux下的音視頻采集與傳輸BasedontheacquisitionandtransmissionofaudioandvideounderlinuxAppBufStartAddr=mmap(NULL/*startanywhere*/,tV4L2buf.length,PROT_READ|PROT_WRITE/*accessprivilege*/,MAP_SHARED/*recommended*/,fd_usbcam,tV4L2buf.m.offset);上述代碼在經(jīng)過(guò)調(diào)用VIDIOC_QUERYBUF獲取內(nèi)核空間的緩沖區(qū)信息后,接著調(diào)用mmap函數(shù)把內(nèi)核空間緩沖區(qū)照射到用戶(hù)空間。○6控制命令VIDIOC_QBUF功能:投放一個(gè)空的視頻緩沖區(qū)到視頻緩沖區(qū)輸入隊(duì)列中;參數(shù)說(shuō)明:參數(shù)種類(lèi)為V4L2緩沖區(qū)數(shù)據(jù)結(jié)構(gòu)種類(lèi)structv4l2_buffer;返回值說(shuō)明:執(zhí)行成功時(shí),函數(shù)返回值為0;函數(shù)執(zhí)行成功后,指令(指定)的視頻緩沖區(qū)進(jìn)入視頻輸入隊(duì)列,在啟動(dòng)視頻設(shè)備拍攝圖像時(shí),相應(yīng)的視頻數(shù)據(jù)被保存到視頻輸入隊(duì)列相應(yīng)的視頻緩沖區(qū)中。使用舉例:structv4l2_buffertV4L2buf;memset(&tV4L2buf,0,sizeof(structv4l2_buffer));tV4L2buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;tV4L2buf.memory=V4L2_MEMORY_MMAP;tV4L2buf.index=i;iret=ioctl(fd_usbcam,VIDIOC_QBUF,&tV4L2buf);○7控制命令VIDIOC_STREAMON功能:?jiǎn)?dòng)視頻采集命令,應(yīng)用程序調(diào)用VIDIOC_STREAMON啟動(dòng)視頻采集命令后,視頻設(shè)備驅(qū)動(dòng)程序開(kāi)始采集視頻數(shù)據(jù),并把采集到的視頻數(shù)據(jù)保存到視頻驅(qū)動(dòng)的視頻緩沖區(qū)中。參數(shù)說(shuō)明:參數(shù)種類(lèi)為V4L2的視頻緩沖區(qū)種類(lèi)enumv4l2_buf_type;返回值說(shuō)明:執(zhí)行成功時(shí),函數(shù)返回值為0;函數(shù)執(zhí)行成功后,視頻設(shè)備驅(qū)動(dòng)程序開(kāi)始采集視頻數(shù)據(jù),此時(shí)應(yīng)用程序一般經(jīng)過(guò)調(diào)用select函數(shù)來(lái)判斷一幀視頻數(shù)據(jù)可否采集達(dá)成,當(dāng)視頻設(shè)備驅(qū)動(dòng)達(dá)成一幀視頻數(shù)據(jù)采集并保存到視頻緩沖區(qū)中時(shí),select函數(shù)返回,應(yīng)用程序接著能夠讀取視頻數(shù)據(jù);否則select函數(shù)阻塞直到視頻數(shù)據(jù)采集達(dá)成。使用舉例:enumv4l2_buf_typev4l2type=V4L2_BUF_TYPE_VIDEO_CAPTURE;fd_setfds;structtimevaltv;iret=ioctl(fd_usbcam,VIDIOC_STREAMON,&v4l2type);FD_ZERO(&fds);FD_SET(fd_usbcam,&fds);tv.tv_sec=2;/*Timeout.*/tv.tv_usec=0;iret=select(fd_usbcam+1,&fds,NULL,NULL,&tv);○8控制命令VIDIOC_DQBUF5基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux功能:從視頻緩沖區(qū)的輸出隊(duì)列中獲取一個(gè)已經(jīng)保存有一幀視頻數(shù)據(jù)的視頻緩沖區(qū);參數(shù)說(shuō)明:參數(shù)種類(lèi)為V4L2緩沖區(qū)數(shù)據(jù)結(jié)構(gòu)種類(lèi)structv4l2_buffer返回值說(shuō)明:執(zhí)行成功時(shí),函數(shù)返回值為0;函數(shù)執(zhí)行成功后,相應(yīng)的內(nèi)核視頻緩沖區(qū)中保存有當(dāng)前拍攝到的視頻數(shù)據(jù),應(yīng)用程序能夠經(jīng)過(guò)接見(jiàn)用戶(hù)空間來(lái)讀取該視頻數(shù)據(jù)。(前面已經(jīng)經(jīng)過(guò)調(diào)用函數(shù)mmap做了用戶(hù)空間和內(nèi)核空間的內(nèi)存照射).使用舉例:structv4l2_buffertV4L2buf;memset(&tV4L2buf,0,sizeof(structv4l2_buffer));tV4L2buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;tV4L2buf.memory=V4L2_MEMORY_MMAP;iret=ioctl(fd_usbcam,VIDIOC_DQBUF,&tV4L2buf);Sasoritattoo說(shuō)明:VIDIOC_DQBUF命令結(jié)果使從隊(duì)列刪除的緩沖幀信息傳給了此tVL2buf。V4L2_buffer結(jié)構(gòu)體的作用就相當(dāng)于申請(qǐng)的緩沖幀的代理,找緩沖幀的都要先問(wèn)問(wèn)它,經(jīng)過(guò)它來(lái)聯(lián)系緩沖幀,起了中間橋梁的作用?!?控制命令VIDIOC_STREAMOFF功能:停止視頻采集命令,應(yīng)用程序調(diào)用VIDIOC_STREAMOFF停止視頻采集命令后,視頻設(shè)備驅(qū)動(dòng)程序不在采集視頻數(shù)據(jù)。參數(shù)說(shuō)明:參數(shù)種類(lèi)為V4L2的視頻緩沖區(qū)種類(lèi)enumv4l2_buf_type;返回值說(shuō)明:執(zhí)行成功時(shí),函數(shù)返回值為0;函數(shù)執(zhí)行成功后,視頻設(shè)備停止采集視頻數(shù)據(jù)。使用舉例:enumv4l2_buf_typev4l2type;v4l2type=V4L2_BUF_TYPE_VIDEO_CAPTURE;iret=ioctl(fd_usbcam,VIDIOC_STREAMOFF,&v4l2type);4、YUYV變換為RGB由于攝像頭支持的視頻格式為YUYV,不能夠直接顯示,因此將其變換為RGB格式,以方便下一步的圖片保存以及視頻保存。像素變換算法以下:r=y+(1.370705*(v-128));g=y-(0.698001*(v-128))-(0.337633*(u-128));b=y+(1.732446*(u-128));if(r>255)r=255;if(g>255)g=255;if(b>255)b=255;if(r<0)r=0;if(g<0)g=0;if(b<0)b=0;pixel[0]=r*220/256;pixel[1]=g*220/256;pixel[2]=b*220/256;6基于linux下的音視頻采集與傳輸BasedontheacquisitionandtransmissionofaudioandvideounderlinuxLinux下音頻采集1、背景介紹(1)ALSAALSA是AdvancedLinuxSoundArchitecture,高級(jí)Linux聲音架構(gòu)的簡(jiǎn)稱(chēng),它在Linux操作系統(tǒng)上供應(yīng)了音頻和MIDI(MusicalInstrumentDigitalInterface,音樂(lè)設(shè)備數(shù)字化接口)的支持。在2.6系列內(nèi)核中,ALSA已經(jīng)成為默認(rèn)的聲音子系統(tǒng),用來(lái)代替2.4系列內(nèi)核中的OSS(OpenSoundSystem,開(kāi)放聲音系統(tǒng))。ALSA的主要特點(diǎn)包括:高效地支持從花銷(xiāo)類(lèi)入門(mén)級(jí)聲卡到專(zhuān)業(yè)級(jí)音頻設(shè)備所有種類(lèi)的音頻接口,完滿(mǎn)模塊化的設(shè)計(jì),支持對(duì)稱(chēng)多辦理(SMP)和線程安全,對(duì)OSS的向后兼容,以及供應(yīng)了用戶(hù)空間的alsa-lib庫(kù)來(lái)簡(jiǎn)化應(yīng)用程序的開(kāi)發(fā)。ALSA是一個(gè)完滿(mǎn)開(kāi)放源代碼的音頻驅(qū)動(dòng)程序集,除了像OSS那樣供應(yīng)了一組內(nèi)核驅(qū)動(dòng)程序模塊之外,ALSA還特地為簡(jiǎn)化應(yīng)用程序的編寫(xiě)供應(yīng)了相應(yīng)的函數(shù)庫(kù),與OSS供應(yīng)的基于ioctl的原始編程接口對(duì)照,ALSA函數(shù)庫(kù)使用起來(lái)要更加方便一些。利用該函數(shù)庫(kù),開(kāi)發(fā)人員能夠方便快捷的開(kāi)發(fā)出自己的應(yīng)用程序,細(xì)節(jié)則留給函數(shù)庫(kù)內(nèi)部辦理。自然ALSA也供應(yīng)了近似于OSS的系統(tǒng)接口,但是ALSA的開(kāi)發(fā)者建議應(yīng)用程序開(kāi)發(fā)者使用音頻函數(shù)庫(kù)而不是驅(qū)動(dòng)程序的API。(2)音頻采集看法數(shù)碼音頻系統(tǒng)是經(jīng)過(guò)將聲波波形變換成一連串的二進(jìn)制數(shù)據(jù)來(lái)再現(xiàn)原始聲音的,實(shí)現(xiàn)這個(gè)步驟使用的設(shè)備是模/數(shù)變換器(A/D)它以每秒上萬(wàn)次的速率對(duì)聲波進(jìn)行采樣,每一次采樣都記錄下了原始模擬聲波在某一時(shí)辰的狀態(tài),稱(chēng)之為樣本。將一串的樣本連接起來(lái),就可以描述一段聲波了,把每一秒鐘所采樣的數(shù)目稱(chēng)為采樣頻率或采率,單位為HZ(赫茲)。采樣頻率越高所能描述的聲波頻率就越高。采樣率決定聲音頻率的范圍(相當(dāng)于音調(diào)),能夠用數(shù)字波形表示。以波形表示的頻率范圍平時(shí)被稱(chēng)為帶寬。要正確理解音頻采樣能夠分為采樣的位數(shù)和采樣的頻率。(3)主要參數(shù)①采樣位數(shù)采樣位數(shù)能夠理解為采集卡辦理聲音的解析度。這個(gè)數(shù)值越大,解析度就越高,錄制和回放的聲音就越真實(shí)。我們第一要知道:電腦中的聲音文件是用數(shù)字0和1來(lái)表示的。因此在電腦上錄音的實(shí)質(zhì)就是把模擬聲音信號(hào)變換成數(shù)字信號(hào)。反之,在播放時(shí)則是把數(shù)字信號(hào)還原成模擬聲音信號(hào)輸出。采集卡的位是指采集卡在采集和播放聲音文件時(shí)所使用數(shù)字聲音信號(hào)的二進(jìn)制位數(shù)。采集卡的位客觀地反響了數(shù)字聲音信號(hào)對(duì)輸入聲音信號(hào)描述的正確程度。8位代表2的8次方--256,16位則代表2的16次方--64K。比較一下,一段相同的音樂(lè)信息,16位聲卡能把它分為64K個(gè)精度單位進(jìn)行辦理,而8位聲卡只能辦理256個(gè)精度單位,造成了較大的信號(hào)損失,最后的采樣收效自然是無(wú)法相提并論的?,F(xiàn)在市道上所有的主流產(chǎn)品都是16位的采集卡,而其實(shí)不是有些無(wú)知商家所煽動(dòng)的64位乃至128位,他們將采集卡的復(fù)音看法與采樣位數(shù)看法混淆在了一起。現(xiàn)在功能最為富強(qiáng)的采集卡系列采用的EMU10K1芯片誠(chéng)然號(hào)稱(chēng)能夠達(dá)到32位,但是它可是建立在DirectSound加速基礎(chǔ)上的一種多音頻流技術(shù),其實(shí)質(zhì)還是一塊16位的聲卡。應(yīng)該說(shuō)16位的采樣精度關(guān)于電腦多媒體音頻而言已經(jīng)綽綽有余了。7基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux②采樣頻率數(shù)碼音頻系統(tǒng)是經(jīng)過(guò)將聲波波形變換成一連串的二進(jìn)制數(shù)據(jù)來(lái)再現(xiàn)原始聲音的,實(shí)現(xiàn)這個(gè)步驟使用的設(shè)備是模/數(shù)變換器(A/D)它以每秒上萬(wàn)次的速率對(duì)聲波進(jìn)行采樣,每一次采樣都記錄下了原始模擬聲波在某一時(shí)辰的狀態(tài),稱(chēng)之為樣本。將一串的樣本連接起來(lái),就可以描述一段聲波了,把每一秒鐘所采樣的數(shù)目稱(chēng)為采樣頻率或采率,單位為HZ(赫茲)。采樣頻率越高所能描述的聲波頻率就越高。采樣頻率是指錄音設(shè)備在一秒鐘內(nèi)對(duì)聲音信號(hào)的采樣次數(shù),采樣頻率越高聲音的還原就越真實(shí)越自然。在現(xiàn)在的主流采集卡上,采樣頻率一般共分為22.05KHz、44.1KHz、48KHz三個(gè)等級(jí),22.05KHz只能達(dá)到FM廣播的聲音質(zhì)量,44.1KHz則是理論上的CD音質(zhì)界限,48KHz則更加精確一些。關(guān)于高于48KHz的采樣頻率人耳已無(wú)法鑒識(shí)出來(lái)了,因此在電腦上沒(méi)有多少使用價(jià)值。5kHz的采樣率僅能達(dá)到人們講話的聲音質(zhì)量。11kHz的采樣率是播放小段聲音的最低標(biāo)準(zhǔn),是CD音質(zhì)的四分之一。22kHz采樣率的聲音能夠達(dá)到CD音質(zhì)的一半,當(dāng)前大多數(shù)網(wǎng)站都采用這樣的采樣率。44kHz的采樣率是標(biāo)準(zhǔn)的CD音質(zhì),能夠達(dá)到很好的聽(tīng)覺(jué)收效。③位速位速是指在一個(gè)數(shù)據(jù)流中每秒鐘能經(jīng)過(guò)的信息量。您可能看到過(guò)音頻文件用“128–KbpsMP3”或“64–KbpsWMA”進(jìn)行描述的狀況。Kbps表示“每秒千位數(shù)”,因此數(shù)值越大表示數(shù)據(jù)越多:128–KbpsMP3音頻文件包括的數(shù)據(jù)量是64–KbpsWMA文件的兩倍,并占用兩倍的空間。(但是在這種狀況下,這兩種文件聽(tīng)起來(lái)沒(méi)什么兩樣。原因是什么呢?有些文件格式比其他文件能夠更有效地利用數(shù)據(jù),64–KbpsWMA文件的音質(zhì)與128–KbpsMP3的音質(zhì)相同。)需要認(rèn)識(shí)的重要一點(diǎn)是,位速越高,信息量越大,對(duì)這些信息進(jìn)行解碼的辦理量就越大,文件需要占用的空間也就越多。為項(xiàng)目選擇合適的位速取決于播放目標(biāo):如果您想把制作的VCD放在DVD播放器上播放,那么視頻必定是1150Kbps,音頻必定是224Kbps。典型的206MHzPocketPC支持的MPEG視頻可達(dá)到400Kbps—高出這個(gè)限度播放時(shí)就會(huì)出現(xiàn)異常。(4)ALSA系統(tǒng)結(jié)構(gòu)ALSAAPI能夠分解成以下幾個(gè)主要的接口:控制接口:供應(yīng)管理聲卡注冊(cè)和央求可用設(shè)備的通用功能PCM接口:管理數(shù)字音頻回放(playback)和錄音(capture)的接口。本文后續(xù)總結(jié)重點(diǎn)放在這個(gè)接口上,由于它是開(kāi)發(fā)數(shù)字音頻程序最常用到的接口。3RawMIDI接口:支持MIDI(MusicalInstrumentDigitalInterface),標(biāo)準(zhǔn)的電子樂(lè)器。這些API供應(yīng)對(duì)聲卡上MIDI總線的接見(jiàn)。這個(gè)原始接口基于MIDI事件工作,由程序員負(fù)責(zé)管理協(xié)議以實(shí)時(shí)間辦理。準(zhǔn)時(shí)器(Timer)接口:為同步音頻事件供應(yīng)對(duì)聲卡上時(shí)間辦理硬件的接見(jiàn)。時(shí)序器(Sequencer)接口混音器(Mixer)接口2、聲音緩存和數(shù)據(jù)傳輸每個(gè)聲卡都有一個(gè)硬件緩存區(qū)來(lái)保存記錄下來(lái)的樣本。當(dāng)緩存區(qū)足夠滿(mǎn)時(shí),聲卡將產(chǎn)生一其中斷。內(nèi)核聲卡驅(qū)動(dòng)爾后使用直接內(nèi)存(DMA)接見(jiàn)通道將樣本傳送到內(nèi)存中的應(yīng)用程序緩存區(qū)。近似地,關(guān)于回放,任何應(yīng)用程序使用DMA將自8基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux己的緩存區(qū)數(shù)據(jù)傳達(dá)到聲卡的硬件緩存區(qū)中。這樣硬件緩存區(qū)是環(huán)緩存。也就是說(shuō)當(dāng)數(shù)據(jù)到達(dá)緩存區(qū)尾端時(shí)將重新回到緩存區(qū)的初步地址。ALSA保護(hù)一個(gè)指針來(lái)指向硬件緩存以及應(yīng)用程序緩存區(qū)中數(shù)據(jù)操作的當(dāng)前地址。應(yīng)用程序緩存區(qū)的大小能夠經(jīng)過(guò)ALSA庫(kù)函數(shù)調(diào)用來(lái)控制。緩存區(qū)能夠很大,一次傳輸操作可能會(huì)以致不能接受的延緩,我們把它稱(chēng)為延時(shí)(latency)。為認(rèn)識(shí)決這個(gè)問(wèn)題,ALSA將緩存區(qū)拆分成一系列周期(period)(OSS/Free中叫片斷fragments)。ALSA以period為單元來(lái)傳達(dá)數(shù)據(jù)。一個(gè)周期(period)儲(chǔ)藏一些幀(frames)。每一幀包括時(shí)間上一個(gè)點(diǎn)所抓取的樣本。關(guān)于立體聲設(shè)備,一個(gè)幀會(huì)包括兩個(gè)信道上的樣本。其分解過(guò)程:一個(gè)緩存區(qū)分解成周期,爾后是幀,然后是樣本。左右信道信息被交替地儲(chǔ)藏在一個(gè)幀內(nèi)。這稱(chēng)為交叉(interleaved)模式。在非交叉模式中,一個(gè)信道的所有樣本數(shù)據(jù)儲(chǔ)藏在別的一個(gè)信道的數(shù)據(jù)此后。OverandUnderRun當(dāng)一個(gè)聲卡活動(dòng)時(shí),數(shù)據(jù)總是連續(xù)地在硬件緩存區(qū)和應(yīng)用程序緩存區(qū)間傳輸。但是也有例外。在錄音例子中,若是應(yīng)用程序讀取數(shù)據(jù)不夠快,循環(huán)緩存區(qū)將會(huì)被新的數(shù)據(jù)覆蓋。這種數(shù)據(jù)的扔掉被稱(chēng)為overrun.在回放例子中,若是應(yīng)用程序?qū)懭霐?shù)據(jù)到緩存區(qū)中的速度不夠快,緩存區(qū)將會(huì)"餓死"。這樣的錯(cuò)誤被稱(chēng)為"underrun"。在ALSA文檔中,有時(shí)將這兩種狀況統(tǒng)稱(chēng)為"XRUN"。合適地設(shè)計(jì)應(yīng)用程序能夠最小化XRUN并且能夠從中恢復(fù)過(guò)來(lái)。使用PCM的程序平時(shí)近似下面的偽代碼:打開(kāi)回放或錄音接口設(shè)置硬件參數(shù)(接見(jiàn)模式,數(shù)據(jù)格式,信道數(shù),采樣率,等等)while有數(shù)據(jù)要被辦理:讀PCM數(shù)據(jù)(錄音)或?qū)慞CM數(shù)據(jù)(回放)關(guān)閉接口此程序包包括四個(gè)部分:WAVParser是對(duì)WAV文件的解析和封裝,這里只針對(duì)StandardWAVFile(即標(biāo)準(zhǔn)WAV文件);SNDCommon是Playback和Record共同操作,如SetParams、ReadPCM和WritePCM等;Playback和Record就分別是播放錄音的主體了。3、錄放音原理以Playback為例:從WAV文件讀取PCM數(shù)據(jù),經(jīng)過(guò)I2S或AC97依次送到AudioCodec。需要注意的地方是對(duì)snd_pcm_hw_params_t的設(shè)置,特別要確定每次要送到AudioCodec的數(shù)據(jù)幀大小(peroid_size)。(1)從WAV文件的頭信息能夠解析出:sample_format、channelsnumber、sample_rate、sample_length,這些參數(shù)要經(jīng)過(guò)snd_pcm_hw_params_set_XXX()接口設(shè)置到snd_pcm_hw_params_t中。(2)接著我們要設(shè)置buffer_time和peroid_time。經(jīng)過(guò)snd_pcm_hw_params_get_buffer_time_max()接口能夠獲取該AudioCodec能夠支持的最大buffer_time,這里我們?cè)O(shè)置buffer_time=(MAX_BUFFER_TIME>500000)?500000:MAX_BUFFER_TIME;peroid_time=buffer_time/4。9基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux關(guān)于peroid的看法有這樣的描述:The“period”isatermthatcorrespondstoafragmentintheOSSworld.TheperioddefinesthesizeatwhichaPCMinterruptisgenerated.從基層驅(qū)動(dòng)看來(lái),應(yīng)該是PCMDMA單次傳達(dá)數(shù)據(jù)幀的大小。其實(shí)真實(shí)關(guān)注基層驅(qū)動(dòng)的話,它其實(shí)不是關(guān)心peroid_time,它關(guān)心的是peroid_size,這兩者有變換關(guān)系。見(jiàn)structsnd_pcm_hardware結(jié)構(gòu)體。(3)經(jīng)過(guò)snd_pcm_hw_params_get_period_size()獲取peroid_size,注意在ALSA中peroid_size是以frame為單位的。依照描述“Theconfiguredbufferandperiodsizesarestoredin“frames”intheruntime.1frame=channels*sample_size”.因此要對(duì)peroid_size進(jìn)行變換:chunk_bytes=peroid_size*sample_length/8。chunk_bytes就是我們單次從WAV讀PCM數(shù)據(jù)的大小。由以上playback過(guò)程能夠知道,capture的過(guò)程是近似的,可是一個(gè)對(duì)文件讀而另一個(gè)對(duì)文件寫(xiě)操作。當(dāng)打開(kāi)PCM設(shè)備時(shí)我們指定打開(kāi)模式為SND_PCM_STREAM_CPATURE。在主循環(huán)中,我們調(diào)用snd_pcm_readi從聲卡中讀取數(shù)據(jù),并把它們寫(xiě)入到標(biāo)準(zhǔn)輸出。同時(shí)也要注意frames和bytes的變換。SNDCommon中SNDWAV_ReadPcm和SNDWAV_WritePcm使用了snd_pcm_readi和snd_pcm_writei,其調(diào)用和Linux下的讀寫(xiě)系統(tǒng)調(diào)用近似。字母i表示辦理的幀是交叉(interleaved)的。ALSA中存在非交互模式的對(duì)應(yīng)的函數(shù)。Linux下的好多設(shè)備也支持mmap系統(tǒng)調(diào)用,這個(gè)調(diào)用將設(shè)備內(nèi)存照射到主內(nèi)存,這樣數(shù)據(jù)就可以用指針來(lái)保護(hù)。ALSA也運(yùn)行以mmap模式打開(kāi)一個(gè)PCM信道,這贊同有效的零拷貝(zerocopy)方式接見(jiàn)聲音數(shù)據(jù)。WAVParser是對(duì)WAV文件的解析和封裝,包括對(duì)文件頭讀寫(xiě)的操作和格式定義等。算法見(jiàn)程序源文件。音頻采集出來(lái)的結(jié)果:******************************sound.wav錄音****************************bynie@ubuntu:~/wav/alsa1$./lrecordsound.wavPlugPCM:RateconversionPCM(48000,sformat=S32_LE)Converter:libspeex(builtin)Protocolversion:10002Itssetupis:stream:CAPTUREaccess:RW_INTERLEAVEDformat:S16_LEsubformat:STDchannels:2rate:8000exactrate:8000(8000/1)msbits:16buffer_size:2730period_size:170period_time:21333tstamp_mode:NONEperiod_step:110基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinuxavail_min:170period_event:0start_threshold:1stop_threshold:2730silence_threshold:0silence_size:0boundary:178913280Slave:SoftvolumePCMControl:DigitalCaptureVolumemin_dB:-30max_dB:30resolution:121Itssetupis:stream:CAPTUREaccess:MMAP_INTERLEAVEDformat:S32_LEsubformat:STDchannels:2rate:48000exactrate:48000(48000/1)msbits:32buffer_size:16384period_size:1024period_time:21333tstamp_mode:NONEperiod_step:1avail_min:1024period_event:0start_threshold:6stop_threshold:16384silence_threshold:0silence_size:0boundary:1073741824Slave:DirectSnoopPCMItssetupis:stream:CAPTUREaccess:MMAP_INTERLEAVEDformat:S32_LEsubformat:STDchannels:2rate:48000exactrate:48000(48000/1)msbits:32buffer_size:1638411基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinuxperiod_size:1024period_time:21333tstamp_mode:NONEperiod_step:1avail_min:1024period_event:0start_threshold:6stop_threshold:16384silence_threshold:0silence_size:0boundary:1073741824HardwarePCMcard0'HDASIS966'device0subdevice0Itssetupis:stream:CAPTUREaccess:MMAP_INTERLEAVEDformat:S32_LEsubformat:STDchannels:2rate:48000exactrate:48000(48000/1)msbits:32buffer_size:16384period_size:1024period_time:21333tstamp_mode:ENABLEperiod_step:1avail_min:1024period_event:0start_threshold:1stop_threshold:1073741824silence_threshold:0silence_size:0boundary:1073741824appl_ptr:0hw_ptr:1054+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/n/nFileMagic:[RIFF]/nFileLength:[480036]/nFileType:[WAVE]/n/nFmtMagic:[fmt]/nFmtSize:[16]/nFmtFormat:[PCM]/nFmtChannels:[2]/nFmtSample_rate:[8000](HZ)/nFmtBytes_p_second:[32000]/nFmtBlocks_align:[4]/nFmtSample_length:[16]/n/nChunkType:[data]/nChunkLength:[480000]/n/n+++++++++++++++++++++++++++++++++++++++++++++12基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux******************************sound.wav放音****************************bynie@ubuntu:~/wav/alsa1$./lplaysound.wavPlugPCM:RateconversionPCM(48000,sformat=S32_LE)Converter:libspeex(builtin)Protocolversion:10002Itssetupis:stream:PLAYBACKaccess:RW_INTERLEAVEDformat:S16_LEsubformat:STDchannels:2rate:8000exactrate:8000(8000/1)msbits:16buffer_size:2730period_size:170period_time:21333tstamp_mode:NONEperiod_step:1avail_min:170period_event:0start_threshold:1stop_threshold:2730silence_threshold:0silence_size:0boundary:178913280Slave:SoftvolumePCMControl:PCMPlaybackVolumemin_dB:-51max_dB:0resolution:256Itssetupis:stream:PLAYBACKaccess:MMAP_INTERLEAVEDformat:S32_LEsubformat:STDchannels:2rate:48000exactrate:48000(48000/1)msbits:32buffer_size:16384period_size:1024period_time:2133313基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinuxtstamp_mode:NONEperiod_step:1avail_min:1024period_event:0start_threshold:6stop_threshold:16384silence_threshold:0silence_size:0boundary:1073741824Slave:DirectStreamMixingPCMItssetupis:stream:PLAYBACKaccess:MMAP_INTERLEAVEDformat:S32_LEsubformat:STDchannels:2rate:48000exactrate:48000(48000/1)msbits:32buffer_size:16384period_size:1024period_time:21333tstamp_mode:NONEperiod_step:1avail_min:1024period_event:0start_threshold:6stop_threshold:16384silence_threshold:0silence_size:0boundary:1073741824HardwarePCMcard0'HDASIS966'device0subdevice0Itssetupis:stream:PLAYBACKaccess:MMAP_INTERLEAVEDformat:S32_LEsubformat:STDchannels:2rate:48000exactrate:48000(48000/1)msbits:32buffer_size:16384period_size:1024period_time:2133314基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinuxtstamp_mode:ENABLEperiod_step:1avail_min:1024period_event:0start_threshold:1stop_threshold:1073741824silence_threshold:0silence_size:1073741824boundary:1073741824appl_ptr:0hw_ptr:0+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/n/nFileMagic:[RIFF]/nFileLength:[480036]/nFileType:[WAVE]/n/nFmtMagic:[fmt]/nFmtSize:[16]/nFmtFormat:[PCM]/nFmtChannels:[2]/nFmtSample_rate:[8000](HZ)/nFmtBytes_p_second:[32000]/nFmtBlocks_align:[4]/nFmtSample_length:[16]/n/nChunkType:[data]/nChunkLength:[480000]/n/n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/15基于linux下的音視頻采集與傳輸BasedontheacquisitionandtransmissionofaudioandvideounderlinuxSocket文件傳輸1、Socket基礎(chǔ)介紹(1)什么是Socket?所謂socket平時(shí)也稱(chēng)作"套接字",應(yīng)用程序平時(shí)經(jīng)過(guò)"套接字"向網(wǎng)絡(luò)發(fā)出央求也許應(yīng)答網(wǎng)絡(luò)央求。以J2SDK-1.3為例,Socket和ServerSocket類(lèi)庫(kù)位于包中。ServerSocket用于服務(wù)器端,Socket是建立網(wǎng)絡(luò)連接時(shí)使用的。在連接成功時(shí),應(yīng)用程序兩端都會(huì)產(chǎn)生一個(gè)Socket實(shí)例,操作這個(gè)實(shí)例,達(dá)成所需的會(huì)話。關(guān)于一個(gè)網(wǎng)絡(luò)連接來(lái)說(shuō),套接字是相同的,并沒(méi)有差別,不由于在服務(wù)器端或在客戶(hù)端而產(chǎn)生不一樣級(jí)別。無(wú)論是Socket還是ServerSocket它們的工作都是經(jīng)過(guò)SocketImpl類(lèi)及其子類(lèi)達(dá)成的。(2)Socket連接過(guò)程依照連接啟動(dòng)的方式以及當(dāng)?shù)靥捉幼忠B接的目標(biāo),套接字之間的連接過(guò)程能夠分為三個(gè)步驟:服務(wù)器監(jiān)聽(tīng),客戶(hù)端央求,連接確認(rèn)。服務(wù)器監(jiān)聽(tīng):是服務(wù)器端套接字其實(shí)不定位詳盡的客戶(hù)端套接字,而是處于等待連接的狀態(tài),實(shí)時(shí)監(jiān)控網(wǎng)絡(luò)狀態(tài)??蛻?hù)端央求:是指由客戶(hù)端的套接字提出連接央求,要連接的目標(biāo)是服務(wù)器端的套接字。為此,客戶(hù)端的套接字必定第一描述它要連接的服務(wù)器的套接字,指出服務(wù)器端套接字的地址和端口號(hào),爾后就向服務(wù)器端套接字提出連接央求。連接確認(rèn):是指當(dāng)服務(wù)器端套接字監(jiān)聽(tīng)到也許說(shuō)接收到客戶(hù)端套接字的連接央求,它就響應(yīng)客戶(hù)端套接字的央求,建立一個(gè)新的線程,把服務(wù)器端套接字的描述發(fā)給客戶(hù)端,一旦客戶(hù)端確認(rèn)了此描述,連接就建立好了。而服務(wù)器端套接字連續(xù)處于監(jiān)聽(tīng)狀態(tài),連續(xù)接收其他客戶(hù)端套接字的連接央求。(3)常用的Socket種類(lèi)有兩種:流式Socket(SOCK_STREAM)和數(shù)據(jù)報(bào)式Socket(SOCK_DGRAM)。流式是一種面向連接的Socket,針關(guān)于面向連接的TCP服務(wù)應(yīng)用;數(shù)據(jù)報(bào)式Socket是一種無(wú)連接的Socket,對(duì)應(yīng)于無(wú)連接的UDP服務(wù)應(yīng)用。Socket為了建立Socket,程序能夠調(diào)用Socket函數(shù),該函數(shù)返回一個(gè)近似于文件描述符的句柄。socket函數(shù)原型為:intsocket(intdomain,inttype,intprotocol);domain指明所使用的協(xié)議族,平時(shí)為PF_INET,(其與addrinfo里的AF_INET在現(xiàn)在看來(lái)是相同的??墒菤v史上人們?cè)鴺?gòu)想將AF(地址家族addressfamily)與PF(protocolfamily協(xié)議家族)分開(kāi),但實(shí)質(zhì)上這種區(qū)分并未真實(shí)實(shí)行,因此現(xiàn)在AF_INET和PF_INET擁有相同的意義。其中AF_INET是基于IPv4而PF_INET基于IPv6)表示互聯(lián)網(wǎng)協(xié)議族(TCP/IP協(xié)議族);type參數(shù)指定socket的種類(lèi):SOCK_STREAM或SOCK_DGRAM,Socket接口還定義了原始Socket(SOCK_RAW),贊同程序使用低層協(xié)議;protocol平時(shí)賦值0。Socket()調(diào)用返回一個(gè)整型socket描述符,你能夠在后邊的調(diào)用使用它。Socket描16基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux述符是一個(gè)指向內(nèi)部數(shù)據(jù)結(jié)構(gòu)的指針,它指向描述符表入口。調(diào)用Socket函數(shù)時(shí),socket執(zhí)行體將建立一個(gè)Socket,實(shí)質(zhì)上"建立一個(gè)Socket"意味著為一個(gè)Socket數(shù)據(jù)結(jié)構(gòu)分配儲(chǔ)藏空間。Socket執(zhí)行體為你管理描述符表。兩個(gè)網(wǎng)絡(luò)程序之間的一個(gè)網(wǎng)絡(luò)連接包括五種信息:通信協(xié)議、當(dāng)?shù)貐f(xié)議地址、當(dāng)?shù)刂鳈C(jī)端口、遠(yuǎn)端主機(jī)地址和遠(yuǎn)端協(xié)議端口。Socket數(shù)據(jù)結(jié)構(gòu)中包括這五種信息。socket在測(cè)量軟件中的使用也很廣泛。2、Socket傳輸程序設(shè)計(jì)服務(wù)器狀態(tài)機(jī)的設(shè)計(jì)(Server)主進(jìn)度只有一個(gè)狀態(tài),就是等待客戶(hù)機(jī)的央求,爾后創(chuàng)辦子進(jìn)度為其服務(wù)。因此所謂服務(wù)器狀態(tài)機(jī)就是這個(gè)子進(jìn)度的。狀態(tài):悠閑狀態(tài):等待客戶(hù)機(jī)的命令;文件接收狀態(tài):正在接收文件內(nèi)容并寫(xiě)入文件中;退出狀態(tài):進(jìn)度馬上死亡,任務(wù)失敗或達(dá)成。事件(網(wǎng)絡(luò)報(bào)文或網(wǎng)絡(luò)連接狀態(tài)):命令:央求接收字串并要求馬上接收;F命令:央求接收文件;D命令:數(shù)據(jù)到達(dá),請(qǐng)接收;E命令:客戶(hù)機(jī)央求結(jié)束任務(wù);數(shù)據(jù)字節(jié)讀取完:需要讀取的數(shù)據(jù)長(zhǎng)度已經(jīng)減少為0,表示已經(jīng)達(dá)成本次傳輸;連接流產(chǎn):故障出現(xiàn),請(qǐng)退出。(2)客戶(hù)機(jī)狀態(tài)機(jī)設(shè)計(jì)(Client)客戶(hù)機(jī)進(jìn)度啟動(dòng)就進(jìn)入央求服務(wù)器狀態(tài),等待服務(wù)器的央求回答,如連接建立成功,則進(jìn)入傳輸狀態(tài)。由于設(shè)計(jì)的應(yīng)用是非并發(fā)的,也就是說(shuō)傳輸文字或傳輸文件,能夠是好多次進(jìn)行,但是每次之間是次序進(jìn)行的??蛻?hù)機(jī)接收操作者的鍵盤(pán)命令也是次序的。因此整個(gè)狀態(tài)只有一個(gè)狀態(tài)。狀態(tài):連接已經(jīng)建立狀態(tài):只有一個(gè)狀態(tài)的話,怎么命名都是對(duì)的,但是為了吻合實(shí)質(zhì)意思還是選擇這個(gè)名稱(chēng)好些;結(jié)束狀態(tài):這是一個(gè)虛假狀態(tài)。程序都結(jié)束了,這個(gè)狀態(tài)就沒(méi)心義。事件(鍵盤(pán)命令):A命令:鍵盤(pán)輸入的A+要傳輸?shù)奈淖肿执籉命令:鍵盤(pán)輸入的F+要傳輸?shù)奈募?;E命令:鍵盤(pán)輸入的E。表示退出本進(jìn)度;連接流產(chǎn):故障出現(xiàn),退出;17基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux(3)客戶(hù)機(jī)主要模塊和流程以下:1、建立和服務(wù)器的連接;2、等待鍵盤(pán)輸入命令;3、辦理命令,選擇以下之一辦理(switch-case)A命令-文字傳輸;F命令-文件傳輸;E命令-結(jié)束任務(wù);網(wǎng)絡(luò)故障;4、轉(zhuǎn)2。(4)服務(wù)器主要模塊和流程以下:1、初始化當(dāng)?shù)剡B接接口(服務(wù)端口號(hào)的設(shè)置),等待客戶(hù)機(jī)的連接建立央求;2、獲取一個(gè)央求,并創(chuàng)辦一個(gè)子進(jìn)度(子服務(wù)器);子進(jìn)度:等待網(wǎng)絡(luò)事件(報(bào)文)的到來(lái);子進(jìn)度:辦理事件,選擇以下之一辦理(switch-case)A報(bào)文-文字報(bào)文;F報(bào)文-文件名稱(chēng)報(bào)文;D報(bào)文-文件數(shù)據(jù)報(bào)文;E報(bào)文-結(jié)束任務(wù)報(bào)文連接流產(chǎn)事件子進(jìn)度:轉(zhuǎn)a)3、轉(zhuǎn)2。18基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux(5)細(xì)流程設(shè)計(jì)其一:從命令行參數(shù)argv獲取服務(wù)器的IP地址和服務(wù)器端口號(hào)碼;試圖和服務(wù)器建立連接,如不能功則提示網(wǎng)絡(luò)故障并結(jié)束;gethostbyname:判斷IP地址合法性等;②socket獲取當(dāng)?shù)靥捉幼?;③connect用當(dāng)?shù)靥捉幼秩ピ噲D和服務(wù)器建立連接。進(jìn)入連接建立狀態(tài)(CurrentState=CLI_CONN_OK_STATE);把TCP連接的套接字描述字和鍵盤(pán)的描述字組成事件排列,等待事件的到來(lái);經(jīng)過(guò)select和ReadKeyString獲取鍵盤(pán)事件;//回車(chē)作為命令字串的結(jié)束FD_ISSET解析是鍵盤(pán)事件還是網(wǎng)絡(luò)連接事件,網(wǎng)絡(luò)事件則認(rèn)為故障了;②如是鍵盤(pán)事件,再用ReadKeyString從鍵盤(pán)讀取字串并解析出命令來(lái);解析鍵盤(pán)命令(事件):A命令:②F命令:E命令:④連接流產(chǎn):解析鍵盤(pán)命令(事件):A命令:a)封裝為A-PDU;b)用send把報(bào)文送到服務(wù)器;c)等待發(fā)送成功或失??;d)如是成功,則提示“成功”并轉(zhuǎn)4;e)如是失敗,則提示“網(wǎng)絡(luò)故障”并轉(zhuǎn)4;命令:a)獲取文件名,并判斷文件可否存在,如不存在則報(bào)告錯(cuò)誤,轉(zhuǎn)4;b)封裝F-PDU;c)用send把報(bào)文送到服務(wù)器;d)等待發(fā)送成功或故障;e)如是成功,則i)調(diào)用文件發(fā)送子程序;(1)讀取文件并封裝為D-PDU;(2)用send把D-PDU發(fā)送到服務(wù)器;(3)文件完了,則推出子程序,否則轉(zhuǎn)(1)ii)如是子程序返回成功,則提示“成功”并轉(zhuǎn)4;iii)如是子程序返回失敗,則提示“網(wǎng)絡(luò)故障,失敗”并轉(zhuǎn)4;命令:a)結(jié)束本進(jìn)度,提示“任務(wù)達(dá)成!”;連接流產(chǎn):結(jié)束本進(jìn)度,提示“網(wǎng)絡(luò)故障,任務(wù)失??!”;19基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux其二:狀態(tài)設(shè)置為SER_FREE_STATE;用select建立網(wǎng)絡(luò)連接的事件隊(duì)列,并等待TCP連接的報(bào)文到來(lái);有報(bào)文到來(lái):先讀取一個(gè)字節(jié),這個(gè)字節(jié)就是報(bào)文種類(lèi);讀取報(bào)文數(shù)據(jù)長(zhǎng)度;爾后解析報(bào)文種類(lèi),即所謂事件種類(lèi);解析事件:選擇以下之一執(zhí)行(switch-case);報(bào)文事件:F報(bào)文事件:D報(bào)文事件:報(bào)文事件:連接故障事件:不明事件:轉(zhuǎn)到2。解析事件的解析解析事件:選擇以下之一執(zhí)行(switch-case);報(bào)文事件:a)按報(bào)文長(zhǎng)度讀取后續(xù)字節(jié),讀完為止;b)正確,則在顯示器上打??;c)故障,則退出進(jìn)度。報(bào)文事件:a)按報(bào)文長(zhǎng)度讀取后續(xù)字節(jié),讀完為止;1)正確,則獲取文件名稱(chēng)和文件長(zhǎng)度;i)創(chuàng)辦文件,準(zhǔn)備接收文件數(shù)據(jù);ii)狀態(tài)轉(zhuǎn)移為SER_FILE_RECV_STATE;2)故障,則退出進(jìn)度。報(bào)文事件:a)讀取報(bào)文數(shù)據(jù),讀完此次報(bào)文數(shù)據(jù)為止;1)正確,數(shù)據(jù)寫(xiě)入接收文件中;2)故障,則退出進(jìn)度。b)減少待接收的字節(jié)數(shù),判斷可否已經(jīng)接收完了,如完了,則1)狀態(tài)轉(zhuǎn)移為SER_FREE_STATE;2)關(guān)閉接收文件;報(bào)文事件:a)正常結(jié)束本進(jìn)度。連接故障事件:a)退出本進(jìn)度。不明事件:提示:接收到不明事件。(6)服務(wù)器客戶(hù)機(jī)的部分定義服務(wù)器:#defineSER_FREE_STATE0//悠閑狀態(tài)#defineSER_FILE_RECV_STATE1//文件接收狀態(tài)#defineSER_QUIT_STATE2//馬上退出狀態(tài)20基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux#defineSER_KEY_A_COMMAND1//A命令#defineSER_KEY_F_COMMAND2//F命令#defineSER_KEY_D_COMMAND3//D命令#defineSER_DATA_OVER4//數(shù)據(jù)字節(jié)讀取完#defineSER_CONN_ABORT5//連接流產(chǎn)#defineSER_CLIENT_OVER6//E命令,客戶(hù)機(jī)關(guān)閉客戶(hù)機(jī):#defineCLI_CONN_OK_STATE0//連接建立#defineCLI_END_STATE1//客戶(hù)機(jī)結(jié)束狀態(tài)#defineCLI_KEY_A_COMMAND1//A命令#defineCLI_KEY_F_COMMAND2//F命令#defineCLI_KEY_E_COMMAND3//E命令#defineCLI_CONN_ABORT4//連接流產(chǎn)#defineCLI_ERROR_COMMAND9//鍵盤(pán)命令錯(cuò)誤(7)相關(guān)Socket的調(diào)用:系統(tǒng)調(diào)用功能使用者Socket(format,type,獲取一個(gè)SOCKET客戶(hù)、服務(wù)者protocol)bind(sd,address,length)SOCKET和address綁服務(wù)者定listen(sd,qlength)設(shè)置傾聽(tīng)服務(wù)者accept(sd,address,接受SOCKET央求服務(wù)者addrlen)connect(sd,address,央求一個(gè)SOCKET連客戶(hù)length)接send(sd,msg,length,向SOCKET發(fā)送數(shù)據(jù)客戶(hù)、服務(wù)者flags)recv(sd,buf,length,從SOCKET接收數(shù)據(jù)客戶(hù)、服務(wù)者flags)write(sd,buf,len)向SOCKET寫(xiě)數(shù)據(jù)客戶(hù)、服務(wù)者read(sd,buf,len)從SOCKET讀數(shù)據(jù)客戶(hù)、服務(wù)者shutdown(sd,mode)關(guān)閉SOCKET客戶(hù)、服務(wù)者close(sd)釋放SOCKET客戶(hù)、服務(wù)者21基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux總結(jié):此次軟件項(xiàng)目的設(shè)計(jì)我們所做的基于linux的音視頻采集及傳輸在重重波折中終于完成,想想這幾周,我們從最開(kāi)始的linux的學(xué)習(xí),到程序設(shè)計(jì),編碼,分步測(cè)試,以及最后的綜合測(cè)試,誠(chéng)然項(xiàng)目不大,技術(shù)含量也不高,卻實(shí)在讓我們學(xué)到了很多東西。最初,隊(duì)長(zhǎng)關(guān)于linux的講解,讓我們對(duì)這個(gè)系統(tǒng)有了更深的認(rèn)識(shí),恰巧我們?cè)谕ㄐ跑浖O(shè)計(jì)中關(guān)于linux有過(guò)相關(guān)接觸。接觸到了基本的平臺(tái),就是更深層的編碼了,音視頻的采集在隊(duì)長(zhǎng)的努力下得以基本解決,而socket傳輸部分也獲取了相應(yīng)的解決。剛開(kāi)始的時(shí)候我們無(wú)法找到接收到的文件,經(jīng)過(guò)研究,客服技術(shù)上的困難,最后得以解決。但是我們還是有一些還沒(méi)有解決的問(wèn)題,比方視頻采集現(xiàn)在沒(méi)有圖像保存那么能夠加入圖像保存的功能,音頻只有WAV格式,能夠改進(jìn)加入多種格式,不損害音質(zhì)的狀況下減少數(shù)據(jù)量那么socket能夠雙向傳輸,傳輸文件時(shí)能夠選擇路徑,經(jīng)過(guò)此次項(xiàng)目設(shè)計(jì),我們學(xué)會(huì)了好多,也有好多值得我們思慮的東西,關(guān)于人性的認(rèn)知在項(xiàng)目中也是有著不能或缺的作用,不一樣性格的人從事不一樣的事情有助于整個(gè)項(xiàng)目的快速進(jìn)展。此次大家也合作的很快樂(lè),希望著下次的連續(xù)合作。22基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux附錄:視頻采集主要程序代碼:videodevice.h#ifndefVIDEODEVICE_H#defineVIDEODEVICE_H#include<string.h>#include<stdlib.h>#include<errno.h>#include<fcntl.h>#include<sys/ioctl.h>#include<sys/mman.h>#include<asm/types.h>#include<linux/videodev2.h>#include<QString>#include<QObject>#defineCLEAR(x)memset(&(x),0,sizeof(x))classVideoDevice:publicQObject{Q_OBJECTpublic:VideoDevice(QStringdev_name);//VideoDevice();intopen_device();intclose_device();intinit_device();intstart_capturing();intstop_capturing();intuninit_device();intget_frame(void**,size_t*);intunget_frame();private:intinit_mmap();structbuffer{void*start;size_tlength;};QStringdev_name;intfd;buffer*buffers;unsignedintn_buffers;intindex;signals:23基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinuxvoiddisplay_error(QString);};#endifprocessImage.h#ifndefPROCESSIMAGE_H#definePROCESSIMAGE_H#include<QtGui>#include"videodevice.h"classProcessImage:publicQWidget{Q_OBJECTpublic:ProcessImage(QWidget*parent=0);~ProcessImage();private:QPainter*painter;QLabel*label;QImage*frame;//QPixmap*frame;QTimer*timer;intrs;uchar*pp;uchar*p;unsignedintlen;intconvert_yuv_to_rgb_pixel(inty,intu,intv);intconvert_yuv_to_rgb_buffer(unsignedchar*yuv,unsignedchar*rgb,unsignedintwidth,unsignedintheight);VideoDevice*vd;privateslots:voidpaintEvent(QPaintEvent*);voiddisplay_error(QStringerr);};#endifvideodevice.cpp#include"videodevice.h"VideoDevice::VideoDevice(QStringdev_name){this->dev_name=dev_name;this->fd=-1;this->buffers=NULL;this->n_buffers=0;this->index=-1;}intVideoDevice::open_device()24基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux{fd=open(dev_name.toStdString().c_str(),O_RDWR/*|O_NONBLOCK*/,0);fd=open(dev_name.toStdString().c_str(),O_RDWR|O_NONBLOCK,0);if(-1==fd){emitdisplay_error(tr("open:%1").arg(QString(strerror(errno))));return-1;}return0;}intVideoDevice::close_device(){if(-1==close(fd)){emitdisplay_error(tr("close:%1").arg(QString(strerror(errno))));return-1;}return0;}intVideoDevice::init_device(){v4l2_capabilitycap;v4l2_cropcapcropcap;v4l2_cropcrop;v4l2_formatfmt;if(-1==ioctl(fd,VIDIOC_QUERYCAP,&cap)){if(EINVAL==errno){emitdisplay_error(tr("%1isnoV4l2device").arg(dev_name));}else{emitdisplay_error(tr("VIDIOC_QUERYCAP:%1").arg(QString(strerror(errno))));}return-1;}if(!(cap.capabilities&V4L2_CAP_VIDEO_CAPTURE)){emitdisplay_error(tr("%1isnovideocapturedevice").arg(dev_name));return-1;}25基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinuxif(!(cap.capabilities&V4L2_CAP_STREAMING)){emitdisplay_error(tr("%1doesnotsupportstreamingi/o").arg(dev_name));return-1;}CLEAR(cropcap);cropcap.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;if(0==ioctl(fd,VIDIOC_CROPCAP,&cropcap)){CLEAR(crop);crop.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;crop.c=cropcap.defrect;if(-1==ioctl(fd,VIDIOC_S_CROP,&crop)){if(EINVAL==errno){//emitdisplay_error(tr("VIDIOC_S_CROPnotsupported"));}else{emitdisplay_error(tr("VIDIOC_S_CROP:%1").arg(QString(strerror(errno))));return-1;}}}else{emitdisplay_error(tr("VIDIOC_CROPCAP:%1").arg(QString(strerror(errno))));return-1;}CLEAR(fmt);fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;fmt.fmt.pix.width=640;fmt.fmt.pix.height=480;fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV;fmt.fmt.pix.field=V4L2_FIELD_INTERLACED;if(-1==ioctl(fd,VIDIOC_S_FMT,&fmt)){emitdisplay_error(tr("VIDIOC_S_FMT").arg(QString(strerror(errno))));return-1;}if(-1==init_mmap())26基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinux{return-1;}return0;}intVideoDevice::init_mmap()VIDIOC_REQBUFS{v4l2_requestbuffersreq;CLEAR(req);req.count=4;req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;req.memory=V4L2_MEMORY_MMAP;if(-1==ioctl(fd,VIDIOC_REQBUFS,&req)){if(EINVAL==errno){emitdisplay_error(tr("%1doesnotsupportmemorymapping").arg(dev_name));return-1;}else{emitdisplay_error(tr("VIDIOC_REQBUFS%1").arg(QString(strerror(errno))));return-1;}}if(req.count<2){emitdisplay_error(tr("Insufficientbuffermemoryon%1").arg(dev_name));return-1;}buffers=(buffer*)calloc(req.count,sizeof(*buffers));if(!buffers){emitdisplay_error(tr("outofmemory"));return-1;}for(n_buffers=0;n_buffers<req.count;++n_buffers){v4l2_bufferbuf;v4l2_bufferCLEAR(buf);27基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinuxbuf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory=V4L2_MEMORY_MMAP;buf.index=n_buffers;if(-1==ioctl(fd,VIDIOC_QUERYBUF,&buf)){emitdisplay_error(tr("VIDIOC_QUERYBUF:%1").arg(QString(strerror(errno))));return-1;}buffers[n_buffers].length=buf.length;buffers[n_buffers].start=mmap(NULL,//startanywheremmap用法buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,buf.m.offset);if(MAP_FAILED==buffers[n_buffers].start){emitdisplay_error(tr("mmap%1").arg(QString(strerror(errno))));return-1;}}return0;}intVideoDevice::start_capturing(){unsignedinti;for(i=0;i<n_buffers;++i){v4l2_bufferbuf;CLEAR(buf);buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory=V4L2_MEMORY_MMAP;buf.index=i;fprintf(stderr,"n_buffers:%d\n",i);if(-1==ioctl(fd,VIDIOC_QBUF,&buf)){emitdisplay_error(tr("VIDIOC_QBUF:%1").arg(QString(strerror(errno))));return-1;}}v4l2_buf_typetype;v4l2_buf_type28基于linux下的音視頻采集與傳輸Basedontheacquisitionandtransmissionofaudioandvideounderlinuxtype=V4L2_BUF_TYPE_VIDEO_CAPTURE;if(-1==ioctl(fd,VIDIOC_STREAMON,&type)){emitdisplay_error(tr("VIDIOC_STREAMON:%1").arg(QString(strerror(errno)))

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論