android 解析mp3文件格式,Android音频学习之利用MediaMuxer从视频中提取视频音频文件和合并视频,音频文件...

1 MediaMuxer 说明

前面利用MediaExtractor提取的aac和.h264文件不经过处理没办法播放,这次利用MediaExtractor和MediaMuxer配合提取合并生成可以播放的文件,ps:aac文件和.h264需要首先利用MediaMuxer生成MP4文件,才能进行合并。

MediaMuxer从api18开始提供,可以封装编码后的视频流和音频流到视频文件中。目前MediaMuxer支持的文件输出格式包括MP4,webm和3gp.

构造函数:

MediaMuxer(String path, int format)

MediaMuxer(FileDescriptor fd, int format)

参数说明:

两个构造函数都需要一个文件路径,和一个format。

**path,fd:**用于存放合成的文件的路径,不能为null。

**format:**输出的文件的格式,OutputFormat中的常量标识。

输出格式:

OutputFormat中包含四种:

MUXER_OUTPUT_3GPP:对应3gp文件,

MUXER_OUTPUT_HEIF:定影HEIF文件,

MUXER_OUTPUT_MPEG_4:对应mp4文件,

MUXER_OUTPUT_WEBM:对应webm文件。

不同版本的api对文件格式的支持:

看上面的表的支持程度知道,一般为了支持更低的版本,合称单音频,单视频的mp4文件在api18时就支持。如果是多个音频和视频的track要怎么处理呢,只能先两个两个的合并,最后剩下两个再合并。

主要函数说明:

addTrack(MediaFormat format):利用MediaFormat添加音频或视频轨道。

release():释放MediaMuxer的资源。

setLocation(float latitude,float longitude):设置并存储地理位置信息到生成文件中。

setOrientationHint(int degrees):设置输出视频回放的方向提示。

start() :开始muxer,等待数据的输入。

Stop():停止muxer,调用这个函数后将生成合成的文件。

writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo):

往muxer中写入编码的数据。

参数说明:

trackIndex:sample(样本)的track index,可以利用MediaExtractor获取。

byteBuf:写入的数据,不可为null;

bufferInfo:当前sample(样本)相关的buffer的信息,不可为null。

MediaCodec.BufferInfo:

主要包括四个数据:

flags:输入buffer相关的buffer flags。

offset:buffer开始的偏移量,通常设为0。

presentationTimeUs:buffer的时间戳。

size:buffer的数据大小。

2 MediaMuxer使用说明

MediaMuxer的使用模板,来自Developer:

MediaMuxer muxer = new MediaMuxer("temp.mp4", OutputFormat.MUXER_OUTPUT_MPEG_4);

// More often, the MediaFormat will be retrieved from MediaCodec.getOutputFormat()

// or MediaExtractor.getTrackFormat().

MediaFormat audioFormat = new MediaFormat(...);

MediaFormat videoFormat = new MediaFormat(...);

int audioTrackIndex = muxer.addTrack(audioFormat);

int videoTrackIndex = muxer.addTrack(videoFormat);

ByteBuffer inputBuffer = ByteBuffer.allocate(bufferSize);

boolean finished = false;

BufferInfo bufferInfo = new BufferInfo();

muxer.start();

while(!finished) {

// getInputBuffer() will fill the inputBuffer with one frame of encoded

// sample from either MediaCodec or MediaExtractor, set isAudioSample to

// true when the sample is audio data, set up all the fields of bufferInfo,

// and return true if there are no more samples.

finished = getInputBuffer(inputBuffer, isAudioSample, bufferInfo);

if (!finished) {

int currentTrackIndex = isAudioSample ? audioTrackIndex : videoTrackIndex;

muxer.writeSampleData(currentTrackIndex, inputBuffer, bufferInfo);

}

};

muxer.stop();

muxer.release();

使用过程介绍:

(1)生成MediaMuxer对象

通过new MediaMuxer(String path, int format)指定视频文件输出路径和文件格式:

