SurfaceView surfaceView;
SurfaceHolder holder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView = findViewById(R.id.surfaceView);
holder = surfaceView.getHolder();
/**
* 视频输入
*/
VideoThread videoThread = new VideoThread(holder);
videoThread.start();
/**
* 音频输入
*/
SecondThread secondThread = new SecondThread();
secondThread.start();
}
}
class VideoThread extends Thread{
private SurfaceHolder holder;
public VideoThread(SurfaceHolder holder){
this.holder = holder;
}
@Override
public void run() {
try {
final MediaExtractor extractor = new MediaExtractor();
//设置视频地址
String path = Environment.getExternalStorageDirectory().getPath() + "/h265.mp4";
extractor.setDataSource(path);
extractor.seekTo(5000, SEEK_TO_NEXT_SYNC);
//Count the number of tracks found in the data source.信道总数一般为2 一个视频一个音频
int numTrack = extractor.getTrackCount();
for (int i = 0; i < numTrack; i++) {
//Get the track format at the specified index
final MediaFormat format = extractor.getTrackFormat(i);
//得到数据信息 1.video/avc 2.audio/mp4a-latm
String mimetype = format.getString(MediaFormat.KEY_MIME);
Log.d("tag", mimetype);
if (mimetype.startsWith("video")) {
//选择频道
extractor.selectTrack(i);
final MediaCodec mediaCodec = MediaCodec.createDecoderByType(mimetype);
// mPlayer = new AudioPlayer(format.getInteger(MediaFormat.KEY_SAMPLE_RATE), AudioFormat
// .CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
// mPlayer.init();
holder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
mediaCodec.configure(format, holder.getSurface(), null, 0);
// outputFormat = format;
mediaCodec.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
mediaCodec.setCallback(new MediaCodec.Callback() {
@Override
public void onInputBufferAvailable(MediaCodec codec, int index) {
ByteBuffer inputBuffer = codec.getInputBuffer(index);
inputBuffer.clear();
int readlen = extractor.readSampleData(inputBuffer, 0);
Log.d("tag", "视频输入" + inputBuffer.toString());
codec.queueInputBuffer(index, 0, readlen, 0, 0);
extractor.advance();//Advance to the next sample.进入下一帧 刷新
}
@Override
public void onOutputBufferAvailable(MediaCodec codec, int index, MediaCodec.BufferInfo info) {
Log.d("tag", "onOutputBufferAvailable:" + info.size);
ByteBuffer outputBuffer = codec.getOutputBuffer(index);
MediaFormat outformat = codec.getOutputFormat();
if (outputBuffer != null && info.size > 0) {
byte[] buffer = new byte[outputBuffer.remaining()];
outputBuffer.get(buffer);
// mPlayer.play(buffer,0,info.size);
Log.d("tag", "Offer to queue failed, queue in full state");
}
codec.releaseOutputBuffer(index, true);
}
@Override
public void onError(MediaCodec codec, MediaCodec.CodecException e) {
Log.d("tag", "onError:" + e.getDiagnosticInfo());
}
@Override
public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
Log.d("tag", "onOutputFormatChanged:");
// outputFormat = format;
}
});
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class SecondThread extends Thread{
AudioPlayer mPlayer;
@Override
public void run() {
try {
final MediaExtractor extractor = new MediaExtractor();
//设置视频地址
String path = Environment.getExternalStorageDirectory().getPath() + "/h265.mp4";
extractor.setDataSource(path);
extractor.seekTo(5000, SEEK_TO_NEXT_SYNC);
//Count the number of tracks found in the data source.信道总数一般为2 一个视频一个音频
int numTrack = extractor.getTrackCount();
for (int i = 0; i < numTrack; i++) {
//Get the track format at the specified index
final MediaFormat format = extractor.getTrackFormat(i);
//得到数据信息 1.video/avc 2.audio/mp4a-latm
String mimetype = format.getString(MediaFormat.KEY_MIME);
Log.d("tag", mimetype);
if (mimetype.startsWith("audio")) {
//选择频道
extractor.selectTrack(i);
final MediaCodec mediaCodec = MediaCodec.createDecoderByType(mimetype);
mPlayer = new AudioPlayer(format.getInteger(MediaFormat.KEY_SAMPLE_RATE), AudioFormat
.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
mPlayer.init();
mediaCodec.setCallback(new MediaCodec.Callback() {
@Override
public void onInputBufferAvailable(MediaCodec codec, int index) {
ByteBuffer inputBuffer = codec.getInputBuffer(index);
inputBuffer.clear();
int readlen = extractor.readSampleData(inputBuffer, 0);
Log.d("tag", "音频输入" + inputBuffer.toString());
codec.queueInputBuffer(index, 0, readlen, 0, 0);
extractor.advance();//Advance to the next sample.进入下一帧 刷新
}
@Override
public void onOutputBufferAvailable(MediaCodec codec, int index, MediaCodec.BufferInfo info) {
Log.d("tag", "onOutputBufferAvailable:" + info.size);
ByteBuffer outputBuffer = codec.getOutputBuffer(index);
MediaFormat outformat = codec.getOutputFormat();
if (outputBuffer != null && info.size > 0) {
byte[] buffer = new byte[outputBuffer.remaining()];
outputBuffer.get(buffer);
mPlayer.play(buffer, 0, info.size);
Log.d("tag", "Offer to queue failed, queue in full state");
}
codec.releaseOutputBuffer(index, true);
}
@Override
public void onError(MediaCodec codec, MediaCodec.CodecException e) {
Log.d("tag", "onError:" + e.getDiagnosticInfo());
}
@Override
public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
Log.d("tag", "onOutputFormatChanged:");
// outputFormat = format;
}
});
mediaCodec.configure(format, null, null, 0);
// outputFormat = format;
mediaCodec.start();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public class AudioPlayer {
private int mFrequency;// 采样率
private int mChannel;// 声道
private int mSampBit;// 采样精度
private AudioTrack mAudioTrack;
public AudioPlayer(int frequency, int channel, int sampbit) {
this.mFrequency = frequency;
this.mChannel = channel;
this.mSampBit = sampbit;
}
/**
* 初始化
*/
public void init() {
if (mAudioTrack != null) {
release();
}
// 获得构建对象的最小缓冲区大小
int minBufSize = AudioTrack.getMinBufferSize(mFrequency, mChannel, mSampBit);
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
mFrequency, mChannel, mSampBit, minBufSize, AudioTrack.MODE_STREAM);
mAudioTrack.play();
}
/**
* 释放资源
*/
private void release() {
if (mAudioTrack != null) {
mAudioTrack.stop();
mAudioTrack.release();
}
}
/**
* 将解码后的pcm数据写入audioTrack播放
*
* @param data 数据
* @param offset 偏移
* @param length 需要播放的长度
*/
public void play(byte[] data, int offset, int length) {
if (data == null || data.length == 0) {
return;
}
try {
mAudioTrack.write(data, offset, length);
} catch (Exception e) {
e.printStackTrace();
}
}
}