Android视频播放之VideoView
Android視頻播放之VideoView
?
1、VideoView類介紹
Android的VideoView組件可以從不同的來源(例如資源文件或內(nèi)容提供器)讀取圖像,計算和維護視頻的畫面尺寸以使其適用于任何布局管理器,并提供一些諸如縮放、著色之類的顯示選項,包含在widget下面:android.widget.VideoView。Android中視屏播放框架如下圖:
從圖中可以看出,VideoView組件進行視頻播放的過程可以分為三步:
(1)JAVA Framework層,應用程序進來之后到VideoView,再經(jīng)過Surface;
(2)Native Framework層,先到SurfaceFlinger,然后到OverlayHal,同時借助了PVPlayer;
(3)Driver層,利用Main framebuffer和Video Plane進行播放;
VideoView組件的類繼承與接口實現(xiàn)情況為:
繼承:public class VideoView extends SurfaceView
接口:implements MediaController.MediaPlayerControl
而從Object開始的繼承層次如下:
java.lang.Object
android.view.View
android.view.SurfaceView
android.widget.VideoView
VideoView類的構造函數(shù)有三個:
(1)public VideoView(Context context),創(chuàng)建一個默認屬性的VideoView實例。參數(shù)context為視圖運行的應用程序上下文,通過它可以訪問當前主題、資源等等。注:以下描述中重復參數(shù)的解釋就不給出了。
(2)public VideoView(Context context, AttributeSet attrs),創(chuàng)建一個帶有attrs屬性的VideoView實例。attrs用于視圖的 XML 標簽屬性集合。
(3)public VideoView(Context context, AttributeSet attrs, int defStyle),創(chuàng)建一個帶有attrs屬性,并且指定其默認樣式的VideoView實例。參數(shù)defStyle為應用到視圖的默認風格,如果為 0 則不應用(包括當前主題中的)風格,該值可以是當前主題中的屬性資源,也可以是明確的風格資源ID。
比較常用的共有方法有播放start()、暫停pause()等,具體描述與用法見后面測試部分。
?
2、視頻播放代碼
?????? 先給出一個簡單的測試案例,程序中以File和Uri兩種形式來給VideoView組件加載手機SD卡中的視頻資源。資源類型為MP4,使用手機自帶攝像機錄制,完整路徑名為“/mnt/sdcard/Pictures/video.mp4”。在代碼采用的是讀取系統(tǒng)路徑的方式:Environment.getExternalStorageDirectory() + "/Pictures/video.mp4"。
另外說明一點,利用Uri對網(wǎng)絡資源進行讀取的方式和本地資源類似,只是資源名稱的形式不同。如:
1 Uri uri = Uri.parse("rtsp://v2.cache2.c.youtube.com/CjgLENy73wIaLwm3JbT_%ED%AF%80%ED%B0%819HqWohMYESARFEIJbXYtZ29vZ2xlSARSB3Jlc3VsdHNg_vSmsbeSyd5JDA==/0/0/0/video.3gp");文件格式3gp也是VideoView組件支持格式中的一種。
由于要對手機中的文件進行讀取,所以必須在AndroidManifest.xml文件中添加用戶權限:
1 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> 2 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 3 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />? ? ? 程序中用到的String變量封裝在了string.xml中:
1 <resources> 2 <string name="app_name">VideoView0803</string> 3 4 <string name="hello_world">Hello world!</string> 5 <string name="action_settings">Settings</string> 6 7 <string name="startCard">PlayCard</string> 8 <string name="pauseCard">StopCard</string> 9 <string name="startUri">PlayUri</string> 10 <string name="pauseUri">StopUri</string> 11 </resources>界面上的組件由一個VideoView、兩個Button,一個TextView組成,布局文件代碼如下:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" 3 android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" 4 android:paddingRight="@dimen/activity_horizontal_margin" 5 android:paddingTop="@dimen/activity_vertical_margin" 6 android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> 7 8 <Button 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:text="@string/startCard" 12 android:id="@+id/startCard" 13 android:layout_alignParentBottom="true" 14 android:layout_alignParentStart="true" 15 android:textColor="#00f" /> 16 17 <Button 18 android:layout_width="wrap_content" 19 android:layout_height="wrap_content" 20 android:text="@string/startUri" 21 android:id="@+id/startUri" 22 android:layout_alignBottom="@+id/startCard" 23 android:layout_alignParentEnd="true" 24 android:textColor="#f00" /> 25 26 <VideoView 27 android:layout_width="wrap_content" 28 android:layout_height="wrap_content" 29 android:id="@+id/videoView" 30 android:layout_alignParentStart="true" 31 android:layout_alignParentTop="true" 32 android:layout_above="@+id/startUri" 33 android:layout_centerHorizontal="true" /> 34 35 <TextView 36 android:layout_width="wrap_content" 37 android:layout_height="wrap_content" 38 android:textAppearance="?android:attr/textAppearanceMedium" 39 android:text="Resource Path" 40 android:id="@+id/fileName" 41 android:layout_alignTop="@+id/startCard" 42 android:layout_alignParentBottom="true" 43 android:layout_toEndOf="@+id/startCard" 44 android:gravity="center_vertical" 45 android:textColor="#000"/> 46 47 </RelativeLayout>其中,VideoView組件videoView用于視頻內(nèi)容的播放,Button組件startFile和startUri分別以File和Uri形式打開視頻文件,TextView組件fileName用于顯示完整路徑名(標注資源的來歷,對于該例子沒這個必要)。運行前的界面圖:
?????? 主文件MainActivity完整代碼如下:
1 package com.dylan_wang.videoview0803; 2 3 import android.app.Activity; 4 import android.net.Uri; 5 import android.os.Bundle; 6 import android.os.Environment; 7 import android.view.Menu; 8 import android.view.MenuItem; 9 import android.view.View; 10 import android.widget.Button; 11 import android.widget.MediaController; 12 import android.widget.TextView; 13 import android.widget.VideoView; 14 15 import java.io.File; 16 17 18 public class MainActivity extends Activity { 19 20 private String filename = null; 21 private Button startCard = null; 22 private Button startUri = null; 23 private TextView fileName = null; 24 private VideoView video = null; 25 private MediaController media = null; 26 27 @Override 28 protected void onCreate(Bundle savedInstanceState) { 29 super.onCreate(savedInstanceState); 30 setContentView(R.layout.activity_main); 31 32 filename = Environment.getExternalStorageDirectory() + "/Pictures/video.mp4"; 33 34 startCard = (Button)findViewById(R.id.startCard); 35 startUri = (Button)findViewById(R.id.startUri); 36 fileName = (TextView)findViewById(R.id.fileName); 37 video = (VideoView)findViewById(R.id.videoView); 38 media = new MediaController(MainActivity.this); 39 40 startCard.setOnClickListener(new View.OnClickListener() { 41 @Override 42 public void onClick(View v) { 43 playVideoFromFile(); 44 } 45 }); 46 47 startUri.setOnClickListener(new View.OnClickListener() { 48 @Override 49 public void onClick(View v) { 50 openVideoFromUri(); 51 } 52 }); 53 } 54 55 private void playVideoFromFile(){ 56 if(startCard.getText().toString().equals("PlayCard")) { 57 File file = new File(filename); 58 if (file.exists()) { 59 //將VideoView與MediaController進行關聯(lián) 60 video.setVideoPath(file.getAbsolutePath()); 61 video.setMediaController(media); 62 media.setMediaPlayer(video); 63 //讓VideoView獲取焦點 64 video.requestFocus(); 65 video.start(); 66 startCard.setText(R.string.pauseCard); 67 fileName.setText(filename); 68 } 69 } 70 else { 71 video.pause(); 72 startCard.setText(R.string.startCard); 73 } 74 } 75 76 private void openVideoFromUri(){ 77 if(startUri.getText().toString().equals("PlayUri")) { 78 Uri uri = Uri.parse(filename); 79 video.setVideoURI(uri); 80 video.setMediaController(media); 81 media.setMediaPlayer(video); 82 //同上 83 video.requestFocus(); 84 video.start(); 85 startUri.setText(R.string.pauseUri); 86 fileName.setText(filename); 87 } 88 else { 89 video.pause(); 90 startUri.setText(R.string.startUri); 91 } 92 } 93 94 @Override 95 public boolean onCreateOptionsMenu(Menu menu) { 96 // Inflate the menu; this adds items to the action bar if it is present. 97 getMenuInflater().inflate(R.menu.menu_main, menu); 98 return true; 99 } 100 101 @Override 102 public boolean onOptionsItemSelected(MenuItem item) { 103 // Handle action bar item clicks here. The action bar will 104 // automatically handle clicks on the Home/Up button, so long 105 // as you specify a parent activity in AndroidManifest.xml. 106 int id = item.getItemId(); 107 108 //noinspection SimplifiableIfStatement 109 if (id == R.id.action_settings) { 110 return true; 111 } 112 113 return super.onOptionsItemSelected(item); 114 } 115 }
3、運行結果分析
OK,現(xiàn)在點擊界面上的任何一個按鈕就可以播放視頻文件了。由于兩個按鈕的響應只是讀取資源的方式不同,播放效果是一樣的,所以下面只給出點擊左邊按鈕PLAYCARD后的播放圖:
?? ??
左邊這張為程序運行后,沒有任何操作的圖片,右邊是正在播放視頻的圖片。
可以發(fā)現(xiàn)兩個有趣的現(xiàn)象:
1、在布局文件activity_main.xml中已將videoView組件在父容器中的設置為水平居中(android:layout_centerHorizontal="true"),而且運行初始界面也是正常的,但是視頻播放后,該組件就偏向了左邊;
2、播放過程中會有系統(tǒng)的控制欄出現(xiàn)在下方,可以點擊進行視屏的播放控制,但是在測試很不穩(wěn)定,出現(xiàn)一兩秒就會消失;
針對第一個問題,查了一些資料,有人說是因為默認情況下,如果視頻分辨率小于設備的屏幕分辨率,VideoView在播放視頻時都是在左上角顯示的,將VideoView組件的gravity屬性設置為center即可。但是在xml文件及UI編輯屬性欄均沒有找到VideoView組件有該屬性,難道和版本有關?也有人說和底層的Player有關,雖然沒有進行替換測試,但感覺這個原因比較靠譜。至于第二個問題,暫時沒有找到合理的解釋,以后繼續(xù)找吧。
有知道真實原因的大神,歡迎一起討論啊!
總結
以上是生活随笔為你收集整理的Android视频播放之VideoView的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Palindrome(插入字符变成回文字
- 下一篇: 【讨论贴】关于父实子虚的疑问???