MediaMuxer mMediaMuxer = new MediaMuxer(mOutputVideoPath,

MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

(2)addTrack

addTrack(MediaFormat format),添加媒体通道,传入MediaFormat对象,通常从MediaExtractor或者MediaCodec中获取,也可以自己创建,后面会有文章说明。

addTrack会返回trackindex,这个index后面会用到。

(3) 调用start函数

MediaMuxer.start();

(4) 写入数据

调用MediaMuxer.writeSampleData()向mp4文件中写入数据了。每次只能添加一帧视频数据或者单个Sample的音频数据,需要BufferInfo对象作为参数。

BufferInfo info = new BufferInfo();

info.offset = 0;

info.size = sampleSize;

info.flags = MediaCodec.BUFFER_FLAG_SYNC_FRAME;

info.presentationTimeUs = mVideoExtractor.getSampleTime();

mMediaMuxer.writeSampleData(videoTrackIndex, buffer, info);

info.size 必须填入数据的大小

info.flags 需要给出是否为同步帧/关键帧

info.presentationTimeUs 必须给出正确的时间戳,注意单位是 us,第二次getSampleTime()和首次getSampleTime()的时间差。

(5)释放关闭资源

结束写入后关闭以及释放资源:

MediaMuxer.stop();

MediaMuxer.release();

3 利用MediaMuxer生成文件

3.1从MP4文件中提取视频和音频文件,提取之后的视频可以播放但是没有声音,提取之后的声音可以播放但是没有视频画面。

private void muxerdata() {

String srcPath = Environment.getExternalStorageDirectory()

.getPath() + "/video/video.mp4";

String dirP = Environment.getExternalStorageDirectory()

.getPath() + "/demo2";

String fPath1 = Environment.getExternalStorageDirectory()

.getPath() + "/demo2/demo1.mp4";

String fPath2 = Environment.getExternalStorageDirectory()

.getPath() + "/demo2/demo2.mp4";

File file = new File(dirP);

if (!file.exists()){

file.mkdir();

}

File file1 = new File(fPath1);

File file2 = new File(fPath2);

try {

if (file1.exists()){

file1.delete();

}

file1.createNewFile();

} catch (IOException e) {

e.printStackTrace();

}

try {

if (file2.exists()){

file2.delete();

}

file2.createNewFile();

} catch (IOException e) {

e.printStackTrace();

}

MediaMuxer mMediaMuxer;

int mVideoTrackIndex = 0;

int mAudioTrackIndex = 0;

long frameRate;

try {

mediaExtractor = new MediaExtractor();//此类可分离视频文件的音轨和视频轨道

mediaExtractor.setDataSource(srcPath);//媒体文件的位置

System.out.println("==========getTrackCount()===================" + mediaExtractor.getTrackCount());

for (int i = 0; i < mediaExtractor.getTrackCount(); i++) {

MediaFormat format = mediaExtractor.getTrackFormat(i);

String mime = format.getString(MediaFormat.KEY_MIME);

if (mime.startsWith("audio")) {//获取音频轨道

ByteBuffer buffer = ByteBuffer.allocate(100 * 1024);

{ mediaExtractor.selectTrack(i);//选择此音频轨道

mediaExtractor.readSampleData(buffer, 0);

long first_sampletime = mediaExtractor.getSampleTime();

mediaExtractor.advance();

long second_sampletime = mediaExtractor.getSampleTime();

frameRate = Math.abs(second_sampletime - first_sampletime);//时间戳

mediaExtractor.unselectTrack(i);

}

mediaExtractor.selectTrack(i);

System.out.println("==============frameRate111=============="+frameRate+"");

mMediaMuxer = new MediaMuxer(fPath2, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

mAudioTrackIndex = mMediaMuxer.addTrack(format);

mMediaMuxer.start();

MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();

info.presentationTimeUs = 0;

int sampleSize = 0;

while ((sampleSize = mediaExtractor.readSampleData(buffer, 0)) > 0) {

info.offset = 0;

info.size = sampleSize;

info.flags = mediaExtractor.getSampleFlags();

info.presentationTimeUs += frameRate;

mMediaMuxer.writeSampleData(mAudioTrackIndex, buffer, info);

mediaExtractor.advance();

}

mMediaMuxer.stop();

mMediaMuxer.release();

}

if (mime.startsWith("video")){

mediaExtractor.selectTrack(i);//选择此视频轨道

frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);

System.out.println("==============frameRate222=============="+ 1000 * 1000 / frameRate+"");

mMediaMuxer = new MediaMuxer(fPath1, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

mVideoTrackIndex = mMediaMuxer.addTrack(format);

mMediaMuxer.start();

MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();

info.presentationTimeUs = 0;

ByteBuffer buffer = ByteBuffer.allocate(100 * 1024);

int sampleSize = 0;

while ((sampleSize = mediaExtractor.readSampleData(buffer, 0)) > 0) {

info.offset = 0;

info.size = sampleSize;

info.flags = mediaExtractor.getSampleFlags();

info.presentationTimeUs += 1000 * 1000 / frameRate;

mMediaMuxer.writeSampleData(mVideoTrackIndex, buffer, info);

mediaExtractor.advance();

}

mMediaMuxer.stop();

mMediaMuxer.release();

}

}

} catch (IOException e) {

e.printStackTrace();

}finally {

mediaExtractor.release();

mediaExtractor = null;

}

}

3.2把提取出来的视频和音频合并:

private void muxermergedata() {

String desPath = Environment.getExternalStorageDirectory()

.getPath() + "/demo2/video.mp4";

String dirP = Environment.getExternalStorageDirectory()

.getPath() + "/demo2";

String fPath1 = Environment.getExternalStorageDirectory()

.getPath() + "/demo2/demo1.mp4";

String fPath2 = Environment.getExternalStorageDirectory()

.getPath() + "/demo2/demo2.mp4";

File file = new File(dirP);

if (!file.exists()){

file.mkdir();

}

File file1 = new File(fPath1);

File file2 = new File(fPath2);

File filedes = new File(desPath);

try {

if (filedes.exists()){

filedes.delete();

}

filedes.createNewFile();

} catch (IOException e) {

e.printStackTrace();

}

MediaMuxer mMediaMuxer = null;

try {

mMediaMuxer = new MediaMuxer(desPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

} catch (IOException e) {

e.printStackTrace();

}

int mVideoTrackIndex = 0;

int mAudioTrackIndex = 0;

long frameRate1 = 0;

long frameRate2 = 0;

MediaFormat format1;

MediaFormat format2;

try {

mediaExtractor = new MediaExtractor();//此类可分离视频文件的音轨和视频轨道

mediaExtractor.setDataSource(fPath1);//媒体文件的位置

System.out.println("==========getTrackCount()===================" + mediaExtractor.getTrackCount());

for (int i = 0; i < mediaExtractor.getTrackCount(); i++) {

format1 = mediaExtractor.getTrackFormat(i);

String mime = format1.getString(MediaFormat.KEY_MIME);

if (mime.startsWith("video")){

mediaExtractor.selectTrack(i);//选择此视频轨道

frameRate1 = format1.getInteger(MediaFormat.KEY_FRAME_RATE);

System.out.println("==============frameRate222=============="+ 1000 * 1000 / frameRate1+"");

mVideoTrackIndex = mMediaMuxer.addTrack(format1);

}

}

} catch (IOException e) {

e.printStackTrace();

}

try {

mediaExtractor2 = new MediaExtractor();//此类可分离视频文件的音轨和视频轨道

mediaExtractor2.setDataSource(fPath2);//媒体文件的位置

System.out.println("==========getTrackCount()===================" + mediaExtractor2.getTrackCount());

for (int i = 0; i < mediaExtractor2.getTrackCount(); i++) {

format2 = mediaExtractor2.getTrackFormat(i);

String mime = format2.getString(MediaFormat.KEY_MIME);

if (mime.startsWith("audio")) {//获取音频轨道

ByteBuffer buffer = ByteBuffer.allocate(100 * 1024);

{

mediaExtractor2.selectTrack(i);//选择此音频轨道

mediaExtractor2.readSampleData(buffer, 0);

long first_sampletime = mediaExtractor2.getSampleTime();

mediaExtractor2.advance();

long second_sampletime = mediaExtractor2.getSampleTime();

frameRate2 = Math.abs(second_sampletime - first_sampletime);//时间戳

mediaExtractor2.unselectTrack(i);

}

mediaExtractor2.selectTrack(i);

System.out.println("==============frameRate111==============" + frameRate2 + "");

mAudioTrackIndex = mMediaMuxer.addTrack(format2);

}

}

} catch (IOException e) {

e.printStackTrace();

}

mMediaMuxer.start();

MediaCodec.BufferInfo info1 = new MediaCodec.BufferInfo();

info1.presentationTimeUs = 0;

ByteBuffer buffer = ByteBuffer.allocate(100 * 1024);

int sampleSize1 = 0;

while ((sampleSize1 = mediaExtractor.readSampleData(buffer, 0)) > 0) {

info1.offset = 0;

info1.size = sampleSize1;

info1.flags = mediaExtractor.getSampleFlags();

info1.presentationTimeUs += 1000 * 1000 / frameRate1;

mMediaMuxer.writeSampleData(mVideoTrackIndex, buffer, info1);

mediaExtractor.advance();

}

MediaCodec.BufferInfo info2 = new MediaCodec.BufferInfo();

info2.presentationTimeUs = 0;

int sampleSize2 = 0;

while ((sampleSize2 = mediaExtractor2.readSampleData(buffer, 0)) > 0) {

info2.offset = 0;

info2.size = sampleSize2;

info2.flags = mediaExtractor2.getSampleFlags();

info2.presentationTimeUs += frameRate2;

mMediaMuxer.writeSampleData(mAudioTrackIndex, buffer, info2);

mediaExtractor2.advance();

}

try {

mediaExtractor.release();

mediaExtractor = null;

mediaExtractor2.release();

mediaExtractor2 = null;

你可能感兴趣的:(android,解析mp3文件格式)