Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android平台下SeeJoPlayer視頻播放器(功能介紹及源碼解析,附源碼)

Android平台下SeeJoPlayer視頻播放器(功能介紹及源碼解析,附源碼)

日期:2017/2/24 18:48:41      編輯:Android開發實例

    SeeJoPlayer是我利用業余時間開發的一款免費的視頻播放器。主要是現在在網上似乎找不到一個Android平台下的界面美觀一點的視頻播放器。而作為智能手機操作系統的Android,沒有一個像樣一點的視頻播放器,豈不糗大了。所以,我就寫了這麼一個磚頭並開出源碼,希望能引出高手們的美玉來吧!


         下載APK程序         下載源代碼        

    



 第一部分:功能介紹


    SeeJoPlayer的優點主要在相對還算美觀的界面和便捷的交互操作上。先說操作吧,它支持:

    1、全屏切換:       雙擊屏幕
    2、播放/暫停:     長按屏幕
    3、靜音/恢復:     長按音量按鈕
    4、播放列表:       控制面板最右邊的按鈕(暫不支持編輯功能)
    5、音量調節:       單擊音量按鈕,在彈出的音量顯示區域觸摸改變音量 

    這些操作和PC上的播放器較為類似,希望大家能用得習慣。

    至於界面的話,多說無益,直接上圖吧:



橫屏


豎屏


全屏


非全屏


播放列表



介紹說明

    好了。功能介紹部分到此為止了。如果您覺得這個軟件還行的話,歡迎下載使用!


         下載APK程序         下載源代碼        



第二部分:源碼解析
 

    SeeJoPlayer不是一個完美的作品,可以說,它在很多地方都不盡如人意。當然一個完美的作品,也不是我寫這款播放器的目的。我只是希望以此為引,結合大家共同的智慧開發出一款真正完美強大的Android平台下的國產視頻播放器出來。

    SeeJoPlayer有許多不足之處,例如,它只支持系統默認的視頻格式,因為它使用系統默認的解碼器。這,一方面是因為如果通過軟解碼的話,播放視頻的效率會很受影響,另外最主要的原因當然還是個人水平、精力有限,沒辦法接著往下做了。如果大家覺得這份代碼還多少有些參考價值的話,不妨拿去用。只是希望當你們以此為參考,開發出真正強大的播放器出來的時候,別忘了如果能開放源碼的話,一定開放出來。畢竟開源軟件就好比能夠進化的物種,提供你的DNA出來,讓我們共同的軟件變得越來越完美吧!

    好了,廢話不說了。播放器的全部源碼本文中已經提供了下載地址。下面,我就其中我覺得可能值得關注的地方做一些解釋。

    一、VideoView與視頻比例縮放:

    以前在論壇上也看到有人問過如何實現視頻按比例縮放的問題。的確,如果僅僅使用VideoView可能達不到我們想要達到的效果。這就需要我們對VideoView做一些改動,簡單的說就是另外寫一個類似VideoView的類出來(慶幸Android是開源的)。

    我們可以很方便的獲得VideoView的源代碼,最簡單的方法是直接在GoogleCodeSearch上找“VideoView.java”。所以重寫VideoView的過程其實只是在原來的基礎上進行一些修改而已,並非一個很麻煩的工作。為什麼Android自帶的VideoView會保持視頻的長寬比而不能讓我們很方便的自定義比例呢?我猜想可能Google做Android也是一個很倉促的工程,許多代碼並沒有考慮得太成熟。

    VideoView的源碼中有這樣一段代碼:
[email protected]
2 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
3 //Log.i("@@@@", "onMeasure");
4 int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
5 int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
6 if (mVideoWidth > 0 && mVideoHeight > 0) {
7 if ( mVideoWidth * height > width * mVideoHeight ) {
8 //Log.i("@@@", "image too tall, correcting");
9 height = width * mVideoHeight / mVideoWidth;
10 } else if ( mVideoWidth * height < width * mVideoHeight ) {
11 //Log.i("@@@", "image too wide, correcting");
12 width = height * mVideoWidth / mVideoHeight;
13 } else {
14 //Log.i("@@@", "aspect ratio is correct: " +
15 //width+"/"+height+"="+
16 //mVideoWidth+"/"+mVideoHeight);
17 }
18 }
19 //Log.i("@@@@@@@@@@", "setting size: " + width + 'x' + height);
20 setMeasuredDimension(width, height);
21 }
22
    這就是為什麼長寬比不能改變的原因了。因為在OnMeasure的時候,就對這個長寬比進行了處理。

    我們把其中處理的代碼屏蔽掉,視頻大小就可以隨著VideoView的長寬改變而改變了。

[email protected]
2 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
3 //Log.i("@@@@", "onMeasure");
4 int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
5 int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
6 /**//*if (mVideoWidth > 0 && mVideoHeight > 0) {
7 if ( mVideoWidth * height > width * mVideoHeight ) {
8 //Log.i("@@@", "image too tall, correcting");
9 height = width * mVideoHeight / mVideoWidth;
10 } else if ( mVideoWidth * height < width * mVideoHeight ) {
11 //Log.i("@@@", "image too wide, correcting");
12 width = height * mVideoWidth / mVideoHeight;
13 } else {
14 //Log.i("@@@", "aspect ratio is correct: " +
15 //width+"/"+height+"="+
16 //mVideoWidth+"/"+mVideoHeight);
17 }
18 }*/
19 //Log.i("@@@@@@@@@@", "setting size: " + width + 'x' + height);
20 setMeasuredDimension(width,height);
21 }

    二、視頻控制菜單與播放界面的層次問題:

    看到過一些別人寫的視頻播放器,其中有一些朋友老是簡簡單單的將VideoView和控制界面放在一個LinearLayout中。這樣隨著控制界面的出現與否,VideoView會隨之改變長寬,給人的體驗並不很好。所以,我認為VideoView和控制界面最好不要放在同一個層次上。不要偷懶,使用一個FrameLayout或者PopupWindow就可以解決這個問題。例如,我就簡簡單單地使用了PopupWindow,這個具體實現上,就百花爭鳴吧。

    三、視頻文件掃描:

    視頻文件的掃描,現在想來主要有兩種方式:

    第一種就是直接讀取媒體庫中的視頻文件數據庫。當Android啟動的時候,系統會自動掃描sdcard,並為媒體文件建立(或者更新)數據庫。我們可以通過對應的URI來訪問數據庫,從而得到視頻文件的列表:
  
