本發(fā)明涉及一種基于智能機頂盒的全景視頻播放器,屬于計算機圖形學(xué)和Android多媒體
技術(shù)領(lǐng)域:
。
背景技術(shù):
:全景視頻,又稱360度視頻,如圖1所示,它將靜態(tài)的全景圖片轉(zhuǎn)化為動態(tài)的視頻圖像,全景視頻可以在拍攝角度左右上下360度的任意觀看動態(tài)視頻,使人有一種真正意義上身臨其境的感覺,而不受時間、空間和地域的限制。目前全景視頻主要應(yīng)用在虛擬現(xiàn)實領(lǐng)域,在智能機頂盒上或智能電視上還沒有應(yīng)用,然而在電視上觀看全景視頻相比在手機上用虛擬現(xiàn)實眼鏡看,雖然少了身臨其境的感覺,但卻具有一些獨特的優(yōu)勢,比如不用戴笨重的虛擬現(xiàn)實眼鏡、屏幕更大、看到的細節(jié)更豐富、同時可供多人觀看等。Blender是一款開源的跨平臺的動畫制作軟件,可以進行建模、制作動畫、材質(zhì)、視頻剪輯的軟件,和3dMax的專業(yè)的三維動畫渲染軟件相比,Blender非常小巧,但是Blender的功能已經(jīng)十分強大,基本的渲染工作已經(jīng)足夠滿足三維動畫制作愛好者的需求。本設(shè)計的播放器中所使用的3D球體模型將使用Blender繪制。智能機頂盒,一般指裝有Android操作系統(tǒng)的機頂盒,其上可以安裝第三方安卓應(yīng)用程序。連接上電視,可以實現(xiàn)Android系統(tǒng)豐富的功能,如聽音樂、看視頻、上網(wǎng)、玩游戲等。帶陀螺儀的遙控器,陀螺儀是一種角速度傳感器,它可以對轉(zhuǎn)動、偏轉(zhuǎn)的動作做很好的測量,這樣就可以精確分析判斷出使用者的實際動作,然后實現(xiàn)相應(yīng)的操作。為了方便和用戶的交互,目前許多廠商的智能電視遙控器都內(nèi)置了陀螺儀,同時市場上也有許多內(nèi)置陀螺儀的萬能遙控器,能支持各種智能機頂盒、智能電視等。目前全景視頻主要用于虛擬現(xiàn)實領(lǐng)域,在智能手機上通過虛擬現(xiàn)實眼鏡觀看。這種方式雖然能帶來身臨其境的感覺,但卻存在許多缺陷,比如需戴上虛擬現(xiàn)實頭盔,長時間觀看容易疲勞、眩暈;另外戴上頭盔后用戶就不能再觸摸手機,存在交互難的問題。技術(shù)實現(xiàn)要素:本發(fā)明目的在于:克服現(xiàn)有技術(shù)的不足,將全景視頻應(yīng)用到電視上,而不僅限于智能手機,省去手機端用虛擬現(xiàn)實眼鏡觀看全景視頻的額外負擔。本發(fā)明提供一種通過智能機頂盒在(智能)電視上觀看全景視頻的解決方案,將播放器安裝在智能機頂盒或智能電視上,然后使用帶陀螺儀的遙控器控制全景視頻的移動。通過這種方式觀看全景視頻不用佩戴虛擬現(xiàn)實頭盔,節(jié)省了成本,并且具有操作輕便、適合多人觀看等優(yōu)點。本發(fā)明的目的通過以下技術(shù)方案來實現(xiàn):由于全景視頻是全方位角度拍攝的,因此可以將全景視頻的每一幀圖像作為OpenGL的紋理映射到一個球面上,再將該球面進行矩陣變換投影到屏幕上。然后使用帶陀螺儀的遙控器傳入角度信息控制全景視頻的移動。所述將全景視頻流的每一幀圖像作為OpenGL的紋理映射在一個球面上,再將該球面進行矩陣變換投影到屏幕上的具體實現(xiàn)如下:(1)將MediaPlayer和SurfaceView配合使用形成視頻流;(2)用SurfaceTexture接收視頻流,并將視頻流中的每一幀圖像作為紋理映射到球面;(3)將球面的頂點位置坐標進行矩陣變換,得到最終顯示在屏幕上的頂點位置坐標。使用帶陀螺儀的遙控器傳入角度信息控制全景視頻的移動的具體實現(xiàn)如下:(1)把陀螺儀遙控器傳入的角度信息轉(zhuǎn)換成矩陣的形式:(2)將此矩陣作為旋轉(zhuǎn)矩陣參與到矩陣變換中,實時改變最終的變換矩陣;(3)由最終的變換矩陣控制球體的投影,實現(xiàn)視頻畫面的實時移動。本發(fā)明具體的方案描述如下:(1)首先要能播放視頻流,這里使用android中的MediaPlayer類,MediaPlayer類主要用于播放音頻,要播放視頻,還需和Surface類配合使用。但是Surface接收到視頻流后會直接在屏幕上顯示,不方便對視頻進行相關(guān)處理,這里要用到另一個類SurfaceTexture,它接收視頻流后不需要直接顯示在屏幕上,它可以從視頻流中獲取圖像幀作為OpenGLES的紋理,它的updateTexImage()方法可以將紋理內(nèi)容更新為視頻流中最近的圖片,經(jīng)過一番處理后,再將SurfaceTexture和Surface進行關(guān)聯(lián),最后顯示在屏幕上。(2)獲得圖像幀作為紋理后,將紋理與OpenGL渲染管線中的TextureUnit(紋理單元)進行綁定關(guān)聯(lián)。TextureUnit可以讀取紋理并傳遞給shader(著色器),這樣紋理才能在屏幕上顯示出來。(3)使用三維建模軟件Blender創(chuàng)建一個球體,如圖2所示。建模完成的3D球體模型最終形成的是一個obj格式的文件,當在程序中加載這個模型文件時,加載的是一堆數(shù)據(jù),這些數(shù)據(jù)主要包含了模型的頂點信息和紋理信息,其格式如下:v1.950948-17.654135-2.919814……vt0.6546350.062500……vn-0.0624000.7715000.633200……f214/209/198229/224/198228/225/198……其中的省略號表示下面的數(shù)據(jù)為若干行相同的數(shù)據(jù)類型構(gòu)成的數(shù)據(jù),主要區(qū)別為數(shù)據(jù)不同,這里所指的數(shù)據(jù)類型指的是每一行最前面的字母?!皏”開頭表示為Vertex,也就是頂點坐標,后面三個用空格隔開的數(shù)據(jù)為頂點的X、Y、Z坐標;“vt”開頭表示為VertexTexture,就是紋理坐標,數(shù)據(jù)分別為S、T坐標;“vn”開頭表示為VertexNormal,數(shù)據(jù)為頂點的法向量在每個坐標軸上的分量;“f”開頭表示為Face,也就是一個面,上文提到OpenGLES中每一個面由3個頂點構(gòu)成,因此這一行數(shù)據(jù)由三組數(shù)據(jù)構(gòu)成,用空格分開,每一組數(shù)據(jù)包含一個頂點的信息,里面的數(shù)據(jù)表示為數(shù)據(jù)索引的行數(shù),例如:f214/209/214229/224/229228/225/228表示為構(gòu)成一個面的三個頂點的頂點坐標來自表示頂點坐標的數(shù)據(jù)行(“v”開頭)中的214、229和228行,紋理坐標來自表示紋理坐標數(shù)據(jù)行(“vt”開頭)的209、224和225行,頂點法向量坐標來自表示法向量坐標數(shù)據(jù)行(“vn”開頭)的241、229和228行。讀取頂點坐標和紋理坐標時,就需要使用面的索引信息,然后去存放頂點坐標和紋理坐標的數(shù)據(jù)中重新找到坐標并進行存儲,最后送入OpenGLES渲染管線。(4)將二維紋理映射到球面。在使用OpenGLES的紋理貼圖功能時,頂點著色器(VertexShader)送入渲染管線的頂點屬性主要包括頂點位置坐標和紋理坐標,其中,位置坐標一般是三維坐標(X,Y,Z),紋理坐標為二維坐標(S,T)。在OpenGLES中,三維坐標使用的是右手坐標系,如附圖3的a所示,紋理坐標方向為水平向右為S,垂直向下為T,如附圖3的b所示。當要為附圖3的a中的三角形貼紋理時,先把三個頂點的(X,Y,Z)和(S,T)送入頂點著色器和片元著色器,再把附圖3的b中整個圖片作為紋理送入紋理單元,OpenGLES渲染管線會把附圖3的b中內(nèi)的三角形紋理映射在附圖3的a中的三角形內(nèi)。若兩個三角形的大小不一樣時,OpenGLES渲染管線會進行拉伸縮放處理,程序員需要做的只是在程序中設(shè)置拉伸和濾波方式即可,合理的拉伸和濾波操作可以彌補一些由于紋理本身的大小缺陷造成的貼圖效果的下降。本發(fā)明構(gòu)建的是一個三維的球體模型,但是拼接后的全景圖像依然是一個二維的圖像,要把一個二維圖像映射到球面上,需要進行拓撲變換。先把球面變換為圓柱面,然后再進行拓撲變換,將圓柱面沿著它的高線切開形成一個長方形。進行拓撲變換后的圖形,頂點的個數(shù)和頂點之間的連接線屬性都是沒有變化的,只不過把這些邊和面做了平移、旋轉(zhuǎn)或縮放操作。這樣,把一個球面變換為一個長方形平面之后,紋理映射就會顯得十分的簡單了,紋理坐標也一目了然。(5)在最終顯示前,還要進行一些視角上的變換,因為球體是三維的,屏幕是二維的,需要將球體投影到屏幕上,這通過一系列的矩陣變換來實現(xiàn)。當對三維場景或物體做變換時,主要是對描繪該物體的頂點位置做相應(yīng)的變換,然后把新的頂點送入OpenGLES渲染管線,當OpenGLES渲染管線進行幀更新的時候,會繪制新的三維場景或物體。典型的矩陣變換示意如下:簡寫為Q=MP上述線性代數(shù)表達式中最左側(cè)為變換后Q點的齊次坐標,中間的為4×4的變換矩陣,右側(cè)為變換前P點的齊次坐標。當矩陣M中的元素取適當?shù)闹禃r,等式Q=MP就會有其特殊的幾何意義。例如:可以將三維空間中的點P平移、旋轉(zhuǎn)或縮放到點Q。這些變換的具體信息就存放在矩陣M中,因此通常稱矩陣M為變換矩陣。當需要連續(xù)執(zhí)行一系列的變換時,依次將變換矩陣乘以表示點位置的齊次坐標向量即可。例如平移變換:QxQyQz1=100mx010my001mz0001×PxPyPz1=Px+mxPy+myPz+mz1]]>實際上,OpenGLES在做變換時,并不是針對物體做變換的,變換的其實是坐標系,傳入渲染管線的仍然是原來的頂點坐標。這是一種非常巧妙的方法,如果對所有的頂點坐標做矩陣計算,將會產(chǎn)生非常龐大的計算量,如果對坐標系做變換,只需要一步計算即可。(6)使用傳感器改變視角。為了通過陀螺儀控制視頻的移動,需要注冊一個旋轉(zhuǎn)矢量傳感器,得到的數(shù)值上是一個將坐標軸和角度混合計算得到的數(shù)據(jù),它主要用來表示設(shè)備的旋轉(zhuǎn)的方向。旋轉(zhuǎn)矢量的三個輸出數(shù)據(jù)可以由以下表達式表明:X×sin(θ2)Y×sin(θ2)Z×sin(θ2)]]>此時旋轉(zhuǎn)矢量大小為旋轉(zhuǎn)矢量的方向與轉(zhuǎn)軸的方向一致。旋轉(zhuǎn)矢量的三個輸出結(jié)果實際上就是四元數(shù)的后三個表達式。旋轉(zhuǎn)矢量的輸出值是無單位的。所參考的坐標系被定義為一個標準正交基(如附圖4)。該坐標系具有以下特征:1、Y值是設(shè)備當前所處位置與地磁北極的正切值。2、X值被定義為Y與Z值的向量積。即設(shè)備當前所處位置的地面與東方向的正切值。3、Z值朝向天空方向,與地面垂直相交。接下來要將旋轉(zhuǎn)矢量數(shù)據(jù)轉(zhuǎn)換成矩陣的形式,也就是旋轉(zhuǎn)矩陣,典型的旋轉(zhuǎn)矩陣示意如下:cosθ+(1-cosθ)ux2(1-cosθ)uyux-sinθuz(1-cosθ)uzux+sinθuy0(1-cosθ)uxuy+sinθuzcosθ+(1-cosθ)uy2(1-cosθ)uzuy-sinθux0(1-cosθ)uxuz-sinθuy(1-cosθ)uyuz+sinθuxcosθ+(1-cosθ)uz200001]]>上述矩陣表示將指定的點P繞軸向量u旋轉(zhuǎn)θ度,其中的表示u向量在X、Y、Z軸上的分量。然后將這個旋轉(zhuǎn)矩陣也參與到矩陣變換中,最后將得到的矩陣與球體位置坐標向量相乘,就得到了頂點在屏幕上的最終位置。這樣由傳感器實時更新數(shù)據(jù),也就實時更新了變換矩陣,得到的效果就是全景視頻在屏幕上進行了移動。本發(fā)明與現(xiàn)有技術(shù)相比的有益效果在于:(1)在電視上直接觀看全景視頻,省去了笨重昂貴的虛擬現(xiàn)實頭盔,節(jié)約了成本;(2)利用遙控器控制全景視頻畫面的移動,而不用轉(zhuǎn)頭,操作起來非常輕松方便;長時間觀看也不會有眩暈感,疲勞感;(3)大屏幕的電視上,可以多人一起觀看,增加樂趣;(4)使用遙控器可以快速移動視頻畫面,便于查看視頻中特定的細節(jié),可以應(yīng)用在一些特殊的場合,比如查看監(jiān)控錄像。附圖說明圖1為全景視頻示意圖;圖2為OpenGL三維球體示意圖;圖3為紋理映射示意圖;a為物體面,b為紋理圖片;圖4為OpenGLES的坐標系;圖5全景視頻播放器工作流程圖。具體實施方式下面根據(jù)
發(fā)明內(nèi)容,結(jié)合說明書附圖,對本發(fā)明進行具體說明:步驟一:使用blender創(chuàng)建一個球體。OpenGL只支持繪制點、線和三角形,所以球體是由一系列三角形頂點組成的多面體,當這些頂點足夠多,這個多面體就近似為一個球體。使用blender創(chuàng)建好球體模型后,將其obj文件放在Android項目的資源目錄下,使用的時候讀取其中的數(shù)據(jù)即可。步驟二:創(chuàng)建并初始化播放器。實例化一個MediaPlayer,使用其setDataSource()方法獲取視頻源,視頻源可以是網(wǎng)絡(luò)視頻,或者是本地視頻。然后設(shè)置Surface為視頻容器,隱藏標題欄并設(shè)置播放器為全屏。步驟三:獲取視頻流圖像幀作為紋理。創(chuàng)建、生成紋理ID,實例化SurfaceTexture,用它接收視頻流,然后獲取視頻流中的圖像幀作為紋理,綁定到生成的紋理ID上,使用GL_TEXTURE_EXTERNAL_OES作為紋理目標,然后設(shè)置紋理濾波方式。最后以實例化的SurfaceTexture為參數(shù),創(chuàng)建上一步使用到的Surface。步驟四:更新紋理。由于播放的視頻不是圖片,所以需要更新紋理。使用SurfaceTexture的updateTexImage()方法將紋理內(nèi)容更新為視頻流中最近的圖片,這樣就能使視頻中的每一幀圖像都作為紋理,經(jīng)過處理后通過OpenGL的渲染管線進行渲染,最后顯示出來。步驟五:注冊陀螺儀傳感器,設(shè)置旋轉(zhuǎn)矩陣。首先創(chuàng)建一個傳感器管理器(SensorManager),由它生成旋轉(zhuǎn)矢量傳感器,接著使用函數(shù)getRotationMatrixFromVector()把由傳感器感應(yīng)到的旋轉(zhuǎn)矢量變化信息轉(zhuǎn)換成四維矩陣的形式,即旋轉(zhuǎn)矩陣,這個矩陣將用來旋轉(zhuǎn)球體模型。步驟六:進行矩陣投影變換,更新視角。需要用到的ModelMatrix(模型矩陣,坐標系以物體為中心),ViewMatrix(視角矩陣,坐標系以眼睛或攝像機為中心),RotationMatrix(旋轉(zhuǎn)矩陣,由傳感器數(shù)值生成),和ProjectionMatrix(投影矩陣,三維空間到二維空間的投影)。其中:視角矩陣ViewMatrix的設(shè)置函數(shù)為Matrix.setLookAtM(mViewMatrix,0,eyeX,eyeY,eyeZ,lookX,lookY,lookZ,upX,upY,upZ);投影矩陣ProjectionMatrix的設(shè)置函數(shù)為Matrix.frustumM(mProjectionMatrix,0,left,right,bottom,top,near,far);旋轉(zhuǎn)矩陣RotationMatrix由傳感器數(shù)據(jù)生成。將這些矩陣相乘,就得到了最終的變換矩陣:MVPMatrix。這個矩陣用于將頂點坐標進行變換。這樣,當傳感器的數(shù)值實時更新時,最終的效果就是更新了變換矩陣MVPMatrix。步驟七:編譯鏈接著色程序。由于OpenGLES著色語言編寫的VertexShader(頂點著色器)程序和FragmentShader(片段著色器)程序不能由java程序識別執(zhí)行,因此兩種著色器程序會放置在另一個資源文件夾中,使用getVertexShader()和getFragmentShader()方法來從該資源文件夾中讀取代碼,保存為String格式。讀取完代碼后,使用glCompileShader()函數(shù)來編譯,接著使用glCreateProgram()函數(shù)創(chuàng)建一個渲染程序program,然后用glAttachShader()方法將編譯好的著色程序和program進行綁定,最后用glLinkProgram()方法鏈接這個program。步驟八:從obj模型文件中讀取數(shù)據(jù)。使用AndroidSDK提供的getResources().openRawResource()方法打開并讀取資源文件的數(shù)據(jù)到一個輸入流中,接下來解析這個輸入流即可。首先分配存儲空間,分別創(chuàng)建存儲頂點坐標信息、紋理坐標信息和面索引信息的字符串類型的動態(tài)數(shù)組,然后根據(jù)數(shù)據(jù)類型分別存放到相應(yīng)的動態(tài)數(shù)組中。Java中的String類的split(″″)函數(shù)可以把字符串按照特定的字符進行分割,分割后的數(shù)據(jù)將依次按順序儲存在數(shù)組中,例如:行數(shù)據(jù)為214/209/198229/224/198228/225/198,分割后的數(shù)據(jù)放在數(shù)組faceComponent中,那么先按空格分割,存儲到數(shù)組j中,j[0]=214/209/198,這就是組成該面的第一個頂點的行索引信息,再把j[0]按“/”分割,那么faceComponent[0]=214,faceComponent[1]=209,那么第一個頂點坐標在214行,紋理坐標在209行。獲取索引信息后,就要去相應(yīng)的地方取出坐標,先使用parseInt()函數(shù)把字符串轉(zhuǎn)換為數(shù)字,取出來的頂點坐標數(shù)據(jù)為1.950948-17.654135-2.919814,然后按空格進行分割,把三個數(shù)字按順序存在數(shù)組中,最后使用parseFloat()函數(shù)轉(zhuǎn)化為float型變量即可。最后,還要將獲取的數(shù)據(jù)送入了內(nèi)存中,因為OpenGLES的渲染是在GPU中完成的,然而GPU是無法從程序主線程中獲取數(shù)據(jù)的,GPU可以從內(nèi)存中取得需要的數(shù)據(jù),所以我們需要把數(shù)據(jù)按照順序送入內(nèi)存中以供GPU使用。步驟九:傳遞數(shù)據(jù)給著色器。讀取obj模型數(shù)據(jù)到內(nèi)存后,接下來GPU要使用這些數(shù)據(jù)。首先聲明使用program作為著色程序,獲取頂點坐標數(shù)據(jù)、紋理、紋理坐標數(shù)據(jù)以及變換矩陣(MVPMatrix)等參數(shù)的句柄,然后使用glVertexAttribPointer()函數(shù)和glEnableVertexAttribArray()函數(shù)向VertexShader傳入這些參數(shù)的數(shù)據(jù)。VertexShader再將相關(guān)變量數(shù)據(jù)傳給FragmentShader,FragmentShader會以線性插值的方法進行逐像素的渲染。步驟十:播放視頻,繪制圖像。使用MediaPlayer的start()方法播放視頻,使用glDrawArrays()方法繪制渲染后的每一幀視頻圖像,并顯示在屏幕上。最后使用陀螺儀遙控器控制全景視頻上下左右移動。這樣就實現(xiàn)了全景視頻在機頂盒上的播放和控制,播放器的工作流程如圖5所示。當前第1頁1 2 3