MediaExtractor API介绍
MediaExtrator的作用是把音频跟视频数据进行分离。
主要API介绍:
setDataSource(String path):可以设置本地文件又可以设置网络文件
getTrackCount():得到源文件通道数
getTrackFormat(int index):获取指定的通道格式
getSampleTime():返回当前的时间戳
readSampleData(ByteBuffer byteBuffer,int offset):把指定通道中的数据按偏移量读取到ByteBuffer中。
advance():读取下一帧数据
release():读取结束后释放资源
使用示例,分离MP4中的音视频,将视频保存为h264文件,将音频保存为aac文件:
public class MediaExtractorUtils
{
private MediaExtractor mediaExtractor;
private WeakReference<Context> mContext;
public MediaExtractorUtils(Context context)
{
mContext = new WeakReference<Context>(context);
}
public void exactorMedia(String videoPath)
{
FileOutputStream outputVideo = null;
FileOutputStream outputAudio = null;
MediaExtractor mediaExtractor = new MediaExtractor();
//分离的视频文件
File videoFile = new File(videoPath, "output_video.h264");
//分离的音频文件
File audioFile = new File(videoPath, "output_audio.aac");
try
{
outputVideo = new FileOutputStream(videoFile);
outputAudio = new FileOutputStream(audioFile);
mediaExtractor.setDataSource(videoPath + "/1.mp4");
int trackCount = mediaExtractor.getTrackCount();
int videoTrackCount = -1;
int audioTrackCount = -1;
for (int i = 0; i < trackCount; i++)
{
MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
if (mimeType.startsWith("video/"))
videoTrackCount = i;
else if (mimeType.startsWith("audio/"))
audioTrackCount = i;
}
ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 500);
//切换到视频信道
mediaExtractor.selectTrack(videoTrackCount);
while (true)
{
int readSampleData = mediaExtractor.readSampleData(byteBuffer, 0);
if (readSampleData < 0)
{
break;
}
byte[] buffer = new byte[readSampleData];
byteBuffer.get(buffer);
outputVideo.write(buffer);
byteBuffer.clear();
mediaExtractor.advance();
}
//切换到音频信道
mediaExtractor.selectTrack(audioTrackCount);
while (true)
{
int readSampleData = mediaExtractor.readSampleData(byteBuffer, 0);
if (readSampleData < 0)
{
break;
}
byte[] buffer = new byte[readSampleData];
byteBuffer.get(buffer);
//给aac添加adts头
byte[] aacAudioBuffer = new byte[readSampleData + 7];
addADTStoPacket(aacAudioBuffer, readSampleData + 7);
System.arraycopy(buffer, 0, aacAudioBuffer, 7, readSampleData);
outputAudio.write(aacAudioBuffer);
byteBuffer.clear();
mediaExtractor.advance();
}
} catch (FileNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
} finally
{
mediaExtractor.release();
mediaExtractor = null;
try
{
outputVideo.close();
outputAudio.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
private static void addADTStoPacket(byte[] packet, int packetLen)
{
int profile = 1; // AAC LC
int freqIdx = getFreqIdx(24000);
int chanCfg = 2; // CPE
// fill in ADTS data
packet[0] = (byte) 0xFF;
packet[1] = (byte) 0xF9;
packet[2] = (byte) (((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2));
packet[3] = (byte) (((chanCfg & 3) << 6) + (packetLen >> 11));
packet[4] = (byte) ((packetLen & 0x7FF) >> 3);
packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);
packet[6] = (byte) 0xFC;
}
private static int getFreqIdx(int sampleRate)
{
int freqIdx;
switch (sampleRate)
{
case 96000:
freqIdx = 0;
break;
case 88200:
freqIdx = 1;
break;
case 64000:
freqIdx = 2;
break;
case 48000:
freqIdx = 3;
break;
case 44100:
freqIdx = 4;
break;
case 32000:
freqIdx = 5;
break;
case 24000:
freqIdx = 6;
break;
case 22050:
freqIdx = 7;
break;
case 16000:
freqIdx = 8;
break;
case 12000:
freqIdx = 9;
break;
case 11025:
freqIdx = 10;
break;
case 8000:
freqIdx = 11;
break;
case 7350:
freqIdx = 12;
break;
default:
freqIdx = 8;
break;
}
return freqIdx;
}
}