1private Uri videoListUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
2
3
4
5Cursor cursor = getContentResolver().query(videoListUri, new String[]{"_display_name","_data"}, null, null, null);
6 int n = cursor.getCount();
7 cursor.moveToFirst();
8 LinkedList<MovieInfo> playList2 = new LinkedList<MovieInfo>();
9 for(int i = 0 ; i != n ; ++i){
10 MovieInfo mInfo = new MovieInfo();
11 mInfo.displayName = cursor.getString(cursor.getColumnIndex("_display_name"));
12 mInfo.path = cursor.getString(cursor.getColumnIndex("_data"));
13 playList2.add(mInfo);
14 cursor.moveToNext();
15 }

    這種方法可能是最有效率的了,不過不知為何,媒體庫中似乎沒有掃描進本身支持的3GP視頻格式(也可能我這裡是一個特例) 。不過,正是因為這個原因,我才想到有可能需要另外一種最基本的掃描文件系統的方法來掃描視頻文件。這就是文件系統的遍歷:

1 private void getVideoFile(final LinkedList<MovieInfo> list,File file){
2
3 file.listFiles(new FileFilter(){
4
5 @Override
6 public boolean accept(File file) {
7 // TODO Auto-generated method stub
8 String name = file.getName();
9 int i = name.indexOf('.');
10 if(i != -1){
11 name = name.substring(i);
12 if(name.equalsIgnoreCase(".mp4")||name.equalsIgnoreCase(".3gp")){
13
14 MovieInfo mi = new MovieInfo();
15 mi.displayName = file.getName();
16 mi.path = file.getAbsolutePath();
17 list.add(mi);
18 return true;
19 }
20 }else if(file.isDirectory()){
21 getVideoFile(list, file);
22 }
23 return false;
24 }
25 });
26 }
    當然,隨著Android平台下的硬件設備越來越多,越來越強大。我們有理由相信,它以後將不僅僅只支持MP4和3GP格式的視頻文件,所以我們必須使用兩種方式結合的方法來獲得最大的視頻集合作為我們的視頻列表。

    四、播放過程中進度條progress的設定:

    視頻開始播放了,那麼一個小麻煩出現了:什麼時候設定進度條才更有效率?我這裡有一種方法供大家參考,那就是通過Handler自己給自己發消息來達到不斷設置進度條的目的。

1 Handler myHandler = new Handler(){
2
3 @Override
4 public void handleMessage(Message msg) {
5 // TODO Auto-generated method stub
6
7 switch(msg.what){
8
9 case PROGRESS_CHANGED:
10
11 int i = vv.getCurrentPosition();
12 seekBar.setProgress(i);
13
14 i/=1000;
15 int minute = i/60;
16 int hour = minute/60;
17 int second = i%60;
18 minute %= 60;
19 playedTextView.setText(String.format("%02d:%02d:%02d", hour,minute,second));
20
21 sendEmptyMessage(PROGRESS_CHANGED);
22 break;
23
24
25
26     
    當然,這種方法,需要首先發送一個初始消息來啟動。

    五、全屏與非全屏:

    大家都知道,一般一個Activity設置全屏的方法有兩種,一是在OnCreate中:

[email protected]
2public void onCreate(Bundle icicle) {
3 super.onCreate(icicle);
4
5 requestWindowFeature(Window.FEATURE_NO_TITLE);
6 Window win = getWindow();
7 win.setFlags(WindowManager.LayoutParams.NO_STATUS_BAR_FLAG,
8 WindowManager.LayoutParams.NO_STATUS_BAR_FLAG);
9
10 setContentView(R.layout.mylayout);
11
12
13
    二是在AndroidManifest.xml中:

1<activity android:name=".MyActivity" 
2          android:label=""
3          android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
    然而,這兩種方法都不能達到我們在視頻播放過程中設置全屏與否的目的。因為它們都只能在初始化的時候決定全屏與否。那麼我現在要說的就是第三種方法:

1getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
1getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    這種方法就可以在Activity運行過程中,動態地改變全屏與否。

    六、音量調節:

    音量調節的方法其實很簡單,不過有人問到,我就在這裡順便說下:

1        AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
2        setIndex(am.getStreamVolume(AudioManager.STREAM_MUSIC));
    好了,就寫這些了吧。可能這些知識有人知道,或者還有些盲點我沒有講到。歡迎大家與我聯系,大家一起多多討論交流,並且整個源碼都開放出來了,大家一定可以把來龍去脈弄得一清二楚的!最後,多謝大家聽我羅嗦,歡迎使用SeeJoPlayer,歡迎閱讀其源碼!本文也歡迎大家轉載,不過轉載請注明出處:http://www.blogjava.net/zh-weir/archive/2010/01/24/310617.html
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved