Android媒体框架:播放、录制与管理全解析
立即解锁
发布时间: 2025-08-26 01:05:18 阅读量: 7 订阅数: 20 


深入解析Android 3开发与实践
### Android 媒体框架:播放、录制与管理全解析
#### 1. 媒体框架概述
Android SDK 的媒体框架提供了丰富的功能,可用于播放和录制音频、视频,还能进行拍照。其核心类为 `android.media.MediaPlayer`,可处理多种格式的音频和视频内容,支持的内容来源包括网络、.apk 文件和 SD 卡。
以下是 `MediaPlayer` 支持的部分内容格式:
| 格式 | 扩展名 |
| ---- | ---- |
| 3GPP | .3gp |
| MP3 | .mp3 |
| MIDI | .mid 等 |
| Ogg Vorbis | .ogg |
| PCM/WAVE | .wav |
| MPEG - 4 | .mp4 |
#### 2. 使用 SD 卡
SD 卡在 Android 设备中常用于存储用户数据,特别是媒体内容。在 Android 开发中,有多种方式使用 SD 卡:
- **创建 SD 卡镜像**:使用 `mksdcard` 工具,例如在命令行中执行 `mksdcard 256M c:\Android\sdcard\sdcard.img` 可创建一个 256MB 的 SD 卡镜像。
- **推送和拉取文件**:可使用 Eclipse 中的 Android 工具或 `adb` 实用程序。`adb push c:\path_to_my_file\filename /mnt/sdcard/newfile` 用于将文件从工作站推送到 SD 卡,`adb pull /mnt/sdcard/devicefile c:\path_to_where_its_going\filename` 用于将文件从 SD 卡拉取到工作站。
SD 卡上有一些标准化目录,如下表所示:
| 目录常量 | 描述 | 模拟器中的目录 |
| ---- | ---- | ---- |
| DIRECTORY_ALARMS | Android 查找闹钟音频文件的标准目录 | Alarms |
| DIRECTORY_DCIM | 查找相机拍摄图片和视频的行业标准目录 | DCIM |
| DIRECTORY_DOWNLOADS | 存放用户下载文件的标准目录 | Download |
| DIRECTORY_MOVIES | Android 查找电影文件的标准目录 | Movies |
| DIRECTORY_MUSIC | Android 查找普通音乐文件的标准目录 | Music |
| DIRECTORY_NOTIFICATIONS | Android 查找通知音频文件的标准目录 | Notifications |
| DIRECTORY_PICTURES | Android 查找非相机拍摄图片的标准目录 | Pictures |
| DIRECTORY_PODCASTS | Android 查找播客音频文件的标准目录 | Podcasts |
| DIRECTORY_RINGTONES | Android 查找铃声音频文件的标准目录 | Ringtones |
从 Android 1.6 开始,若应用要写入 SD 卡,需在 `AndroidManifest.xml` 文件中添加权限:
```xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
```
#### 3. 播放媒体
##### 3.1 播放音频内容
以下是一个简单的音频播放应用示例,包含布局文件和 Java 代码:
```xml
<!-- /res/layout/main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button android:id="@+id/startPlayerBtn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Start Playing Audio" android:onClick="doClick" />
<Button android:id="@+id/pausePlayerBtn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Pause Player" android:onClick="doClick" />
<Button android:id="@+id/restartPlayerBtn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Restart Player" android:onClick="doClick" />
<Button android:id="@+id/stopPlayerBtn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Stop Player" android:onClick="doClick" />
</LinearLayout>
```
```java
// MainActivity.java
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
public class MainActivity extends Activity
{
static final String AUDIO_PATH =
"http://www.androidbook.com/akc/filestorage/android/documentfiles/3389/play.mp3";
private MediaPlayer mediaPlayer;
private int playbackPosition=0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void doClick(View view) {
switch(view.getId()) {
case R.id.startPlayerBtn:
try {
playAudio(AUDIO_PATH);
} catch (Exception e) {
e.printStackTrace();
}
break;
case R.id.pausePlayerBtn:
if(mediaPlayer != null && mediaPlayer.isPlaying()) {
playbackPosition = mediaPlayer.getCurrentPosition();
mediaPlayer.pause();
}
break;
case R.id.restartPlayerBtn:
if(mediaPlayer != null && !mediaPlayer.isPlaying()) {
mediaPlayer.seekTo(playbackPosition);
mediaPlayer.start();
}
break;
case R.id.stopPlayerBtn:
if(mediaPlayer != null) {
mediaPlayer.stop();
playbackPosition = 0;
}
break;
}
}
private void playAudio(String url) throws Exception
{
killMediaPlayer();
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(url);
mediaPlayer.prepare();
mediaPlayer.start();
}
private void playLocalAudio() throws Exception
{
mediaPlayer = MediaPlayer.create(this, R.raw.music_file);
mediaPlayer.start();
}
private void playLocalAudio_UsingDescriptor() throws Exception {
AssetFileDescriptor fileDesc = getResources().openRawResourceFd(
R.raw.music_file);
if (fileDesc != null) {
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(fileDesc.getFileDescriptor(),
fileDesc.getStartOffset(), fileDesc.getLength());
fileDesc.close();
mediaPlayer.prepare();
mediaPlayer.start();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
killMediaPlayer();
}
private void killMediaPlayer() {
if(mediaPlayer!=null) {
try {
mediaPlayer.release();
}
catch(Exception e) {
e.printStackTrace();
}
}
}
}
```
该示例展示了如何从网络播放音频文件,同时也提供了播放本地音频文件的方法。
##### 3.2 使用 `SoundPool` 同时播放多个音频轨道
`SoundPool` 适合播放少量音频,以实现快速响应。以下是一个使用 `SoundPool` 播放动物声音的示例:
```xml
<!-- /res/layout/main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent" android:layout_height="fill_parent"
>
<ToggleButton android:id="@+id/button"
android:textOn="Pause" android:textOff="Resume"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:onClick="doClick" android:checked="true" />
</LinearLayout>
```
```java
// MainActivity.java
import java.io.IOException;
import android.app.Activity;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.ToggleButton;
public class MainActivity extends Activity implements SoundPool.OnLoadCompleteListener {
private static final int SRC_QUALITY = 0;
private static final int PRIORITY = 1;
private SoundPool soundPool = null;
private AudioManager aMgr;
private int sid_background;
private int sid_roar;
private int sid_bark;
private int sid_chimp;
private int sid_rooster;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onResume() {
soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC,
SRC_QUALITY);
soundPool.setOnLoadCompleteListener(this);
aMgr =
(AudioManager)this.getSystemService(Context.AUDIO_SERVICE);
sid_background = soundPool.load(this, R.raw.crickets, PRIORITY);
sid_chimp = soundPool.load(this, R.raw.chimp, PRIORITY);
sid_rooster = soundPool.load(this, R.raw.rooster, PRIORITY);
sid_roar = soundPool.load(this, R.raw.roar, PRIORITY);
try {
AssetFileDescriptor afd =
this.getAssets().openFd("dogbark.mp3");
sid_bark = soundPool.load(afd.getFileDescriptor(),
0, afd.getLength(), PRIORITY);
afd.close();
} catch (IOException e) {
e.printStackTrace();
}
super.onResume();
}
public void doClick(View view) {
switch(view.getId()) {
case R.id.button:
if(((ToggleButton)view).isChecked()) {
soundPool.autoResume();
}
else {
soundPool.autoPause();
}
break;
}
}
@Override
protected void onPause() {
soundPool.release();
soundPool = null;
super.onPause();
}
@Override
public void onLoadComplete(SoundPool sPool, int sid, int status) {
Log.v("soundPool", "sid " + sid + " loaded with status " +
status);
final float currentVolume =
((float)aMgr.getStreamVolume(AudioManager.STREAM_MUSIC)) /
((float)aMgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC));
if(status != 0)
return;
if(sid == sid_background) {
if(sPool.play(sid, currentVolume, currentVolume,
PRIORITY, -1, 1.0f) == 0)
Log.v("soundPool", "Failed to start sound");
} else if(sid == sid_chimp) {
queueSound(sid, 5000, currentVolume);
} else if(sid == sid_rooster) {
queueSound(sid, 6000, currentVolume);
} else if(sid == sid_roar) {
queueSound(sid, 12000, currentVolume);
} else if(sid == sid_bark) {
queueSound(sid, 7000, currentVolume);
}
}
private void queueSound(final int sid, final long delay,
final float volume)
{
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if(soundPool == null) return;
if(soundPool.play(sid, volume, volume,
PRIORITY, 0, 1.0f) == 0)
Log.v("soundPool", "Failed to start sound (" + sid +
")");
queueSound(sid, delay, volume);
}}, delay);
}
}
```
该示例中,创建 `SoundPool` 需要三个参数:
- 同时播放的最大样本数。
- 音频流类型,通常为 `AudioManager.STREAM_MUSIC`。
- `SRC_QUALITY` 值,应设置为 0。
##### 3.3 其他音频播放方式
- **`JetPlayer`**:适用于游戏,使用 MIDI 定义声音,需使用 `JETCreator` 工具创建声音文件。
- **`AsyncPlayer`**:用于在后台播放音频,无需占用当前线程。示例代码如下:
```java
private static final String TAG = "AsyncPlayerDemo";
private AsyncPlayer mAsync = null;
// ...
mAsync = new AsyncPlayer(TAG);
mAsync.play(this, Uri.parse("file://” + “/perry_ringtone.mp3"),
false, AudioManager.STREAM_MUSIC);
// ...
@Override
protected void onPause() {
mAsync.stop();
super.onPause();
}
```
- **`AudioTrack`**:用于底层音频播放,可对音频播放进行更精细的控制。
#### 4. 播放视频内容
视频播放比音频播放更复杂,Android 提供了 `android.widget.VideoView` 来简化操作。以下是一个播放视频的示例:
```xml
<!-- /res/layout/main.xml -->
<LinearLayout
android:layout_width="fill_parent" android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<VideoView android:id="@+id/videoView"
android:layout_width="200px" android:layout_height="200px" />
</LinearLayout>
```
```java
// MainActivity.java
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.widget.MediaController;
import android.widget.VideoView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
VideoView videoView =
(VideoView)this.findViewById(R.id.videoView);
MediaController mc = new MediaController(this);
videoView.setMediaController(mc);
videoView.setVideoURI(Uri.parse(
"http://www.androidboo
```
0
0
复制全文
相关推荐










