To build a better world !

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


              轉載請注明出處:http://www.aygfsteel.com/zh-weir/archive/2010/01/24/310617.html


              2010.03.27    SeeJoPlayer v1.2.0 beta版:  

               下載SeeJoPlayer v1.2.0 beta     下載SeeJoPlayer v1.2.0 beta源碼


              更新說明:

              1、完美支持android1.5、android1.6、android2.0、android2.01、android2.1平臺;
              2、完美支持320×480、480×800、480×854等各種分辨率(自適應屏幕分辨率);
              3、支持在線音視頻播放,支持URL input和從瀏覽器調用SeeJoPlayer播放器播放在線音視頻;
              4、自動轉為橫屏播放,為用戶提供更好的觀看體驗;
              5、修改了沒有SD卡程序出錯的Bug;
              6、美化了視頻播放列表和操作說明的界面。

              補充圖片:
              




          URL輸入功能

              




          瀏覽器中調用SeeJoPlayer播放


              感謝大家對SeeJoPlayer的大力支持!希望新版本能帶給大家更好的體驗!


              2010.01.24    SeeJoPlayer v1.0.0版: 

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


                   下載APK程序         下載源代碼         轉到eoeMarket發布頁

              



           第一部分:功能介紹


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

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

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

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



          橫屏



          豎屏



          全屏



          非全屏



          播放列表



          介紹說明

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


                   下載APK程序         下載源代碼         轉到eoeMarket發布頁



          第二部分:源碼解析
           

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

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

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

              一、VideoView與視頻比例縮放:

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

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

              VideoView的源碼中有這樣一段代碼:

           1@Override
           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的長寬改變而改變了。

           1@Override
           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"}nullnullnull);
           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中:

           1@Override   
           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.aygfsteel.com/zh-weir/archive/2010/01/24/310617.html


                   下載APK程序         下載源代碼         轉到eoeMarket發布頁



              
              

          posted on 2010-01-24 17:20 zh.weir 閱讀(61991) 評論(104)  編輯  收藏 所屬分類: Android項目源碼

          評論共2頁: 上一頁 1 2 

          評論

          # re: Android平臺下SeeJoPlayer視頻播放器(功能介紹及源碼解析,附源碼)[未登錄] 2010-01-24 18:10 L

          不知道支持的視頻格式有哪些??  回復  更多評論   

          # re: Android平臺下SeeJoPlayer視頻播放器(功能介紹及源碼解析,附源碼) 2010-01-24 18:25 zh.weir

          @L
          SeeJoPlayer采用的是系統默認的解碼方式,因此對于G1來說,它應該只支持MP4和3GP。但是如果你的系統本身支持更多格式,那么只要媒體庫里有的格式,它原理上都支持。  回復  更多評論   

          # re: Android平臺下SeeJoPlayer視頻播放器(功能介紹及源碼解析,附源碼) 2010-01-25 15:28 changedi

          慚愧,首先在eoeandriod看到這篇文章,來支持一下~~最近打算學習Andriod  回復  更多評論   

          # re: Android平臺下SeeJoPlayer視頻播放器(功能介紹及源碼解析,附源碼)[未登錄] 2010-02-08 16:27 a

          Android1.5支持如下的媒體類型:

          類型
          格式
          編碼
          解碼
          詳情
          文件類型

          Audio
          AAC LC/LTP

          Y
          單/ 雙聲道160Kpbs 的碼率,采樣4-48KHz


          3GPP(.3gp)

          MPEG-4(.mp4,.m4a)

          不支持raw AAC(.aac)

          HE-AACv1

          (AAC+)

          Y

          HE-AACv2

          ( 增強AAC+)

          Y

          AMR-NB
          Y
          Y
          4.75 to 12.2 kbps sampled @ 8kHz
          3GPP (.3gp)

          AMR-WB

          Y
          9 rates from 6.60 kbit/s to 23.85 kbit/s sampled @ 16kHz
          3GPP (.3gp)

          MP3

          Y
          Mono/Stereo 8-320Kbps constant (CBR) or variable bit-rate (VBR)
          MP3 (.mp3)

          MIDI

          Y
          MIDI Type 0 and 1. DLS Version 1 and 2. XMF and Mobile XMF. Support for ringtone formats RTTTL/RTX, OTA, and iMelody
          Type 0 and 1 (.mid, .xmf, .mxmf). Also RTTTL/RTX (.rtttl, .rtx), OTA (.ota), and iMelody (.imy)

          Ogg Vorbis

          Y

          Ogg (.ogg)

          PCM/WAVE

          Y
          8- and 16-bit linear PCM (rates up to limit of hardware)
          WAVE (.wav)

          Image
          JPEG
          Y
          Y
          Base+progressive
          JPEG(.jpg)

          GIF

          Y

          GIF(.gif)

          PNG

          Y

          PNG(.png)

          BMP

          Y

          BMP(.bmp)

          Video
          H.263
          Y
          Y

          3GPP (.3gp)


          H.264 AVC

          Y

          3GPP (.3gp) and MPEG-4 (.mp4)


          MPEG-4 SP

          Y

          3GPP (.3gp)


          T1還 額外支持了:Audio 的WMA ,Video 的WMV類型。
            回復  更多評論   

          評論共2頁: 上一頁 1 2 

          公告

          大家好!歡迎光臨我的 Android 技術博客!



          本博客旨在交流與 Android 操作系統相關的各種技術及信息。

          博客內的文章會盡量以開源的形式提供給大家,希望我們能相互交流,共同提高!

          有不足之處,請不吝賜教!

          我的郵箱:zh.weir@gmail.com
          我的新浪微博:@囧虎張建偉

           

          導航

          <2016年1月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          統計

          留言簿(19)

          隨筆分類(24)

          隨筆檔案(18)

          文章檔案(1)

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 孝义市| 宝丰县| 宣恩县| 宁夏| 岳普湖县| 岳阳市| 百色市| 顺义区| 大庆市| 安平县| 彩票| 双流县| 鄂伦春自治旗| 合江县| 林口县| 彭水| 旺苍县| 大洼县| 五指山市| 阿尔山市| 乃东县| 鲜城| 茶陵县| 册亨县| 合作市| 克什克腾旗| 沐川县| 台南市| 且末县| 安丘市| 阿坝县| 卫辉市| 宜丰县| 宜川县| 谷城县| 衢州市| 三都| 周口市| 偏关县| 宝鸡市| 兰西县|