日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

解决SurfaceView渲染的各种疑难杂症

發布時間:2024/4/15 编程问答 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 解决SurfaceView渲染的各种疑难杂症 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

======================== 2020.3.24 修改部分過時API =============================

Pangu-Immortal (Pangu-Immortal) · GitHub

RecyclerView加載多個surfaceview覆蓋,旋轉,黑屏 ??

SurfaceView黑色背景??透明背景??多層嵌套被遮擋??

苦苦找了好多天,各個論壇問遍了,都是互相抄,痛苦的我,嘗試了好多種方式都解決不了。

翻了幾天surfaceview的源碼和API,現把解決方法總結,分享一下。


首先說:不能在list視圖中使用VideoView,因為VideoView繼承SurfaceView,

而SurfaceView不支持UI同步緩沖(UI synchronization buffer),這導致當滑動list時視頻會丟進度。

TextureView支持同步緩沖,但沒有基于TextureView的VideoView。這個問題至今我無法解決。

使用WebRTC 58 想實現一個視頻窗口列表,幾十個視頻窗口,劃出屏幕就暫停,顯示時就開始加載。仍無法無法實現WebRTC內使用的是SurfaceView。

贈送源碼:GitHub - Pangu-Immortal/MagicWX: 🔥免root實現 Android改機(一鍵新機)技術解密,微信無限多開等。。

Pangu-Immortal (Pangu-Immortal) · GitHub

《最完整的Android逆向知識體系》

這個問題有 愿意討論 或者 做過類似效果,或者知道如何處理的,請告知我一聲,十萬分的感謝。。。


看一下google的API都有哪些:

多層嵌套被遮擋:

setZOrderOnTop(boolean onTop) // 在最頂層,會遮擋一切view

setZOrderMediaOverlay(boolean isMediaOverlay)// 如已繪制SurfaceView則在surfaceView上一層繪制。

網上很多人都會告訴你第一個,幾乎都是互相抄襲,應用在游戲里還可以,多窗口視頻是不可以的。

如果在surfaceView上繪制surfaceView應該用第二個,并且必須在addview之后調用。

  • layout.addView(surfaceView);
  • surfaceView.setZOrderMediaOverlay(true); ? // 必須layout.addView之后使用,必須動態調用。

SurfaceView 怎么進行旋轉,透明操作的?

  • 普通View旋轉后,View的內容也跟著同步做了旋轉.

  • SurfaceView在旋轉之后,其顯示內容并沒有跟著一起旋轉.

比喻:這就好比在墻上開了一個窗(Surface),通過窗口可以看外面的花花世界,但窗口無論怎樣變化,窗外面的世界是不會跟著窗口一同變化。

一般視頻播放器可以橫豎屏切換,是如何實現的?
在 Activity 中覆寫 onConfigurationChanged 方法就可以。根據橫豎屏切換,修改 SurfaceView 的 Parameter 的寬高參數即可。

