【Android 多媒体应用】使用MediaCodec解码使用AudioTrack播放音频数据
1.MainActivity.java
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button; import java.io.IOException; public class MainActivity extends Activity { private static final String SAMPLE = Environment.getExternalStorageDirectory() + "/test.aac";
protected static AudioDecoderThread mAudioDecoder;
private Button btn; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.play);
mAudioDecoder = new AudioDecoderThread();
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
try {
mAudioDecoder.startPlay(SAMPLE);
} catch (IOException e) {
e.printStackTrace();
} }
}); } @Override
protected void onStop() {
super.onStop();
mAudioDecoder.stop();
} }
2.AudioDecoderThread.java
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.util.Log; import java.io.IOException;
import java.nio.ByteBuffer; public class AudioDecoderThread {
private static final int TIMEOUT_US = 1000;
private MediaExtractor mExtractor;
private MediaCodec mDecoder; private boolean eosReceived;
private int mSampleRate = 0;
int channel = 0;
private final String TAG = "AACPlay";
public void startPlay(String path) throws IOException {
eosReceived = false;
//创建MediaExtractor对象用来解AAC封装
mExtractor = new MediaExtractor();
try {
//设置需要MediaExtractor解析的文件的路径
mExtractor.setDataSource(path);
} catch (IOException e) {
e.printStackTrace();
} MediaFormat format = mExtractor.getTrackFormat(0);
if (format == null)
{
Log.e(TAG,"format is null");
return;
} //判断当前帧的文件类型是否为audio
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("audio/")) {
Log.d(TAG, "format : " + format);
//获取当前帧的采样率
mExtractor.selectTrack(0);
mSampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
//获取当前帧的通道数
channel = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
//音频文件长度
long duration = format.getLong(MediaFormat.KEY_DURATION);
Log.d(TAG,"length:"+duration/1000000);
} //创建MediaCodec对象
mDecoder = MediaCodec.createDecoderByType(mime);
//配置MediaCodec
mDecoder.configure(format, null, null, 0); if (mDecoder == null) {
Log.e(TAG, "Can't find video info!");
return;
}
//启动MediaCodec
mDecoder.start(); new Thread(AACDecoderAndPlayRunnable).start();
} Runnable AACDecoderAndPlayRunnable = new Runnable() { @Override
public void run() {
AACDecoderAndPlay();
}
}; public void AACDecoderAndPlay() {
ByteBuffer[] inputBuffers = mDecoder.getInputBuffers();
ByteBuffer[] outputBuffers = mDecoder.getOutputBuffers(); BufferInfo info = new BufferInfo(); int buffsize = AudioTrack.getMinBufferSize(mSampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
// 创建AudioTrack对象
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, mSampleRate,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
buffsize,
AudioTrack.MODE_STREAM);
//启动AudioTrack
audioTrack.play(); while (!eosReceived) {
int inIndex = mDecoder.dequeueInputBuffer(TIMEOUT_US);
if (inIndex >= 0) {
ByteBuffer buffer = inputBuffers[inIndex];
//从MediaExtractor中读取一帧待解数据
int sampleSize = mExtractor.readSampleData(buffer, 0);
if (sampleSize < 0) {
// We shouldn't stop the playback at this point, just pass the EOS
// flag to mDecoder, we will get it again from the
// dequeueOutputBuffer
Log.d(TAG, "InputBuffer BUFFER_FLAG_END_OF_STREAM");
mDecoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); } else {
//向MediaDecoder输入一帧待解码数据
mDecoder.queueInputBuffer(inIndex, 0, sampleSize, mExtractor.getSampleTime(), 0);
mExtractor.advance();
}
//从MediaDecoder队列取出一帧解码后的数据
int outIndex = mDecoder.dequeueOutputBuffer(info, TIMEOUT_US);
switch (outIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
Log.d(TAG, "INFO_OUTPUT_BUFFERS_CHANGED");
outputBuffers = mDecoder.getOutputBuffers();
break; case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
MediaFormat format = mDecoder.getOutputFormat();
Log.d(TAG, "New format " + format);
audioTrack.setPlaybackRate(format.getInteger(MediaFormat.KEY_SAMPLE_RATE)); break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
Log.d(TAG, "dequeueOutputBuffer timed out!");
break; default:
ByteBuffer outBuffer = outputBuffers[outIndex];
//Log.v(TAG, "outBuffer: " + outBuffer); final byte[] chunk = new byte[info.size];
// Read the buffer all at once
outBuffer.get(chunk);
//清空buffer,否则下一次得到的还会得到同样的buffer
outBuffer.clear();
// AudioTrack write data
audioTrack.write(chunk, info.offset, info.offset + info.size);
mDecoder.releaseOutputBuffer(outIndex, false);
break;
} // 所有帧都解码、播放完之后退出循环
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
Log.d(TAG, "OutputBuffer BUFFER_FLAG_END_OF_STREAM");
break;
}
}
} //释放MediaDecoder资源
mDecoder.stop();
mDecoder.release();
mDecoder = null; //释放MediaExtractor资源
mExtractor.release();
mExtractor = null; //释放AudioTrack资源
audioTrack.stop();
audioTrack.release();
audioTrack = null;
} public void stop() {
eosReceived = true;
} }
3.activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <Button
android:id="@+id/play"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Play" /> </LinearLayout>
【Android 多媒体应用】使用MediaCodec解码使用AudioTrack播放音频数据的更多相关文章
- Android多媒体框架总结(1) - 利用MediaMuxer合成音视频数据流程分析
场景介绍: 设备端通过服务器传向客户端(Android手机)实时发送视频数据(H.264)和音频数据(g711a或g711u), 需要在客户端将音视频数据保存为MP4文件存放在本地,用户可以通过APP ...
- Android 音视频开发(三):使用 AudioTrack 播放PCM音频
一.AudioTrack 基本使用 AudioTrack 类可以完成Android平台上音频数据的输出任务.AudioTrack有两种数据加载模式(MODE_STREAM和MODE_STATIC),对 ...
- Android音视频之AudioTrack播放音频(二)
前一篇讲了如何录制wav音频文件,本篇就来讲讲如何播放wav文件,这里就是使用AudioTrack来播放音频,确切的说是播放pcm格式数据,使用AudioTrack播放也没什么难度,主要就是将数据写入 ...
- Android 音视频开发(二):使用 AudioRecord 采集音频数据并保存到文件
版权声明:转载请说明出处:http://www.cnblogs.com/renhui/p/7457321.html 一.AudioRecord API详解 AudioRecord是Android系统提 ...
- Android学习总结(十六) ———— MediaPlayer播放音频与视频
一.基本概念 本文主要介绍的是Android中很重要也最为复杂的媒体播放器(MediaPlayer)部分的架构.Android的MediaPlayer包含了Audio和video的播放功能,在Andr ...
- 【Android 多媒体应用】使用MediaRecoder录制,MediaPlayer播放音频数据
1.MainActivity.java import android.annotation.TargetApi; import android.app.Activity; import android ...
- 【Android】实验6 在应用程序中播放音频和视频 截止提交报告时间2016.4.21
注:也可以在数独游戏项目中完成该实验的内容.
- 使用AudioTrack播放PCM音频数据(android)
众所周知,Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用MediaPlayer实现的.MediaPl ...
- Android 音视频深入 二 AudioTrack播放pcm(附源码下载)
本篇项目地址,名字是录音和播放PCM,求starhttps://github.com/979451341/Audio-and-video-learning-materials 1.AudioTrack ...
随机推荐
- MySQL Innodb 神秘消失
问题描述: 早晨接到 Zabbix 报警,提示 Host: 10.10.1.2, MySQL 主从同步失败. 登录服务器查看具体情况. shell > mysql mysql> show ...
- 【冷门】 C# 小技巧之获取变量名称
今天在自我规范程序设计的时候,变量名匹配字符串来自配置文件,网上找了一会儿发现也有朋友在找寻这种方式,很不容易找到一个解决方案来自http://www.th7.cn/Program/net/20140 ...
- 关于 jdbc 的错误
- IEnumerator & IEnumerable
[IEnumerator] 用于遍历一个对象,IEnumerator在System.Collections命名空间中. public interface IEnumerator { object Cu ...
- Struts2项目走向流转
----------------siwuxie095 Struts2 项目走向流转 1.HTTP 请求流转过程 2.配置文件连接点详解 [made by siwuxie095]
- python中函数作用域
在python中,一个函数就是一个作用域 name = 'xiaoyafei' def change_name(): name = 'sthu' print('在change_name里的name:' ...
- Ajax与Controller的参数交互
理论 jQuery.ajax( options )中重要参数设置 jQuery.ajax( options ) : 通过 HTTP 请求加载远程数据.通过jquery.ajax与SpringMVC的C ...
- Java 读取jar内的文件的超简便方法
坑爹的java课程设计,偏要用jar来运行 读取.存储jar内文件的支持也好低 存储方法: 进入jar文件其实没有说的那么困难,jar文件本质是一个zip格式的压缩文件,只是把文件后缀名改了,要用Ja ...
- 用Collections升降排序
//期末从业人员 总收入 资产总计等 升降 排序 if("qmcyry".equals(sss)){ if("desc".equals(orders)){ Co ...
- 斐波那契数列—java实现
最近在面试的时候被问到了斐波那契数列,而且有不同的实现方式,就在这里记录一下. 定义 斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...