先简要说明下Android支持的视频格式,如下:


由于硬件的不同,不同的手机支持的编解码方式有些不一样,在T-Mobile G1实际设备中增加了对WMA,WMV,H.264AVC格式解码的支持。Android支持的音/视频编码方式仅包括:AMR-NB,H.263,输出的视频格式也只*.3gp或者*.mp4,这点在以后的开发中需要注意。

对Android的编解码有了一些了解后,我们再去研究下如何在Android上来播放/录制视频,打开Android SDK中关于媒体方面的说明,摘要其主要部分如下:

首先注意的就是:MediaPlayer,MediaRecoder,主要是用来播放视频与录制视频的类;由于这2个类都比较复杂,本篇在后面会详细介绍如何使用MediaRecoder,MediaPlayer将在以后篇幅中再详细介绍。
其他的几个类,定义Android支持的编码方式,如下:

说明 编码方式定义
MediaRecorder.AudioEncoder 音频编码当时 AMR_NB:AMR NB编码
MediaRecorder.AudioSource 声音采样设备 MIC:麦克风
MediaRecorder.OutputFormat 录制输出格式 MPEG_4:*.mp4
RAW_AMR:*.amr
THREE_GPP:*.3gp
MediaRecorder.VideoEncoder 视频编码方式 H263:H.263编码
H264:H.264编码
MPEG_4_SP:mp4编码
MediaRecorder.VideoSource 视频采样设备 CAMERA:数码相机
如何使用MediaRecorder录制声音?
先对声音录制有个大致的了解,需要 设置声音 数据的来源、输出编码方式、输出 文件路径、输出文件格式等。有一点需要说明的是:输出文件格式就相当于一个容器,具体采用什么编码需要指定编码格式。编码一样可能输出格式不一样,输出格式一样其编码方式可能不一样。
android.media 包含与媒体子 系统交互的类。使用 android.media.MediaRecorder 类进行媒体采样,包括音频和视频。MediaRecorder 作为状态机 运行。需要设置不同的参数,比如源设备和格式。设置后,可执行任何 时间长度的录制,直到 用户停止。
录制音频主要片段如下:
MediaRecorder mrec ;
File audiofile = null;
private static final String TAG=”SoundRecordingDemo”;
protected void startRecording() throws IOException
{
mrec.setAudioSource(MediaRecorder.AudioSource.MIC);
mrec.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mrec.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
if (mSampleFile == null)
{
File sampleDir = Environment.getExternalStorageDirectory();
try
{
audiofile = File.createTempFile(”ibm”, “.3gp”, sampleDir);
}catch (IOException e)
{
Log.e(TAG,”sdcard access error”);
return;
}
}
mrec.setOutputFile(audiofile.getAbsolutePath());
mrec.prepare();
mrec.start();
}
protected void stopRecording()
{
mrec.stop();
mrec.release();
processaudiofile(audiofile.getAbsolutePath());
}
protected void processAudiofile()
{
ContentValues values = new ContentValues(3);
long current = System.currentTimeMillis();
values.put(MediaStore.Audio.Media.TITLE, “audio” + audiofile.getName());
values.put(MediaStore.Audio.Media.DATE_ADDED, (int) (current / 1000));
values.put(MediaStore.Audio.Media.MIME_TYPE, “audio/3gpp”);
values.put(MediaStore.Audio.Media.DATA, audiofile.getAbsolutePath());
ContentResolver contentResolver = getContentResolver();
Uri base = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Uri newUri = contentResolver.insert(base, values);
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, newUri));
}
对以上 代码解析如下:
  • 在 startRecording 方法中,实例化并初始化 MediaRecorder 的实例。
  • 输入源被设置为麦克风(MIC)。
  • 输出格式被设置为 3GPP(*.3gp 文件),这是移动设备专用的媒体格式。
  • 编码器被设置为 AMR_NB,这是音频格式,采样率为 8 KHz。NB 表示窄频。SDK 文档 解释了不同的数据格式和可用的编码器。
  • 音频文件存储在存储卡而不是内存中。External.getExternalStorageDirectory() 返回存储卡位置的名称,在该目录中将创建一个临时文件名。然后,通过调用 setOutputFile 方法将文件关联到 MediaRecorder 实例。音频数据将存储到该文件中。
  • 调用 prepare 方法完成 MediaRecorder 的初始化。准备开始录制流程时,将调用 start 方法。在调用 stop 方法之前,将对存储卡上的文件进行录制。release 方法将释放分配给 MediaRecorder 实例的资源。
  • 音频采样完成之后, 向设备的媒体库添加该音频。在该代码样例中,processAudiofile 方法将音频添加到媒体库。使用 Intent 通知设备上的媒体应用程序有新内容可用。
  • 最后还需要注意的是,录制声音需要一定的权限,需要向 AndroidManifest.xml 添加权限声明:


<uses-permission android:name=”android.permission.RECORD_AUDIO”></uses-permission>总结说明:

  • Android SDK中对视频开发方面提供了很大的方便,但是在使用的过程中发现,这些类封装的都很高层,很多地方估计也无法满足开发人员的需求,主要体现在缺少对文件流操作等底层接口,我们只能通过控制状态来控制文件流,缺少这方面操作增加了Android视频开发的难度,比如说增加其他编码器等。
  • Android T-Mobile G1可以在线看Youtube视频,然而我们在开发中却发现,其无法播放FLV格式的视频,这就有些不明白了?估计在未来应该会支持的,FLV是当前最流行的流媒体格式,如果不支持对用户在Android上直接看这些FLV视频会有很大的影响。

来自:http://www.360doc.com/content/10/1214/17/474846_78089534.shtml#

android音频eq平衡http://www.j2megame.com/html/xwzx/ty/1519.html

Android 音频均衡器,调节音频EQ

2.3之后,google 为Mediaplayer 类添加了EQ支持,如果你需要使用这个EQ功能,有两点需要注意,分别为如下:

在配置文件中设置最小的SDK版本为9
添加权限Android.permission.RECORD_AUDIO 即可使用,具体的使用方法,下文会介绍
为了使应用程序能够支持波段变化,我们需要重新定义一个VIEW对象,在onDraw 方法画频谱,代码如下:

class VisualizerView extends View {

private byte[] mBytes;
private float[] mPoints;
// 矩形区域
private Rect mRect = new Rect();
// 画笔
private Paint mPaint = new Paint();

// 初始化画笔
private void init() {
mBytes = null;
mPaint.setStrokeWidth(1f);
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLUE);
}

public VisualizerView(Context context) {
super(context);
init();
}

public void updateVisualizer(byte[] mbyte) {
mBytes = mbyte;
invalidate();
}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);

if (mBytes == null) {
return;
}
if (mPoints == null || mPoints.length < mBytes.length * 4) {
mPoints = new float[mBytes.length * 4];
}

mRect.set(0, 0, getWidth(), getHeight());

for (int i = 0; i < mBytes.length - 1; i++) {
mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
mPoints[i * 4 + 1] = mRect.height() / 2
+ ((byte) (mBytes[i] + 128)) * (mRect.height() / 2)
/ 128;
mPoints[i * 4 + 2] = mRect.width() * (i + 1)
/ (mBytes.length - 1);
mPoints[i * 4 + 3] = mRect.height() / 2
+ ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2)
/ 128;
}

canvas.drawLines(mPoints, mPaint);
}
}

另外,为了使用EQ和频谱可视化,我们必须了解以下两个类:

Visualizer
此类能使应用程序获取当前有效的一部分音频可视化的目的。使用此类必须添加上面提到的权限。
Equalizer
一个均衡器的类,使用此类可以轻松的操纵音频的频段,和输出的混合 。
具体使用代码和注释见下面:

/**
* 通过mMediaPlayer返回的AudioSessionId创建一个优先级为0均衡器对象 并且通过频谱生成相应的UI和对应的事件
*/
private void setupEqualizeFxAndUi() {
mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());
mEqualizer.setEnabled(true);// 启用均衡器
TextView eqTextView = new TextView(this);
eqTextView.setText("均衡器:");
mLayout.addView(eqTextView);

// 通过均衡器得到其支持的频谱引擎
short bands = mEqualizer.getNumberOfBands();

// getBandLevelRange 是一个数组,返回一组频谱等级数组,
// 第一个下标为最低的限度范围
// 第二个下标为最大的上限,依次取出
final short minEqualizer = mEqualizer.getBandLevelRange()[0];
final short maxEqualizer = mEqualizer.getBandLevelRange()[1];

for (short i = 0; i < bands; i++) {
final short band = i;

TextView freqTextView = new TextView(this);
freqTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));

freqTextView.setGravity(Gravity.CENTER_HORIZONTAL);

// 取出中心频率
freqTextView
.setText((mEqualizer.getCenterFreq(band) / 1000) + "HZ");
mLayout.addView(freqTextView);

LinearLayout row = new LinearLayout(this);
row.setOrientation(LinearLayout.HORIZONTAL);

TextView minDbTextView = new TextView(this);
minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));

minDbTextView.setText((minEqualizer / 100) + " dB");

TextView maxDbTextView = new TextView(this);
maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
maxDbTextView.setText((maxEqualizer / 100) + " dB");

LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);

layoutParams.weight = 1;

SeekBar seekbar = new SeekBar(this);
seekbar.setLayoutParams(layoutParams);
seekbar.setMax(maxEqualizer - minEqualizer);
seekbar.setProgress(mEqualizer.getBandLevel(band));

seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}

@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
mEqualizer.setBandLevel(band,
(short) (progress + minEqualizer));
}
});
row.addView(minDbTextView);
row.addView(seekbar);
row.addView(maxDbTextView);

mLayout.addView(row);
}

}

/**
* 生成一个VisualizerView对象,使音频频谱的波段能够反映到 VisualizerView上
*/
private void setupVisualizerFxAndUi() {
mVisualizerView = new VisualizerView(this);
mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
(int) (VISUALIZER_HEIGHT_DIP * getResources()
.getDisplayMetrics().density)));
mLayout.addView(mVisualizerView);

mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
// 参数内必须是2的位数
mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);

// 设置允许波形表示,并且捕获它
mVisualizer.setDataCaptureListener(new OnDataCaptureListener() {

@Override
public void onWaveFormDataCapture(Visualizer visualizer,
byte[] waveform, int samplingRate) {
// TODO Auto-generated method stub
mVisualizerView.updateVisualizer(waveform);
}

@Override
public void onFftDataCapture(Visualizer visualizer, byte[] fft,
int samplingRate) {
// TODO Auto-generated method stub

}
}, Visualizer.getMaxCaptureRate() / 2, true, false);

}

进入程序后,在程序入口加载如下代码:

mStatusTextView = new TextView(this);
mLayout = new LinearLayout(this);
mLayout.setOrientation(LinearLayout.VERTICAL);
mLayout.addView(mStatusTextView);
setContentView(mLayout);

mMediaPlayer = MediaPlayer.create(this, R.raw.eason);

setupVisualizerFxAndUi();
setupEqualizeFxAndUi();

mVisualizer.setEnabled(true);
mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {

@Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
mVisualizer.setEnabled(false);
}
});

mMediaPlayer.start();
mStatusTextView.setText("播放中。。。");

2.3之后,google 为Mediaplayer 类添加了EQ支持,如果你需要使用这个EQ功能,有两点需要注意,分别为如下:

在配置文件中设置最小的SDK版本为9
添加权限Android.permission.RECORD_AUDIO 即可使用,具体的使用方法,下文会介绍
为了使应用程序能够支持波段变化,我们需要重新定义一个VIEW对象,在onDraw 方法画频谱,代码如下:

class VisualizerView extends View {

private byte[] mBytes;
private float[] mPoints;
// 矩形区域
private Rect mRect = new Rect();
// 画笔
private Paint mPaint = new Paint();

// 初始化画笔
private void init() {
mBytes = null;
mPaint.setStrokeWidth(1f);
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLUE);
}

