"MPlayer+TextureView" : 封裝一個視訊播放器的 "SDK"
用過很多的SDK,關於友盟的、高德地圖的、騰訊的和支付寶的等;在這些功能上的實現會讓我們使用起來特別方便,即拿即用,閱讀下文件就好!對這種神奇的效果,我一直有著好奇心,最近在這塊兒稍微花了下時間和心思,然後這裡封裝一個視訊播放器的SDK來詮釋下這方面的封裝過程和思路。
使用類圖展示業務關係
SDK封裝邏輯
SDK = 視訊播放的業務功能 + 外觀模式實現業務功能的封裝
簡單描述
為了使用者快速上手使用,以最少的學習成本完成功能上的實現。比如我們使用過的騰訊、阿里和新浪微博的一些分享的或者地圖的SDK,往往那些複雜的邏輯功能最終呈現給我們開發者的時候,使用類的例項呼叫對應功能的api就搞定了。而實現的原理肯定能夠猜得到,即一層一層的封裝。最後最為開發者不用關心實現的過程,只需呼叫功能性的方法就能實現開發需求。
針對“MPlayer+TextureView” 實現的一個簡單的視訊播放的SDK :
上圖中 CustomVideoView 繼承自 RelativeLayout 所實現的一個基本的播放器功能的視訊播放核心類,只有視訊播放、暫停和停止等功能。而其他業務功能則是使用內部的一個介面 ADVideoPlayerListener ,其作用有 :
1)
承接CustomVideoView中的一些功能,並暴露到外部。從而實現功能上的層層封裝,然後在應用層回撥。
2)
實現業務功能上的擴充套件,如點選全屏播放、小平播放、播放視窗劃入螢幕播放和滑出暫停等功能。其中VideoAdShell是對眾多業務上的擴充套件,比如滑入播放、滑出暫停播放功能;
3)
業務層VideoAdShell也仿照這種方式繼續向上封裝。
VideoFullDialog是對全屏播放和小屏模式的功能擴充套件。業務功能上從內到外的通訊方式使用的是介面的回撥。最後使用一個類<構建者模式建立例項、外觀模式封裝業務功能>作為該SDK呼叫視訊播放器api的入口,通過簡單的方法呼叫來實現複雜的播放邏輯,並結合介面的回撥來獲得操作上的結果反饋。
視訊效果展示
簡單邏輯描述:該頁面是一個RecycleView
列表,其中一個item
用來展示視訊播放;視訊的item播放視窗滑入螢幕超過自身的50%則開始靜音播放,滑出暫停。點選全屏,則進入全屏的有聲播放。點選全屏按鈕,item的播放視訊的View從item的Layout中remove,然後add到全屏視訊的dialog的Layout中繼續播放;全屏點選關閉按鈕或者播放完畢,則將視訊播放的view再次從dialog的Layout中remove,將視訊的view再次add到列表的item中的Layout繼續執行全屏時候的視訊狀態。視訊核心只有播放、暫停等基本視訊功能,複雜業務擴充套件在上層進行封裝,最後通過外觀模式進行再次的封裝成為方便通用的SDK 以供使用。
程式碼介紹
通過程式碼來描述視訊播放功能,從內到外,各種業務邏輯實現的封裝過程。直至最後的sdk。
做一個視訊播放,它的生命週期是要牢記的
核心層邏輯
自定義一個RelativeLayout,作為視訊播放”MPlayer+TextureView”的Layout。這樣的設計會讓整個視訊播放元件的使用靈活性大大提高。
設定視訊在列表中的播放視窗大小的寬高比是 16:9
當自定義RelativeLayout被載入之後執行
上面74、75、76三行程式碼,目的和作用是為了防止播放頁面切換之後出現黑屏問題;
接下來就進入到了視訊播放前的資源載入邏輯。
316:表示顯示視訊播放之前,開始進入載入資源之後的視訊載入動畫;
320:設定靜音播放;
321:載入視訊資源;
319:判斷、建立MediaPlayer物件,配置mediaPlayer、vvideoSurface(Surface物件)
當視訊資源非同步載入成功之後,回撥
呼叫resume();方法進行視訊播放。
public void resume() {
if (this.playerState != STATE_PAUSING) {
return;
}
LogUtils.d(TAG, "do resume");
if (!isPlaying()) {
entryResumeState();
mediaPlayer.setOnSeekCompleteListener(null);
mediaPlayer.start();
mHandler.sendEmptyMessage(TIME_MSG);
showPauseView(true);
} else {
showPauseView(false);
}
}
一個視訊播放器的基本功能當然還由暫停、播放按鈕等按鈕的響應邏輯;
225:播放器狀態處於暫停狀態,點選按鈕之後,進入播放;
232:否則,重新載入視訊資源,並進行重播;
234:點選進入大屏播放;
237:點選視訊播放視窗呼叫對應的操作邏輯;
以上則是播放核心執行的過程及邏輯。作為一個sdk,除了這些,一定還會有更復雜的業務的。那麼怎對核心層進行封裝擴充套件業務?
核心層業務的封裝擴充套件——視訊播放業務層
對核心層進行業務擴充套件,就是說把一些視訊播放的業務邏輯包裹封裝在核心層外面。
達到一種什麼效果呢?“視訊播放業務層” 能訪問到 “核心層” 的內容,核心層同樣也能訪問視訊播放業務層的內容。也就是說,視訊播放業務層和核心層兩者互相暴露響應的介面給對方。
這個時候使用什麼方式實現呢?介面回撥。
使用這種方式,而不是以內部類暴露介面的實現方式,這樣能夠更好的擴充套件Class A的業務功能。當然回到視訊播放的核心層也是一樣,也是為了更好的進行業務的擴充套件來設計的。並且使用介面進行業務分層也是一種很好的解耦和方式。
好的,進入核心層原始碼,定義核心層需要進行擴充套件的業務,使用介面進行擴充套件。
在視訊播放業務層即擴充套件層進行實現,
比如其中一個功能上的擴充套件,當視訊播放結束之後的擴充套件:
在核心層
在業務擴充套件層——視訊播放的業務層
兩個方法進行對比可得出結論,核心層直接處理視訊播放結束之後的邏輯,並使用回撥把視訊播放結束的資訊反饋到上層進行封裝並做相應處理。然後在業務擴充套件層又繼續使用介面,將視訊播放結束的資訊反饋到更上一層,直到最後的sdk封裝並暴露介面對外不的應用層做最後的簡單處理,以此來實現作為一個sdk要實現的功能。
324:視訊播放結束之後的回撥;
視訊播放業務層,也使用核心層進行擴充套件的方式,定義介面進行業務的擴充套件和對外介面的暴露。
在sdk的頂層實現業務層釋放的介面進行再次封裝,然後使用外觀模式*並結合
*構建者模式來實現一個使用者寥寥幾行程式碼就能夠實現複雜視訊播放的業務功能。
視訊視窗、小屏和大屏切換的邏輯演算法
視訊視窗滑入螢幕、滑出螢幕,然後根據視訊視窗進入螢幕視野百分比計算的演算法。
public static int getVisiblePercent(View pView) {
if (pView != null && pView.isShown()) {
DisplayMetrics displayMetrics = pView.getContext().getResources().getDisplayMetrics();
int displayWidth = displayMetrics.widthPixels;
Rect rect = new Rect();
pView.getGlobalVisibleRect(rect);
if ((rect.top > 0) && (rect.left < displayWidth)) {
double areaVisible = rect.width() * rect.height();
double areaTotal = pView.getWidth() * pView.getHeight();
return (int) ((areaVisible / areaTotal) * 100);
} else {
return -1;
}
}
return -1;
}
在列表中點選視訊播放視窗的全屏按鈕,邏輯實現在視訊播放業務層
169:記錄、反饋使用者操作給後臺;
175:從列表的Layout中移除自定義的 RelativeLayout (播放視訊的View);
176:新增播放視訊的View到全屏播放的Dialog中,並繼續當前的視訊播放;
public static Bundle getViewProperty(View view) {
Bundle bundle = new Bundle();
int[] screenLocation = new int[2];
view.getLocationOnScreen(screenLocation); //獲取view在整個螢幕中的位置
bundle.putInt(PROPNAME_SCREENLOCATION_LEFT, screenLocation[0]);
bundle.putInt(PROPNAME_SCREENLOCATION_TOP, screenLocation[1]);
bundle.putInt(PROPNAME_WIDTH, view.getWidth());
bundle.putInt(PROPNAME_HEIGHT, view.getHeight());
Log.e("Utils", "Left: " + screenLocation[0] + " Top: " + screenLocation[1]
+ " Width: " + view.getWidth() + " Height: " + view.getHeight());
return bundle;
}
而當視訊播放完成或者點選關閉按鈕的話,會回撥上面185行程式碼,的下面方法:
視訊播放完成或者點選關閉按鈕,dialog會執行dismiss方法,
@Override
public void dismiss() {
LogUtils.e(TAG, "dismiss");
mParentView.removeView(mVideoView);
super.dismiss();
}
dialog中remove掉,列表Layout中add。從而實現視訊的正常大小屏的切換和播放;
相關文章
- AVFoundation | 封裝一個好用的視訊播放器封裝播放器
- React Native 原生檢視封裝全解析:視訊播放器示例React Native封裝播放器
- ArtVideoPlayer:一個靈活的視訊播放器IDE播放器
- 分享一個功能很全的視訊播放器播放器
- request sdk 封裝封裝
- 騰訊直播SDK接入及封裝(一)之錄屏直播封裝
- 一個高自由度的Flutter 視訊播放器Flutter播放器
- Cordova-iOS SDK封裝iOS封裝
- Java 封裝 SDK 以及使用Java封裝
- 一個強悍而優美的Android視訊播放器Android播放器
- Mac視訊播放器哪個好用?Mac播放器
- iOS 圖解一個功能很全的視訊播放器的使用iOS圖解播放器
- Flutter視訊播放封裝歷程Flutter封裝
- 封裝一個通用的PopupWindow封裝
- 封裝了一個騰訊雲im的flutter外掛封裝Flutter
- 使用VideoView做個實用的視訊播放器IDEView播放器
- 一個簡單的 Amqp 封裝MQ封裝
- 封裝一個自己的js庫封裝JS
- 基於 logger sdk-logger 封裝封裝
- 用promise封裝一個ajaxPromise封裝
- 使用ts封裝一個ajax封裝
- Android播放器基礎封裝庫PlayerBaseAndroid播放器封裝
- eventBus(封裝) 一個巧妙的解決vue同級元件通訊的思路封裝Vue元件
- 2.1 萬 Star!一個開源免費、功能強大的視訊播放器庫播放器
- MPV 播放器:Linux 下的極簡視訊播放器播放器Linux
- 封裝一個簡單的日曆元件封裝元件
- 8.7 一個模組的封裝過程封裝
- MusicLibrary-一個豐富的音訊播放SDK。音訊
- 自定義視訊播放器播放器
- 視訊播放器工具Infuse播放器
- 阿里雲視訊播放器阿里播放器
- 我自己封裝的 Laravel 融雲 sdk,簡單好用封裝Laravel
- 短視訊平臺原始碼,取驗證碼 封裝全部封裝好直接呼叫原始碼封裝
- 批量將一個視訊新增到多個視訊中的背景,一鍵生成視訊背景
- 【JavaScript框架封裝】實現一個類似於JQuery的動畫框架的封裝JavaScript框架封裝jQuery動畫
- 封裝了一個? URL地址解析封裝
- 記一則iOS封裝SDK的開發過程之WebView與JS的互動iOS封裝WebViewJS
- 前端ui自動化測試sdk封裝前端UI封裝