android:configChanges="orientation|keyboardHidden|screenSize" @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { //變成橫屏了 } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { //變成豎屏了 } }

不繪制任何東西,SurfaceView顯示的是黑色?

每次更新視圖時都會先將背景繪制成黑色。所以在移動或者縮放過程,會更新不及時時就會看黑邊。

@Override public void draw(Canvas canvas) {if (mDrawFinished && !isAboveParent()) {// draw() is not called when SKIP_DRAW is setif ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {// punch a whole in the view-hierarchy below uscanvas.drawColor(0, PorterDuff.Mode.CLEAR);}}super.draw(canvas); }//這句話表示PorterDuff.Mode.CLEAR會將像素設置為0,也就是黑色 //Destination pixels covered by the source are cleared to 0. public enum Mode {// these value must match their native equivalents. See SkXfermode.h/*** <p>* <img src="{@docRoot}reference/android/images/graphics/composite_CLEAR.png" />* <figcaption>Destination pixels covered by the source are cleared to 0.</figcaption>* </p>* <p>\(\alpha_{out} = 0\)</p>* <p>\(C_{out} = 0\)</p>*/CLEAR (0), }

SurfaceView背景問題:

很多人介紹了好多種方法改變他的黑色背景為透明。我初步加載時就直接看到了桌面,直接透過去了。并沒有遇到很多人說的默認黑色背景。

原因是設置的主題問題,由于我自定義了dialog。有無法去除的背景白條,所以設置了主題,這個白條背景也是主題引起的。然而這個主題

也造成了透明的效果。

嘗試好多天,翻遍各種API,才突然意識到可能是主題不同引起的。

studio創建工程時的默認主題:

<!-- Base application theme. --><style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"><!-- Customize your theme here. --><item name="colorPrimary">@color/colorPrimary</item><item name="colorPrimaryDark">@color/colorPrimaryDark</item><item name="colorAccent">@color/colorAccent</item></style>

這個主題是默認SurfaceView為黑色背景,當然dialog也是有無法去除的背景,想設置半透明就要設置一個主題。

<style name="Theme.AppStartLoadTranslucent" parent="android:Theme"><item name="android:windowIsTranslucent">true</item><item name="android:windowNoTitle">true</item></style>

注意看主題的值:parent="android:Theme" ? ,item不重要。如果是:DarkActionBar 就是黑色背景。

我換成了這個主題,dialog的背景就成功去除了,當然surfaceView默認加載就是透到桌面的,沒有背景,如果設置背景會遮蓋住畫面。必須換一個主題。

網上你會搜到很多更改背景為透明的方法,比如:

  • surfaceView.setZOrderOnTop(true);
  • surfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT); ? // 設置畫布 ?背景透明

這是在默認的主題下設置的。多次嘗試后“Theme.Design.NoActionBar” 這個主題很通用??梢試L試一下。有問題可以留言,我們再討論。

當你發現一些能夠API對你的View不起作用,尤其是透明度,背景,圓角等,你感覺主題可以設置的一切屬性,你要先檢查一下自己設置的主題樣式是不是對他有限制。

可以嘗試換個主題試試呢,沒準會有意外收獲。。

贈送源碼:GitHub - Pangu-Immortal/MagicWX: 🔥免root實現 Android改機(一鍵新機)技術解密,微信無限多開等。。

《最完整的Android逆向知識體系》


SurfaceView的生命周期管理有三個方法:

  • SurfaceCreated

  • SurfaceChanged

  • SurfaceDestoryed

如何使用SurfaceView呢?

1、獲取SurfaceHolder對象,其是SurfaceView的內部類。

  • 監聽Surface生命周期。

  • 只有當native層的Surface創建完畢之后,才可以調用lockCanvas(),否則失敗。
    holder.Callback。

2、調用holder.lockCanvas()。
3、繪制
4、調用SurfaceHolder.unlockCanvasAndPost,將繪制內容post到Surface中

SurfaceView的特點有那些

  • 具有獨立的繪圖表面Surface。

  • 需要在宿主窗口上挖一個洞來顯示自己,z軸比普通的window要小。

  • 它的UI繪制可以在獨立的線程中進行,這樣就可以進行復雜的UI繪制,并且不會影響應用程序的主線程響應用戶輸入。

SurfaceView的優缺點

優點

  • 在一個子線程中對自己進行繪制,避免造成UI線程阻塞。

  • 高效復雜的UI效果。

  • 獨立Surface,獨立的Window。

  • 使用雙緩沖機制,播放視頻時畫面更流暢。

缺點

  • 每次繪制都會優先繪制黑色背景,更新不及時會出現黑邊現象。

  • Surface不在View hierachy中,它的顯示也不受View的屬性控制,平移,縮放等變換。

  • 不支持UI同步緩沖

SurfaceVeiw雙緩沖區

雙緩沖:在運用時可以理解為:SurfaceView在更新視圖時用到了兩張 Canvas,一張 frontCanvas 和一張 backCanvas ,每次實際顯示的是 frontCanvas ,backCanvas 存儲的是上一次更改前的視圖。當你在播放這一幀的時候,它已經提前幫你加載好后面一幀了,所以播放起視頻很流暢。
當使用lockCanvas()獲取畫布時,得到的實際上是backCanvas 而不是正在顯示的 frontCanvas ,之后你在獲取到的 backCanvas 上繪制新視圖,再 unlockCanvasAndPost(canvas)此視圖,那么上傳的這張 canvas 將替換原來的 frontCanvas 作為新的frontCanvas ,原來的 frontCanvas 將切換到后臺作為 backCanvas 。例如,如果你已經先后兩次繪制了視圖A和B,那么你再調用 lockCanvas()獲取視圖,獲得的將是A而不是正在顯示的B,之后你將重繪的 A 視圖上傳,那么 A 將取代 B 作為新的 frontCanvas 顯示在SurfaceView 上,原來的B則轉換為backCanvas。

相當與多個線程,交替解析和渲染每一幀視頻數據。

surfaceholder.lockCanvas--surfaceholder.unlockCanvasAndPost

SurfaceView 和普通的View的區別?

  • surfaceView是在一個新起的單獨線程中可以重新繪制畫面。

  • View必須在UI的主線程中更新畫面。

  • 那么在UI的主線程中更新畫面可能會引發問題,比如你更新畫面的時間過長,那么你的主UI線程會被你正在畫的函數阻塞。那么將無法響應按鍵,觸屏等消息。

  • 當使用surfaceView 由于是在新的線程中更新畫面所以不會阻塞你的UI主線程。

SurfaceView 生命周期

使用:雙緩沖
導致:需要更多的內存開銷
為了節約系統內存開銷:

SurfaceView 可見時 -> 創建 SurfaceHolder
SurfaecView 不可見時 -> 摧毀 SurfaceHolder

1、程序打開
Activity 調用順序:onCreate()->onStart()->onResume()
SurfaceView 調用順序: surfaceCreated()->surfaceChanged()

2、程序關閉(按 BACK 鍵)
Activity 調用順序:onPause()->onStop()->onDestory()
SurfaceView 調用順序: surfaceDestroyed()

3、程序切到后臺(按 HOME 鍵)
Activity 調用順序:onPause()->onStop()
SurfaceView 調用順序: surfaceDestroyed()

4、程序切到前臺
Activity 調用順序: onRestart()->onStart()->onResume()
SurfaceView 調用順序: surfaceChanged()->surfaceCreated()

5、屏幕鎖定(掛斷鍵或鎖定屏幕)
Activity 調用順序: onPause()
SurfaceView 什么方法都不調用

6、屏幕解鎖?
Activity 調用順序: onResume()
SurfaceView 什么方法都不調用

橫屏錄制橫屏播放,豎屏錄制豎屏播放
通過以下方法可以獲取到視頻的寬高,根據視頻的寬高就可以知道該視頻是橫屏還是豎屏錄制的。

public void onVideoSizeChanged(MediaPlayer mp, int width, int height)

橫屏判斷:width>height
旋轉屏幕:setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

豎屏錄制:height>width
旋轉屏幕:setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

mediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {@Overridepublic void onVideoSizeChanged(MediaPlayer mp, int width, int height) {Log.e(TAG, "onVideoSizeChanged:WIDTH>>" + width);Log.e(TAG, "onVideoSizeChanged:HEIGHT>>" + height);if (width > height) {//橫屏錄制if (getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);}} else {//豎屏錄制if (getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);}}} });

View的繪制要知道的知識
View的繪制其實是在UI線程(實現onCanvas方法進行繪制)。如果進行繪制高效復雜的UI,最好不用自定義View。要用SurfaceView進行繪制。

SurfaceView 能繪制什么東西?
從下面代碼可以看到,SurfaceView 的繪制也是使用 Canvas 進行繪制的,繪制應該跟普通的 View 繪制差不多

/*** 繪制*/ private void draw() {if (radius > getWidth()) {return;}Canvas canvas = mHolder.lockCanvas();if (canvas != null) {canvas.drawCircle(300, 300, radius += 10, mPaint);mHolder.unlockCanvasAndPost(canvas);} }

View的繪畫三要素

  • Canvas (畫布,繪制BitMap操作)

  • Paint (繪制的畫筆Paint,顏色、樣式)

  • Path (路徑)

一、Canvas

  • 如果直接extends View 可以重寫onDraw(Canvas canvas)方法,直接用里面的canvas進行繪制。

  • 可以直接利用Activity的繪制機制,用lockCanvas()方法來獲得當前的Activity的Canvas。

  • 在SurfaceView中,同2可以利用SurfaceHolder的對象的lockCanvas()方法來Canvas。

二、Paint

直接通過new關鍵字來實例化,然后通過Paint對象來對畫筆進行相應的設置:
如:

  • 1.1 去鋸齒setAntiAlia(true)

  • 1.2 去抖動setDither(true)

  • 1.3 設置圖層混合模式setXfermode(Xfermode,xfermode)

三、 Path

  • 1、Path路徑 直接用new來實例化

  • 2、通過path對象設置想要畫圖的軌跡或路線,如:矩形 、三角形 、圓、曲線等


綜上所述:

為什么視頻技術入門要先了解圖片繪制,那么圖片繪制的API也有多種,為什么選擇用SurfaceView這個API,

因為:

其一,繪制是在子線程中進行繪制的,

其二,可能繪制出高效復雜的UI效果,

其三,使用雙緩沖機制,播放視頻時畫面更流暢。


找到的一些小項目源碼:Pangu-Immortal (Pangu-Immortal) · GitHub

很值得學習的一個視頻直播項目?https://github.com/littleMeng/video-live

贈送源碼:GitHub - Pangu-Immortal/MagicWX: 🔥免root實現 Android改機(一鍵新機)技術解密,微信無限多開等。。

《最完整的Android逆向知識體系》

沉溺于編程不可自拔時,也要記得多多鍛煉。。


總結

以上是生活随笔為你收集整理的解决SurfaceView渲染的各种疑难杂症的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。