public VisualizerView(Context context) {
super(context);
init();
}

public void updateVisualizer(byte[] mbyte) {
mBytes = mbyte;
invalidate();
}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);

if (mBytes == null) {
return;
}
if (mPoints == null || mPoints.length < mBytes.length * 4) {
mPoints = new float[mBytes.length * 4];
}

mRect.set(0, 0, getWidth(), getHeight());

for (int i = 0; i < mBytes.length - 1; i++) {
mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
mPoints[i * 4 + 1] = mRect.height() / 2
+ ((byte) (mBytes[i] + 128)) * (mRect.height() / 2)
/ 128;
mPoints[i * 4 + 2] = mRect.width() * (i + 1)
/ (mBytes.length - 1);
mPoints[i * 4 + 3] = mRect.height() / 2
+ ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2)
/ 128;
}

canvas.drawLines(mPoints, mPaint);
}
}

另外,为了使用EQ和频谱可视化,我们必须了解以下两个类:

Visualizer
此类能使应用程序获取当前有效的一部分音频可视化的目的。使用此类必须添加上面提到的权限。
Equalizer
一个均衡器的类,使用此类可以轻松的操纵音频的频段,和输出的混合 。
具体使用代码和注释见下面:

/**
* 通过mMediaPlayer返回的AudioSessionId创建一个优先级为0均衡器对象 并且通过频谱生成相应的UI和对应的事件
*/
private void setupEqualizeFxAndUi() {
mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());
mEqualizer.setEnabled(true);// 启用均衡器
TextView eqTextView = new TextView(this);
eqTextView.setText("均衡器:");
mLayout.addView(eqTextView);

// 通过均衡器得到其支持的频谱引擎
short bands = mEqualizer.getNumberOfBands();

// getBandLevelRange 是一个数组,返回一组频谱等级数组,
// 第一个下标为最低的限度范围
// 第二个下标为最大的上限,依次取出
final short minEqualizer = mEqualizer.getBandLevelRange()[0];
final short maxEqualizer = mEqualizer.getBandLevelRange()[1];

for (short i = 0; i < bands; i++) {
final short band = i;

TextView freqTextView = new TextView(this);
freqTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));

freqTextView.setGravity(Gravity.CENTER_HORIZONTAL);

// 取出中心频率
freqTextView
.setText((mEqualizer.getCenterFreq(band) / 1000) + "HZ");
mLayout.addView(freqTextView);

LinearLayout row = new LinearLayout(this);
row.setOrientation(LinearLayout.HORIZONTAL);

TextView minDbTextView = new TextView(this);
minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));

minDbTextView.setText((minEqualizer / 100) + " dB");

TextView maxDbTextView = new TextView(this);
maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
maxDbTextView.setText((maxEqualizer / 100) + " dB");

LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);

layoutParams.weight = 1;

SeekBar seekbar = new SeekBar(this);
seekbar.setLayoutParams(layoutParams);
seekbar.setMax(maxEqualizer - minEqualizer);
seekbar.setProgress(mEqualizer.getBandLevel(band));

seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}

@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
mEqualizer.setBandLevel(band,
(short) (progress + minEqualizer));
}
});
row.addView(minDbTextView);
row.addView(seekbar);
row.addView(maxDbTextView);

mLayout.addView(row);
}

}

/**
* 生成一个VisualizerView对象,使音频频谱的波段能够反映到 VisualizerView上
*/
private void setupVisualizerFxAndUi() {
mVisualizerView = new VisualizerView(this);
mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
(int) (VISUALIZER_HEIGHT_DIP * getResources()
.getDisplayMetrics().density)));
mLayout.addView(mVisualizerView);

mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
// 参数内必须是2的位数
mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);

