【Android 多媒体开发】 MediaPlayer 网络视频播放器
作者 : 万境绝尘 (octopus_truth@163.com)
转载请著名出处 :http://blog.csdn.net/shulianghan/article/details/38895143
一. 相关模块解析
1. 播放载体 SurfaceView 简介
(1) SurfaceView 与 Surface
SurfaceView 与 Surface 简介 : SurfaceView 中嵌入了一个 Surface, SurfaceView 可以操控 Surface 的 位置, 大小尺寸等;
-- SurfaceView 绘制图像可见性 : Surface 相当与一块画板, 上面绘制了一些东西, 但是不是所有的内容都可见, SurfaceView 相当与 Surface 的窗口, 只有在 SurfaceView 窗口区域内的才是可见的, 其它没有在窗口正下方的内容不可见;
-- Surface 与 SurfaceView 声明周期对应 : SurfaceView 可见的时候 Surface 被创建, SurfaceView 不可见时 Surface 销毁, Surface 创建销毁时机回调方法 SurfaceCreated(SurfaceHolder) 和 SurfaceDestoryed(SurfaceHolder) 方法, 这两个回调方法是 SurfaceHolder.Callback 中设定;
-- Surface 控制 : SurfaceView 通过 SurfaceHolder 控制 Surface;
(2) SurfaceHolder 简介
Surfaceholder 简介 : SurfaceHolder 是 Surface 的控制器, 用于控制 SurfaceView 绘图, 处理画布上的 动画 渲染效果 尺寸等;
-- 添加 Callback 回调接口 :abstract void addCallback(SurfaceHolder.Callback callback), 添加一个 SurfaceHolder.Callback 接口对象, 监听 Surface 的开始结束绘制大小改变事件;
-- 锁定画布 : abstract Canvas lockCanvas(), 锁定画布, 可以获得 Canvas 对象, 之后就可以在 Canvas 上绘图了;
(3) SurfaceHolder.Callback 简介
SurfaceHolder.Callback 接口 :
-- Surface 绘图边界 : 所有的绘图操作, 在 Surface 创建后操作, 在 Surface 销毁之前结束;
-- SurfaceHolder.Callback 接口对应 Surface 边界 : SurfaceCreated() 方法在 Surface 创建时回调, SurfaceDestroyed() 方法在 Surface 销毁前回调;
SurfaceHolder.Callback 接口中的方法简介 :
-- SurfaceChanged() : Surface 大小改变前回调;
-- surfaceCreated() : surface 创建时回调;
-- surfaceDestroyed() : surface 销毁时回调;
2. SurfaceView 使用流程
(1) 在布局文件中使用 SurfaceView 组件
布局文件 : 在布局文件中使用 <SurfaceView /> 组件;
-- 示例 :
<SurfaceView android:id="@+id/surface_view" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="3"/>
(2) 设置 SurfaceHolder.Callback 回调接口
创建回调接口子类 : Activity 继承SurfaceHolder.Callback 接口, 实现接口的三个方法 SurfaceCreated(), SurfaceChanged(), SurfaceDestroyed() 方法;
-- 示例 : 一般情况下直接设置 Activity 实现该接口, 为 SurfaceHolder 设置接口的时候直接将 Activity 设置进去;
public class HomeActivity extends Activity implements SurfaceHolder.Callback { /** * 在 Surface 大小发生改变的时候回调 * 实现的 SurfaceHolder.Callback 接口方法 */ @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { System.out.println("SurfaceHolder.Callback.surfaceChanged : Surface 大小发生改变"); } /** * 在 Surface 创建的时候回调, 一般在该方法中开始绘图 * 实现的 SurfaceHolder.Callback 接口方法 */ @Override public void surfaceCreated(SurfaceHolder arg0) { System.out.println("SurfaceHolder.Callback.surfaceCreated : Surface 开始创建"); } /** * 在 Surface 销毁之前回调, 在该方法中停止渲染线程, 释放相关资源 * 实现的 SurfaceHolder.Callback 接口方法 */ @Override public void surfaceDestroyed(SurfaceHolder arg0) { System.out.println("SurfaceHolder.Callback.surfaceDestroyed : Surface 销毁"); } }
(3) 获取 SurfaceHolder 对象 并添加回调接口子类
获取 SurfaceHolder 流程 :
-- a. 获取 SurfaceView : 使用 findViewById() 方法从布局文件中获取 SurfaceView 组件对象;
surface_view = (SurfaceView) findViewById(R.id.surface_view);-- b. 从 SurfaceView 组件对象中获取 SurfaceHolder : 调用 SurfaceView 对象的 getHolder() 即可获取 SurfaceHolder 对象;
surface_holder = surface_view.getHolder(); /* 根据 SurfaceView 组件, 获取 SurfaceHolder 对象 */-- c. 为 SurfaceHolder 设置回调接口 : 调用 Surfaceholder 的 setCallback() 方法即可, 用于监听 Surface 的创建 改变 和 销毁;
surface_holder.addCallback(this); /* 为 SurfaceHolder 设置回调函数, 即 SurfaceHolder.Callback 子类对象 */
SurfaceHolder 其它设置 :
-- 设置 SurfaceHolder 画面比例 : 调用 SurfaceHolder 的setFixedSize() 方法;
surface_holder.setFixedSize(160, 128); /* 设置视频大小比例 */-- 设置 SurfaceHolder 数据类型 : 调用 SurfaceHolder 的setType() 方法;
surface_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);/* 设置视频类型 */
总体代码示例 :
/** * 初始化相关数据变量 */ private void initData() { /* 获取并设置 SurfaceHolder 对象 */ surface_holder = surface_view.getHolder(); /* 根据 SurfaceView 组件, 获取 SurfaceHolder 对象 */ surface_holder.addCallback(this); /* 为 SurfaceHolder 设置回调函数, 即 SurfaceHolder.Callback 子类对象 */ surface_holder.setFixedSize(160, 128); /* 设置视频大小比例 */ surface_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);/* 设置视频类型 */ }
3.AutoCompleteTextView 组件
组件特性 : 可以设置一个适配器, 适配器中维护一组字符串, 当输入一部份字符后, 能自动将符合条件的提示出来;
-- 示例 :
(1) 在布局文件中定义组件
布局文件中 : 使用 <AutoCompleteTextView /> 标签添加组件;
-- 设置后面省略 :android:ellipsize="end" , 由于链接太长, 不能显示全部, 自动将后面的部分省略;
-- 设置提示 :android:completionHint="选择下载的视频地址", 设置弹出的提示栏最后一栏的提示;
-- 设置单行显示 :android:singleLine="true";
-- 设置输入几个字符之后开始提示 :android:completionThreshold="1", 这里设置的是输入第一个字符之后就开始自动提示;
-- 示例 :
<AutoCompleteTextView android:id="@+id/url" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:ellipsize="end" android:completionThreshold="1" android:text="http://daily3gp.com/vids/747.3gp" android:completionHint="选择下载的视频地址"/>
(2) 创建适配器
创建适配器方法 :
android.widget.ArrayAdapter.ArrayAdapter<String>(Context context, int textViewResourceId, String[] objects)-- Context context 参数 : 上下文对象;
--int textViewResourceId 参数 : 显示列表的组件的布局;
--String[] objects 参数 : 字符串数组对象;
代码示例 :
/* 设置一个列表适配器 */ String[] urls = { "http://daily3gp.com/vids/747.3gp", "http://daily3gp.com/vids/Funny%20women%20cannot%20understand.3gp", "http://k.youku.com/player/getFlvPath/sid/9409280845322127f6c57_00/st/flv/fileid/0300020100540024BC9E5C08BD8A98D8200E2B-7950-B9A5-8669-DC283BDCC077?K=3a58dc2cdcc532df261dddec&ctype=12&ev=1&oip=1931322792&token=5696&ep=eyaUE0uFVsYE4CDdij8bYHrkJ3IIXP4J9h%2BFg9JjALshTOi%2FmzqjtJTFS4xCHottelMPGJ%2F5qdDnH0JmYfdKrGgQrUfZPPro%2BPbq5dkgxpgDFG1FAc3Qs1SbRTn3", "http://k.youku.com/player/getFlvPath/sid/9409280845322127f6c57_00/st/flv/fileid/030002040053FFB59E433100422C39BAFA46CC-4DED-E928-87B8-91706CDB5FF2?K=645d8478a3aa59052411eb8a&ctype=12&ev=1&oip=1931322792&token=5696&ep=eyaUE0uFVsYE4CDdij8bYHrkJ3IIXP4J9h%2BFg9JmALshS57J6zvYspmzTf5CFv0bcFEFGZmA3aHjbDNnYfQ33BwQqkeqMfro%2BYLr5aRSw5AGFW1Ed7uhtlSbRTn3" }; /* 创建数组适配器 */ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, urls); /* 将适配器设置给 AutoCompleteTextView 组件对象 */ url.setAdapter(adapter);
4. MediaPlayer 播放
(1) 设置音量 和 播放载体
设置音量 :
mediaPlayer.setAudioStreamType(2); /* 设置播放音量 */
设置播放载体 : 调用 setDisplay() 方法, 传入 SurfaceHolder 对象;
mediaPlayer.setDisplay(surface_holder); /* 设置播放载体 */
(2) 设置各种监听器
设置错误监听器 : 如果出现错误, 会回调该监听器中的方法, 并提供错误码;
/* 设置 MediaPlayer 错误监听器, 如果出现错误就会回调该方法打印错误代码 */ mediaPlayer.setOnErrorListener(new OnErrorListener() { @Override public boolean onError(MediaPlayer arg0, int what, int extra) { System.out.println("MediaPlayer 出现错误 what : " + what + " , extra : " + extra); return false; } });
设置缓冲进度监听器 : 缓冲有进展后, 回调该监听器中的方法, 传入缓冲的数据百分比;
/* 设置缓冲进度更新监听器 */ mediaPlayer.setOnBufferingUpdateListener(new OnBufferingUpdateListener() { @Override public void onBufferingUpdate(MediaPlayer arg0, int percent) { /* 打印缓冲的百分比, 如果缓冲 */ System.out.println("缓冲了的百分比 : " + percent + " %"); } });
设置播放完毕监听器 : 播放完毕后会回调该监听器中的方法;
/* 设置播放完毕监听器 */ mediaPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer arg0) { System.out.println("播放完毕了"); status.setText("播放完毕"); } });
设置准备完毕回调监听器 : 准备完毕后会回调该方法;
/* 设置准备完毕监听器 */ mediaPlayer.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer arg0) { System.out.println("准备完毕"); /* 设置播放状态 */ status.setText("播放中"); } });
二. 代码示例
1. 布局文件代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="20dp" tools:context="cn.org.octopus.videodemo.HomeActivity" tools:ignore="MergeRootFrame" android:orientation="vertical"> <AutoCompleteTextView android:id="@+id/url" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:ellipsize="end" android:completionThreshold="1" android:text="http://daily3gp.com/vids/747.3gp" android:completionHint="选择下载的视频地址"/> <SurfaceView android:id="@+id/surface_view" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="3"/> <TextView android:id="@+id/status" android:layout_width="match_parent" android:gravity="center" android:layout_height="0dp" android:layout_weight="1" android:textSize="20dp" android:text="状态"/> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="center_vertical" android:orientation="horizontal"> <Button android:id="@+id/play" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="onClick" android:text="播放"/> <Button android:id="@+id/pause" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="onClick" android:text="暂停"/> <Button android:id="@+id/reset" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="onClick" android:text="重放"/> <Button android:id="@+id/stop" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="onClick" android:text="停止"/> </LinearLayout> </LinearLayout>
2. AndroidManifest 代码
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.org.octopus.videodemo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="17" android:targetSdkVersion="19" /> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="cn.org.octopus.videodemo.HomeActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
3. Activity 代码
package cn.org.octopus.videodemo; import java.io.IOException; import android.R.anim; import android.app.Activity; import android.content.DialogInterface.OnClickListener; import android.graphics.PixelFormat; import android.media.MediaPlayer; import android.media.MediaPlayer.OnBufferingUpdateListener; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.media.MediaPlayer.OnPreparedListener; import android.os.Bundle; import android.support.v4.view.ViewPager; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.TextView; /** * * * SurfaceHolder * 1. 简介 : 是 Surface 的控制器, 用于控制 SurfaceView 绘图, 处理画布上的动画, 渲染效果, 大小等; * 2. 常用方法 : * -- abstract void addCallback(SurfaceHolder.Callback callback) : 添加一个 SurfaceHolder.Callback 接口对象, 监听 Surface 的开始结束绘制大小改变事件; * -- abstract Canvas lockCanvas() : 锁定画布, 可以获得 Canvas 对象, 之后就可以在 Canvas 上绘图了; * * SurfaceHolder.Callback接口 : * 1. Surface 绘图边界 : 所有的绘图工作都在 Surface 创建之后才能进行, 在 Surface 销毁之前结束; * 2. Callback 接口对应的 Surface 边界 : surfaceCreated() 方法在开始绘制时回调, surfaceDestroyed() 在 Surface 销毁前回调; * 3. 该接口中的方法 : * -- surfaceChanged() : 在 Surface 大小改变时回调; * -- surfaceCreated() : 在 Surface 创建时回调; * -- surfaceDestroyed() : 在 Surface 销毁时回调; * * @author octopus * */ public class HomeActivity extends Activity implements SurfaceHolder.Callback { private AutoCompleteTextView url; /* 地址输入框, 带自动提示功能 */ private SurfaceView surface_view; /* 播放视频载体 */ private TextView status; /* 显示播放状态 */ private Button play; /* 播放按钮 */ private Button pause; /* 咱提供按钮 */ private Button reset; /* 重放按钮 */ private Button stop; /* 停止按钮 */ private MediaPlayer mediaPlayer; /* 播放器 */ private SurfaceHolder surface_holder; /* Surface 控制器 */ private boolean isStartPlaying; /* 是否开始了播放 */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); initViews(); initData(); } /** * 初始化成员变量中的组件变量 */ private void initViews() { /* 通过 findViewById 获取相关方法 */ url = (AutoCompleteTextView) findViewById(R.id.url); surface_view = (SurfaceView) findViewById(R.id.surface_view); status = (TextView) findViewById(R.id.status); play = (Button) findViewById(R.id.play); pause = (Button) findViewById(R.id.pause); reset = (Button) findViewById(R.id.reset); stop = (Button) findViewById(R.id.stop); /* 设置一个列表适配器 */ String[] urls = { "http://daily3gp.com/vids/747.3gp", "http://daily3gp.com/vids/Funny%20women%20cannot%20understand.3gp", "http://k.youku.com/player/getFlvPath/sid/9409280845322127f6c57_00/st/flv/fileid/0300020100540024BC9E5C08BD8A98D8200E2B-7950-B9A5-8669-DC283BDCC077?K=3a58dc2cdcc532df261dddec&ctype=12&ev=1&oip=1931322792&token=5696&ep=eyaUE0uFVsYE4CDdij8bYHrkJ3IIXP4J9h%2BFg9JjALshTOi%2FmzqjtJTFS4xCHottelMPGJ%2F5qdDnH0JmYfdKrGgQrUfZPPro%2BPbq5dkgxpgDFG1FAc3Qs1SbRTn3", "http://k.youku.com/player/getFlvPath/sid/9409280845322127f6c57_00/st/flv/fileid/030002040053FFB59E433100422C39BAFA46CC-4DED-E928-87B8-91706CDB5FF2?K=645d8478a3aa59052411eb8a&ctype=12&ev=1&oip=1931322792&token=5696&ep=eyaUE0uFVsYE4CDdij8bYHrkJ3IIXP4J9h%2BFg9JmALshS57J6zvYspmzTf5CFv0bcFEFGZmA3aHjbDNnYfQ33BwQqkeqMfro%2BYLr5aRSw5AGFW1Ed7uhtlSbRTn3" }; /* 创建数组适配器 */ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, urls); /* 将适配器设置给 AutoCompleteTextView 组件对象 */ url.setAdapter(adapter); /* 使窗口支持透明度, 把当前 Activity 窗口设置成透明, 设置了该选项就可以使用 setAlpha 等函数设置窗口透明度 */ getWindow().setFormat(PixelFormat.TRANSPARENT); } /** * 初始化相关数据变量 */ private void initData() { /* 获取并设置 SurfaceHolder 对象 */ surface_holder = surface_view.getHolder(); /* 根据 SurfaceView 组件, 获取 SurfaceHolder 对象 */ surface_holder.addCallback(this); /* 为 SurfaceHolder 设置回调函数, 即 SurfaceHolder.Callback 子类对象 */ surface_holder.setFixedSize(160, 128); /* 设置视频大小比例 */ surface_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);/* 设置视频类型 */ } /** * 设置点击事件 * @param view */ public void onClick(View view) { int id = view.getId(); switch (id) { case R.id.play: /* 播放视频直接从 AutoCompleteTextView 中获取字符串, 播放该 url 代表的网络视频 */ playVideo(url.getText().toString()); break; case R.id.pause: if(mediaPlayer != null){ mediaPlayer.pause(); status.setText("暂停"); } break; case R.id.reset: if(mediaPlayer != null){ mediaPlayer.seekTo(0); mediaPlayer.start(); status.setText("播放中"); } break; case R.id.stop: if(mediaPlayer != null){ mediaPlayer.stop(); mediaPlayer.release(); isStartPlaying = false; status.setText("停止"); } break; default: break; } } /** * 播放网络视频 * a. 创建并配置 MediaPlayer 对象 (音量, SurfaceHolder) * b. 为 MediaPlayer 设置错误监听器, 缓冲进度监听器, 播放完毕监听器, 准备完毕监听器 * c. 未 MediaPlayer 设置数据源 * d. 调用 prepare() 进入 Prapared 状态 * e. 调用 start() 进入 Started 状态 * * @param dataSource 播放视频的网络地址 */ private void playVideo(final String dataSource) { /* 点击播放有两种情况 * a. 第一次点击 : 需要初始化 MediaPlayer 对象, 设置监听器 * b. 第二次点击 : 只需要 调用 mediaPlayer 的 start() 方法 * 两种情况通过 isStartPlaying 点击时间判断 */ if(isStartPlaying){ /* 如果已经开始了播放, 就直接开始播放 */ mediaPlayer.start(); }else{ /* 如果是第一次开始播放, 需要初始化 MediaPlayer 设置监听器等操作 */ mediaPlayer = new MediaPlayer(); /* 创建 MediaPlayer 对象 */ mediaPlayer.setAudioStreamType(2); /* 设置播放音量 */ mediaPlayer.setDisplay(surface_holder); /* 设置播放载体 */ /* 设置 MediaPlayer 错误监听器, 如果出现错误就会回调该方法打印错误代码 */ mediaPlayer.setOnErrorListener(new OnErrorListener() { @Override public boolean onError(MediaPlayer arg0, int what, int extra) { System.out.println("MediaPlayer 出现错误 what : " + what + " , extra : " + extra); return false; } }); /* 设置缓冲进度更新监听器 */ mediaPlayer.setOnBufferingUpdateListener(new OnBufferingUpdateListener() { @Override public void onBufferingUpdate(MediaPlayer arg0, int percent) { /* 打印缓冲的百分比, 如果缓冲 */ System.out.println("缓冲了的百分比 : " + percent + " %"); } }); /* 设置播放完毕监听器 */ mediaPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer arg0) { System.out.println("播放完毕了"); status.setText("播放完毕"); } }); /* 设置准备完毕监听器 */ mediaPlayer.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer arg0) { System.out.println("准备完毕"); /* 设置播放状态 */ status.setText("播放中"); } }); new Thread(){ public void run() { try { System.out.println("设置数据源"); mediaPlayer.setDataSource(dataSource); mediaPlayer.prepare(); /* 打印播放视频的时长 */ System.out.println("视频播放长度 : " + mediaPlayer.getDuration()); mediaPlayer.start(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }; }.start(); /* 设置 MediaPlayer 开始播放标识为 true */ isStartPlaying = true; /* 设置播放状态 */ status.setText("正在缓冲"); } } /** * 在 Surface 大小发生改变的时候回调 * 实现的 SurfaceHolder.Callback 接口方法 */ @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { System.out.println("SurfaceHolder.Callback.surfaceChanged : Surface 大小发生改变"); } /** * 在 Surface 创建的时候回调, 一般在该方法中开始绘图 * 实现的 SurfaceHolder.Callback 接口方法 */ @Override public void surfaceCreated(SurfaceHolder arg0) { System.out.println("SurfaceHolder.Callback.surfaceCreated : Surface 开始创建"); } /** * 在 Surface 销毁之前回调, 在该方法中停止渲染线程, 释放相关资源 * 实现的 SurfaceHolder.Callback 接口方法 */ @Override public void surfaceDestroyed(SurfaceHolder arg0) { System.out.println("SurfaceHolder.Callback.surfaceDestroyed : Surface 销毁"); } @Override protected void onDestroy() { if(mediaPlayer != null) mediaPlayer.release(); super.onDestroy(); } }
4. 运行示例
日志信息 :
octopus@octopus:~/develop/adt-bundle-linux/sdk/tools$ adb logcat -s System.out --------- beginning of /dev/log/main --------- beginning of /dev/log/system I/System.out(21129): 设置数据源 I/System.out(21129): 视频播放长度 : 31200 I/System.out(21129): 准备完毕 I/System.out(21129): 缓冲了的百分比 : 0 % I/System.out(21129): 缓冲了的百分比 : 37 % I/System.out(21129): 缓冲了的百分比 : 37 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 缓冲了的百分比 : 100 % I/System.out(21129): 播放完毕了 I/System.out(21129): 缓冲了的百分比 : 100 %
作者:万境绝尘(octopus_truth@163.com)
转载请著名出处:http://blog.csdn.net/shulianghan/article/details/38895143
相关推荐
Android开发 多媒体开发之MediaPlayer源代码
本文实例为大家分享了android多媒体音乐播放器的具体实现代码,供大家参考,具体内容如下 首先,在AndroidManifest.xml中配置权限 <!-- 读取手机中的音乐 --> <uses android:name=android.permission.READ...
Android MediaPlayer Playback---多媒体开发应用程序接口
android 利用MediaPlayer+SurfaceView播放视频,与我的文章对应http://blog.csdn.net/shenxiaolei507/article/details/41349295,而且其中还有很多高级功能的实现,还包括ViedioView播放视频!!
视频播放器(IJKplayer、ExoPlayer、MediaPlayer),HTTPS支持,支持弹幕,支持滤镜、水印、gif截图,片头广告、中间广告,多个同时播放,支持基本的拖动,声音、亮度调节,支持边播边缓存,支持视频本身自带...
例子中使用SurfaceView控件显示视频,使用MediaPlayer控制视频播放。
7.1 多媒体开发详解 7.1.1 Open Core 7.1.2 MediaPlayer 7.1.3 MediaRecorder 7.2 播放音乐 7.3 播放视频 7.4 录制歌曲 7.5 相机设置 7.6 闹钟设置 7.7 铃声设置 7.8 小结 第8章 网络与通信 8.1 网络通信基础 8.1.1...
《Android应用开发揭秘》内容全面,不仅详细讲解了Android框架、Android组件、用户界面开发、游戏开发、数据存储、多媒体开发和网络开发等基础知识,而且还深入阐述了传感器、语音识别、桌面组件开发、Android游戏...
本文实例讲述了Android开发之MediaPlayer多媒体(音频,视频)播放工具类。分享给大家供大家参考,具体如下: package com.android.imooc.chat; import java.io.IOException; import android.media.AudioManager; ...
代码中使用MediaPlayer类实现播放音频的功能。
7.1 多媒体开发详解 7.1.1 Open Core 7.1.2 MediaPlayer 7.1.3 MediaRecorder 7.2 播放音乐 7.3 播放视频 7.4 录制歌曲 7.5 相机设置 7.6 闹钟设置 7.7 铃声设置 7.8 小结 第8章 网络与通信...
7.1 多媒体开发详解 7.1.1 Open Core 7.1.2 MediaPlayer 7.1.3 MediaRecorder 7.2 播放音乐 7.3 播放视频 7.4 录制歌曲 7.5 相机设置 7.6 闹钟设置 7.7 铃声设置 7.8 小结 第8章 网络与通信...
如何使用Open Core、MediaPlayer、MediaRecorder方便快速地开发出包含音频和视频等流媒体的丰富多媒体应用? 如何利用Android 2.0新增的蓝牙特性开发包含蓝牙功能的应用?又如何使用蓝牙APL来完善应用的网络功能...
《Android开发案例驱动教程》 配套代码。 注: 由于第12,13,14章代码太大,无法上传到一个包中。 这三节代码会放到其他压缩包中。 作者:关东升,赵志荣 Java或C++程序员转变成为Android程序员 采用案例驱动模式...
视频播放器(IJKplayer、ExoPlayer、MediaPlayer),HTTPS支持,支持弹幕,支持滤镜、水印、gif截图,片头广告、中间广告,多个同时播放,支持基本的拖动,声音、亮度调节,支持边播边缓存,支持视频本身自带...
Android提供了对常用音频和视频格式的支持,它所支持的音频格式有MP3(.mp3)、3GPP(.3gp)、Ogg(.ogg)和WAVE(.ave)等,支持的视频格式有3GPP(.3gp)和MPEG-4(.mp4)等。通过AndroidAPI提供的相关方法,在Android中可以...