把一個音視訊檔案的視訊部分抽取出來播放
阿新 • • 發佈:2019-01-25
知識結構
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;只有多次練習,我們才能熟練使用;