// 设置允许波形表示,并且捕获它
mVisualizer.setDataCaptureListener(new OnDataCaptureListener() {

@Override
public void onWaveFormDataCapture(Visualizer visualizer,
byte[] waveform, int samplingRate) {
// TODO Auto-generated method stub
mVisualizerView.updateVisualizer(waveform);
}

@Override
public void onFftDataCapture(Visualizer visualizer, byte[] fft,
int samplingRate) {
// TODO Auto-generated method stub

}
}, Visualizer.getMaxCaptureRate() / 2, true, false);

}

进入程序后,在程序入口加载如下代码:

mStatusTextView = new TextView(this);
mLayout = new LinearLayout(this);
mLayout.setOrientation(LinearLayout.VERTICAL);
mLayout.addView(mStatusTextView);
setContentView(mLayout);

mMediaPlayer = MediaPlayer.create(this, R.raw.eason);

setupVisualizerFxAndUi();
setupEqualizeFxAndUi();

mVisualizer.setEnabled(true);
mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {

@Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
mVisualizer.setEnabled(false);
}
});

mMediaPlayer.start();
mStatusTextView.setText("播放中。。。");

Android平台中应该如何获取音乐文件的信息

Android系统提供了MediaScanner,MediaProvider,MediaStore等接口,并且提供了一套数据库表格,通过Content Provider的方式提供给用户。当手机开机或者有SD卡插拔等事件发生时,系统将会自动扫描SD卡和手机内存上的媒体文件,如audio,video,图片等,将相应的信息放到定义好的数据库表格中。在这个程序中,我们不需要关心如何去扫描手机中的文件,只要了解如何查询和使用这些信息就可以了。
MediaStore中定义了一系列的数据表格,通过ContentResolver提供的查询接口,我们可以得到各种需要的信息。下面我们重点介绍查询SD卡上的音乐文件信息。
先来了解一下ContentResolver的查询接口:

Cursorquery(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);

Uri:指明要查询的数据库名称加上表的名称,从MediaStore中我们可以找到相应信息的参数,具体请参考 开发文档。
Projection: 指定查询数据库表中的哪几列,返回的游标中将包括相应的信息。Null则返回所有信息。
selection: 指定查询条件
selectionArgs:参数selection里有 ?这个符号是,这里可以以实际值代替这个问号。如果selection这个没有?的话,那么这个String数组可以为null。
SortOrder:指定查询结果的排列顺序
下面的命令将返回所有在外部存储卡上的音乐文件的信息:
Cursor cursor = query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
得到cursor后,我们可以调用Cursor的相关方法具体的音乐信息:

歌曲ID:MediaStore.Audio.Media._ID

Int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));

歌曲的名称 :MediaStore.Audio.Media.TITLE

String tilte = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));

歌曲的专辑名:MediaStore.Audio.Media.ALBUM

String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));


歌曲的歌手名: MediaStore.Audio.Media.ARTIST
String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));

歌曲文件的路径 :MediaStore.Audio.Media.DATA

String url = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));

歌曲的总播放时长 :MediaStore.Audio.Media.DURATION

Int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));

歌曲文件的大小 :MediaStore.Audio.Media.SIZE

Int size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));

一些歌词处理的文章:http://blog.csdn.net/dany1202/article/details/6533513

更多相关文章

  1. Android中的音频播放(MediaPlayer和SoundPool)
  2. Android(安卓)音频播放速率调整实现
  3. android中Media Playback(媒体播放)
  4. Android(安卓)App中使用AudioManager类来编写音频播放器
  5. Android学习笔记-1.Android工程结构
  6. Android音频开发之AudioRecord录音实现
  7. Android(安卓)Mediarecorder录制的时候屏蔽掉声音
  8. Android音频架构概览
  9. Android如何获取assets或者raw目录的视频文件路径播放视频

随机推荐

  1. Android文件系统的结构及目录用途、操作
  2. Google Issues Cease & Desist to Open S
  3. Android(安卓)命名空间和自定义属性
  4. Android的IPC机制Binder的详解汇总
  5. 【ncnn android】算法移植(九)——DBface a
  6. 在Android中如何让gif动起来
  7. android 静音与振动
  8. android 和 lucene
  9. Android类加载器源码分析
  10. Android与unity交互