知识结构
MediaCodec: Android中直播视频技术探究之—基础知识大纲介绍、MediaCodec文档翻译
详细介绍了MediaCodec的用法;在这里我们只使用MediaCodec的解码的功能;
mMediaCodec.configure(mMediaFormat, mSurface, null, 0);我们把SurfaceView.getSurface()传给它,就能把视频在SurfaceView上播放;
MediaExtractor: 实现把一个音频文件的视频抽取出来这里已经详细介绍了MediaExtractor的用处,这里不再累述;
步骤
1、创建一个SurfaceView
mSurfaceView = (SurfaceView) this.findViewById(R.id.mSurfaceView);
mSurfaceView.getHolder().addCallback(this);
2、在SurfaceView的Surface创建成功后开启一个线程执行MediaExtractor抽取视频,在MediaCodec进行解码;
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
mSurfaceHolder = holder;
if(null == mPlayerThread){
mPlayerThread = new Thread(new PlayerRunnable(mSurfaceHolder.getSurface()));
mPlayerThread.start();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if(null != mPlayerThread){
mPlayerThread.interrupt();
}
}
3、最重要的:MediaExtractor与MediaCodec的组合
private class PlayerRunnable implements Runnable{
private MediaExtractor mMediaExtractor;
private MediaCodec mMediaCodec;
private Surface mSurface ;
public PlayerRunnable(Surface surface) {
this.mSurface = surface;
}
@Override
public void run() {
try {
mMediaExtractor = new MediaExtractor();
String filePath = new File(Environment.getExternalStorageDirectory(), "/input.mp4").getPath();
mMediaExtractor.setDataSource(filePath);
int trackCount = mMediaExtractor.getTrackCount();
for(int i=0; i<trackCount; i++){
MediaFormat mMediaFormat = mMediaExtractor.getTrackFormat(i);
String mime = mMediaFormat.getString(MediaFormat.KEY_MIME);
if(mime.startsWith("video/")){
mMediaExtractor.selectTrack(i);
mMediaCodec = MediaCodec.createDecoderByType(mime);
mMediaCodec.configure(mMediaFormat, mSurface, null, 0);
break;
}
}
if(null == mMediaCodec){
Log.d("MainActivity","dont't find mediaformat info;");
return ;
}
mMediaCodec.start();
ByteBuffer[] inputBuffers = mMediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mMediaCodec.getOutputBuffers();
boolean isEOS = false;
BufferInfo info = new BufferInfo();
long startMs = System.currentTimeMillis();
while(!Thread.interrupted()){
if(!isEOS){
int inputBufferIndex = mMediaCodec.dequeueInputBuffer(10000);
if(inputBufferIndex >= 0){
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
int readSampleSize = mMediaExtractor.readSampleData(inputBuffer, 0);
if(readSampleSize < 0){
//此时表明Video数据我们已经抽取完毕
mMediaCodec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
isEOS = true;
} else {
mMediaCodec.queueInputBuffer(inputBufferIndex, 0, readSampleSize, mMediaExtractor.getSampleTime(), 0);
mMediaExtractor.advance();
}
}
}
int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(info, 10000);
switch (outputBufferIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
outputBuffers = mMediaCodec.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
Log.d("MainActivity", "New format " + mMediaCodec.getOutputFormat());
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
Log.d("MainActivity", "dequeueOutputBuffer timed out!");
break;
default:
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
while (info.presentationTimeUs / 1000 > System.currentTimeMillis() - startMs) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
mMediaCodec.releaseOutputBuffer(outputBufferIndex, true);
break;
}
}
mMediaCodec.stop();
mMediaCodec.release();
mMediaExtractor.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
总结
上面的代码主要是练习这几天学习的MediaCodec、MediaExtractor;只有多次练习,我们才能熟练使用;
Demo实例下载:DecodeVideoFileDemo